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.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 }