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.data.statics;
18
19 import io.github.tonywasher.joceanus.moneywise.exc.MoneyWiseDataException;
20 import io.github.tonywasher.joceanus.oceanus.base.OceanusException;
21 import io.github.tonywasher.joceanus.oceanus.resource.OceanusBundleId;
22 import io.github.tonywasher.joceanus.prometheus.data.PrometheusStaticDataClass;
23
24 /**
25 * Enumeration of Security Type Classes.
26 */
27 public enum MoneyWiseSecurityClass
28 implements PrometheusStaticDataClass {
29 /**
30 * Shares.
31 * <p>
32 * This is a share security and represents stock held in a company.
33 */
34 SHARES(1, 0),
35
36 /**
37 * Growth Unit Trust or OEIC.
38 * <p>
39 * This is a UnitTrust account and represents a mutual fund that reinvests income.
40 */
41 GROWTHUNITTRUST(2, 1),
42
43 /**
44 * Income Unit Trust or OEIC.
45 * <p>
46 * This is a UnitTrust account and represents a mutual fund that provides income.
47 */
48 INCOMEUNITTRUST(3, 2),
49
50 /**
51 * Life Bond.
52 * <p>
53 * This is a LifeBond account, which is a specialised form of an {@link #GROWTHUNITTRUST}
54 * security. It simply differs in tax treatment.
55 */
56 LIFEBOND(4, 3),
57
58 /**
59 * Endowment.
60 * <p>
61 * This is a Endowment account, which is a specialised form of an {@link #GROWTHUNITTRUST}
62 * security. It simply differs in tax treatment.
63 */
64 ENDOWMENT(5, 4),
65
66 /**
67 * Property.
68 * <p>
69 * This is a Property account, which represents an owned property.
70 */
71 PROPERTY(6, 5),
72
73 /**
74 * Vehicle.
75 * <p>
76 * This is a Vehicle account, which represents a road vehicle.
77 */
78 VEHICLE(7, 6),
79
80 /**
81 * Defined Contribution Pension Pot.
82 * <p>
83 * This is a defined contribution PensionPot. TaxFree contributions can be made to this Pot via
84 * an Income:Pension transaction. It should have a single unit valued at the size of the
85 * PensionPot.
86 */
87 DEFINEDCONTRIBUTION(8, 7),
88
89 /**
90 * DefinedBenefit PensionPot.
91 * <p>
92 * This is a defined Benefit Pension Pot. TaxFree contributions can be made to this Pot via an
93 * Income:Pension transaction. It should have a single unit valued at the annual income value.
94 * Its valuation is the annual income multiplied by 20.
95 */
96 DEFINEDBENEFIT(9, 8),
97
98 /**
99 * StatePension PensionPot.
100 * <p>
101 * This is a state Pension Pot. It should have a single unit valued at the weekly income value.
102 * Its valuation is the weekly income multiplied by 52*20. It is a singular Security.
103 */
104 STATEPENSION(10, 9),
105
106 /**
107 * StockOption.
108 * <p>
109 * This is stockOption. It relates to an option to buy a particular stock at a particular price
110 * at a later date.
111 */
112 STOCKOPTION(11, 10),
113
114 /**
115 * Generic Asset Account.
116 * <p>
117 * This is a generic asset account and represents items whose value is determined by the product
118 * of the number units held and the most recent unit price.
119 */
120 ASSET(12, 11);
121
122 /**
123 * Number of Pension Years for valuation.
124 */
125 private static final int PENSION_YEARS = 20;
126
127 /**
128 * Number of Pension Weeks for valuation.
129 */
130 private static final int PENSION_WEEKS = 52;
131
132 /**
133 * The String name.
134 */
135 private String theName;
136
137 /**
138 * Class Id.
139 */
140 private final int theId;
141
142 /**
143 * Class Order.
144 */
145 private final int theOrder;
146
147 /**
148 * Constructor.
149 *
150 * @param uId the Id
151 * @param uOrder the default order.
152 */
153 MoneyWiseSecurityClass(final int uId,
154 final int uOrder) {
155 theId = uId;
156 theOrder = uOrder;
157 }
158
159 @Override
160 public int getClassId() {
161 return theId;
162 }
163
164 @Override
165 public int getOrder() {
166 return theOrder;
167 }
168
169 @Override
170 public String toString() {
171 /* If we have not yet loaded the name */
172 if (theName == null) {
173 /* Load the name */
174 theName = bundleIdForSecurityClass(this).getValue();
175 }
176
177 /* return the name */
178 return theName;
179 }
180
181 /**
182 * get value from id.
183 *
184 * @param id the id value
185 * @return the corresponding enum object
186 * @throws OceanusException on error
187 */
188 public static MoneyWiseSecurityClass fromId(final int id) throws OceanusException {
189 for (MoneyWiseSecurityClass myClass : values()) {
190 if (myClass.getClassId() == id) {
191 return myClass;
192 }
193 }
194 throw new MoneyWiseDataException("Invalid ClassId for " + MoneyWiseStaticDataType.SECURITYTYPE.toString() + ":" + id);
195 }
196
197 /**
198 * Determine whether the SecurityType is a pension.
199 *
200 * @return <code>true</code> if the security type is a pension, <code>false</code> otherwise.
201 */
202 public boolean isPension() {
203 return switch (this) {
204 case DEFINEDBENEFIT, DEFINEDCONTRIBUTION, STATEPENSION -> true;
205 default -> false;
206 };
207 }
208
209 /**
210 * Determine whether the SecurityType is a dividend provider.
211 *
212 * @return <code>true</code> if the security type is a dividend provider, <code>false</code>
213 * otherwise.
214 */
215 public boolean isDividend() {
216 return switch (this) {
217 case SHARES, INCOMEUNITTRUST, GROWTHUNITTRUST -> true;
218 default -> false;
219 };
220 }
221
222 /**
223 * Determine whether the SecurityType is shares.
224 *
225 * @return <code>true</code> if the security type is shares, <code>false</code> otherwise.
226 */
227 public boolean isShares() {
228 return this == SHARES;
229 }
230
231 /**
232 * Determine whether the SecurityType is option.
233 *
234 * @return <code>true</code> if the security type is option, <code>false</code> otherwise.
235 */
236 public boolean isOption() {
237 return this == STOCKOPTION;
238 }
239
240 /**
241 * Determine whether the SecurityType needs a symbol.
242 *
243 * @return <code>true</code> if the security type needs a symbol, <code>false</code> otherwise.
244 */
245 public boolean needsSymbol() {
246 return switch (this) {
247 case SHARES, GROWTHUNITTRUST, INCOMEUNITTRUST, LIFEBOND -> true;
248 default -> false;
249 };
250 }
251
252 /**
253 * Determine whether the SecurityType needs a region.
254 *
255 * @return <code>true</code> if the security type needs a region, <code>false</code> otherwise.
256 */
257 public boolean needsRegion() {
258 return switch (this) {
259 case INCOMEUNITTRUST, GROWTHUNITTRUST, LIFEBOND -> true;
260 default -> false;
261 };
262 }
263
264 /**
265 * Determine whether the SecurityType needs market as a parent.
266 *
267 * @return <code>true</code> if the security type needs market as a parent, <code>false</code>
268 * otherwise.
269 */
270 public boolean needsMarketParent() {
271 return switch (this) {
272 case ASSET, PROPERTY, VEHICLE, ENDOWMENT -> true;
273 default -> false;
274 };
275 }
276
277 /**
278 * Determine whether the SecurityType can be tax free.
279 *
280 * @return <code>true</code> if the security type can be tax free, <code>false</code> otherwise.
281 */
282 public boolean canTaxFree() {
283 return switch (this) {
284 case SHARES, INCOMEUNITTRUST, GROWTHUNITTRUST, PROPERTY -> true;
285 default -> false;
286 };
287 }
288
289 /**
290 * Determine whether the SecurityType is subject to Capital Gains.
291 *
292 * @return <code>true</code> if the security type is subject to Capital Gains,
293 * <code>false</code> otherwise.
294 */
295 public boolean isCapitalGains() {
296 return switch (this) {
297 case SHARES, INCOMEUNITTRUST, GROWTHUNITTRUST, PROPERTY -> true;
298 default -> false;
299 };
300 }
301
302 /**
303 * Determine whether the SecurityType is subject to Residential Gains.
304 *
305 * @return <code>true</code> if the security type is subject to Residential Gains,
306 * <code>false</code> otherwise.
307 */
308 public boolean isResidentialGains() {
309 return this == PROPERTY;
310 }
311
312 /**
313 * Determine whether the SecurityType is subject to Chargeable Gains.
314 *
315 * @return <code>true</code> if the security type is subject to Chargeable Gains,
316 * <code>false</code> otherwise.
317 */
318 public boolean isChargeableGains() {
319 return this == LIFEBOND;
320 }
321
322 /**
323 * Determine whether the SecurityType is Capital.
324 *
325 * @return <code>true</code> if the security type is Capital, <code>false</code> otherwise.
326 */
327 public boolean isCapital() {
328 return switch (this) {
329 case SHARES, LIFEBOND, INCOMEUNITTRUST, GROWTHUNITTRUST -> true;
330 default -> false;
331 };
332 }
333
334 /**
335 * Determine whether the SecurityType is UnitTrust.
336 *
337 * @return <code>true</code> if the security type is Capital, <code>false</code> otherwise.
338 */
339 public boolean isUnitTrust() {
340 return switch (this) {
341 case INCOMEUNITTRUST, GROWTHUNITTRUST -> true;
342 default -> false;
343 };
344 }
345
346 /**
347 * Is this a statePension?
348 *
349 * @return <code>true</code> if the SecurityType is statePension, <code>false</code> otherwise.
350 */
351 public boolean isStatePension() {
352 return this == STATEPENSION;
353 }
354
355 /**
356 * Is this a singular security?.
357 *
358 * @return <code>true</code> if the SecurityType is singular, <code>false</code> otherwise.
359 */
360 public boolean isSingular() {
361 return isStatePension();
362 }
363
364 /**
365 * Is this an autoUnits?
366 *
367 * @return <code>true</code> if the SecurityType is an autoUnits, <code>false</code> otherwise.
368 */
369 public boolean isAutoUnits() {
370 return switch (this) {
371 case ENDOWMENT, STATEPENSION, DEFINEDCONTRIBUTION, DEFINEDBENEFIT -> true;
372 default -> false;
373 };
374 }
375
376 /**
377 * Obtain autoUnits.
378 *
379 * @return the number of units for this security if active.
380 */
381 public int getAutoUnits() {
382 return switch (this) {
383 case ENDOWMENT, DEFINEDCONTRIBUTION -> 1;
384 case STATEPENSION -> PENSION_YEARS * PENSION_WEEKS;
385 case DEFINEDBENEFIT -> PENSION_YEARS;
386 default -> 0;
387 };
388 }
389
390 /**
391 * Obtain the resource bundleId for the security class.
392 *
393 * @param pClass the security class
394 * @return the resource bundleId
395 */
396 private static OceanusBundleId bundleIdForSecurityClass(final MoneyWiseSecurityClass pClass) {
397 /* Create the map and return it */
398 return switch (pClass) {
399 case SHARES -> MoneyWiseStaticResource.SECURITYTYPE_SHARES;
400 case INCOMEUNITTRUST -> MoneyWiseStaticResource.SECURITYTYPE_INCOMEUNIT;
401 case GROWTHUNITTRUST -> MoneyWiseStaticResource.SECURITYTYPE_GROWTHUNIT;
402 case LIFEBOND -> MoneyWiseStaticResource.SECURITYTYPE_LIFEBOND;
403 case ENDOWMENT -> MoneyWiseStaticResource.SECURITYTYPE_ENDOWMENT;
404 case PROPERTY -> MoneyWiseStaticResource.SECURITYTYPE_PROPERTY;
405 case VEHICLE -> MoneyWiseStaticResource.SECURITYTYPE_VEHICLE;
406 case STATEPENSION -> MoneyWiseStaticResource.SECURITYTYPE_STATEPENSION;
407 case DEFINEDBENEFIT -> MoneyWiseStaticResource.SECURITYTYPE_BENEFIT;
408 case DEFINEDCONTRIBUTION -> MoneyWiseStaticResource.SECURITYTYPE_CONTRIBUTION;
409 case STOCKOPTION -> MoneyWiseStaticResource.SECURITYTYPE_STOCKOPTION;
410 case ASSET -> MoneyWiseStaticResource.SECURITYTYPE_ASSET;
411 default -> throw new IllegalArgumentException();
412 };
413 }
414 }