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.validate;
18  
19  import io.github.tonywasher.joceanus.metis.field.MetisFieldRequired;
20  import io.github.tonywasher.joceanus.moneywise.data.basic.MoneyWiseAssetBase;
21  import io.github.tonywasher.joceanus.moneywise.data.basic.MoneyWiseBasicDataType;
22  import io.github.tonywasher.joceanus.moneywise.data.basic.MoneyWiseBasicResource;
23  import io.github.tonywasher.joceanus.moneywise.data.basic.MoneyWiseDataValidator.MoneyWiseDataValidatorAutoCorrect;
24  import io.github.tonywasher.joceanus.moneywise.data.basic.MoneyWisePayee;
25  import io.github.tonywasher.joceanus.moneywise.data.basic.MoneyWisePayee.MoneyWisePayeeList;
26  import io.github.tonywasher.joceanus.moneywise.data.basic.MoneyWiseSecurity;
27  import io.github.tonywasher.joceanus.moneywise.data.basic.MoneyWiseSecurity.MoneyWiseSecurityDataMap;
28  import io.github.tonywasher.joceanus.moneywise.data.basic.MoneyWiseSecurity.MoneyWiseSecurityList;
29  import io.github.tonywasher.joceanus.moneywise.data.basic.MoneyWiseSecurityHolding;
30  import io.github.tonywasher.joceanus.moneywise.data.basic.MoneyWiseSecurityInfoSet;
31  import io.github.tonywasher.joceanus.moneywise.data.statics.MoneyWiseAccountInfoClass;
32  import io.github.tonywasher.joceanus.moneywise.data.statics.MoneyWiseCurrency;
33  import io.github.tonywasher.joceanus.moneywise.data.statics.MoneyWisePayeeClass;
34  import io.github.tonywasher.joceanus.moneywise.data.statics.MoneyWiseSecurityClass;
35  import io.github.tonywasher.joceanus.moneywise.data.statics.MoneyWiseSecurityType;
36  import io.github.tonywasher.joceanus.moneywise.data.statics.MoneyWiseSecurityType.MoneyWiseSecurityTypeList;
37  import io.github.tonywasher.joceanus.moneywise.data.statics.MoneyWiseStaticDataType;
38  import io.github.tonywasher.joceanus.oceanus.base.OceanusException;
39  import io.github.tonywasher.joceanus.prometheus.data.PrometheusData.PrometheusDataItemCtl;
40  import io.github.tonywasher.joceanus.prometheus.data.PrometheusDataItem;
41  import io.github.tonywasher.joceanus.prometheus.data.PrometheusDataResource;
42  import io.github.tonywasher.joceanus.prometheus.views.PrometheusEditSet;
43  
44  import java.util.Iterator;
45  
46  /**
47   * Validator for Security.
48   */
49  public class MoneyWiseValidateSecurity
50          extends MoneyWiseValidateAccount<MoneyWiseSecurity>
51          implements MoneyWiseDataValidatorAutoCorrect<MoneyWiseSecurity> {
52      /**
53       * New Account name.
54       */
55      private static final String NAME_NEWACCOUNT = MoneyWiseBasicResource.SECURITY_NEWACCOUNT.getValue();
56  
57      /**
58       * The infoSet validator.
59       */
60      private final MoneyWiseValidateSecurityInfoSet theInfoSet;
61  
62      /**
63       * Constructor.
64       */
65      MoneyWiseValidateSecurity() {
66          theInfoSet = new MoneyWiseValidateSecurityInfoSet();
67      }
68  
69      @Override
70      public void setEditSet(final PrometheusEditSet pEditSet) {
71          super.setEditSet(pEditSet);
72          theInfoSet.storeEditSet(pEditSet);
73      }
74  
75      @Override
76      public void validate(final PrometheusDataItemCtl pSecurity) {
77          final MoneyWiseSecurity mySecurity = (MoneyWiseSecurity) pSecurity;
78          final MoneyWiseSecurityList myList = mySecurity.getList();
79          final MoneyWisePayee myParent = mySecurity.getParent();
80          final MoneyWiseSecurityType mySecType = mySecurity.getCategory();
81          final MoneyWiseCurrency myCurrency = mySecurity.getAssetCurrency();
82          final String mySymbol = mySecurity.getSymbol();
83  
84          /* Validate base components */
85          super.validate(pSecurity);
86  
87          /* SecurityType must be non-null */
88          if (mySecType == null) {
89              mySecurity.addError(PrometheusDataItem.ERROR_MISSING, MoneyWiseBasicResource.CATEGORY_NAME);
90          } else {
91              /* Access the class */
92              final MoneyWiseSecurityClass myClass = mySecType.getSecurityClass();
93  
94              /* SecurityType must be enabled */
95              if (!mySecType.getEnabled()) {
96                  mySecurity.addError(PrometheusDataItem.ERROR_DISABLED, MoneyWiseBasicResource.CATEGORY_NAME);
97              }
98  
99              /* If the SecurityType is singular */
100             if (myClass.isSingular()) {
101                 /* Count the elements of this class */
102                 final MoneyWiseSecurityDataMap myMap = myList.getDataMap();
103                 if (!myMap.validSingularCount(myClass)) {
104                     mySecurity.addError(PrometheusDataItem.ERROR_MULT, MoneyWiseBasicResource.CATEGORY_NAME);
105                 }
106             }
107         }
108 
109         /* Currency must be non-null and enabled */
110         if (myCurrency == null) {
111             mySecurity.addError(PrometheusDataItem.ERROR_MISSING, MoneyWiseStaticDataType.CURRENCY);
112         } else if (!myCurrency.getEnabled()) {
113             mySecurity.addError(PrometheusDataItem.ERROR_DISABLED, MoneyWiseStaticDataType.CURRENCY);
114         }
115 
116         /* Parent must be non-null */
117         if (myParent == null) {
118             mySecurity.addError(PrometheusDataItem.ERROR_MISSING, MoneyWiseBasicResource.ASSET_PARENT);
119         } else {
120             /* If we are open then parent must be open */
121             if (!Boolean.TRUE.equals(mySecurity.isClosed())
122                     && Boolean.TRUE.equals(myParent.isClosed())) {
123                 mySecurity.addError(ERROR_PARCLOSED, MoneyWiseBasicResource.ASSET_CLOSED);
124             }
125 
126             /* Check class */
127             if (mySecType != null) {
128                 /* Access the classes */
129                 final MoneyWiseSecurityClass myClass = mySecType.getSecurityClass();
130                 final MoneyWisePayeeClass myParClass = myParent.getCategoryClass();
131 
132                 /* Parent must be suitable */
133                 if (!myParClass.canParentSecurity(myClass)) {
134                     mySecurity.addError(ERROR_BADPARENT, MoneyWiseBasicResource.ASSET_PARENT);
135                 }
136             }
137         }
138 
139         /* If we have a securityType */
140         if (mySecType != null) {
141             /* Check symbol rules */
142             if (mySecType.getSecurityClass().needsSymbol()) {
143                 if (mySymbol == null) {
144                     mySecurity.addError(PrometheusDataItem.ERROR_MISSING, MoneyWiseSecurityInfoSet.getFieldForClass(MoneyWiseAccountInfoClass.SYMBOL));
145                 } else if (!myList.validSymbolCount(mySymbol)) {
146                     mySecurity.addError(PrometheusDataItem.ERROR_DUPLICATE, MoneyWiseSecurityInfoSet.getFieldForClass(MoneyWiseAccountInfoClass.SYMBOL));
147                 }
148             } else if (mySymbol != null) {
149                 mySecurity.addError(PrometheusDataItem.ERROR_EXIST, MoneyWiseSecurityInfoSet.getFieldForClass(MoneyWiseAccountInfoClass.SYMBOL));
150             }
151         }
152 
153         /* If we have an infoSet */
154         if (mySecurity.getInfoSet() != null) {
155             /* Validate the InfoSet */
156             theInfoSet.validate(mySecurity.getInfoSet());
157         }
158 
159         /* Set validation flag */
160         if (!mySecurity.hasErrors()) {
161             mySecurity.setValidEdit();
162         }
163     }
164 
165     @Override
166     public void validateName(final MoneyWiseAssetBase pSecurity,
167                              final String pName) {
168         /* Perform basic checks */
169         super.validateName(pSecurity, pName);
170 
171         /* Check that the name is not a reserved name */
172         if (pName.equals(MoneyWiseSecurityHolding.SECURITYHOLDING_NEW)
173                 || pName.equals(MoneyWiseValidatePortfolio.NAME_CASHACCOUNT)) {
174             pSecurity.addError(ERROR_RESERVED, PrometheusDataResource.DATAITEM_FIELD_NAME);
175         }
176     }
177 
178     /**
179      * Determine if an infoSet class is required.
180      *
181      * @param pClass the infoSet class
182      * @return the status
183      */
184     public MetisFieldRequired isClassRequired(final MoneyWiseAccountInfoClass pClass) {
185         return theInfoSet.isClassRequired(pClass);
186     }
187 
188     @Override
189     public void setDefaults(final MoneyWiseSecurity pSecurity) throws OceanusException {
190         /* Set values */
191         final MoneyWiseSecurityList myList = pSecurity.getList();
192         pSecurity.setName(getUniqueName(myList, NAME_NEWACCOUNT));
193         pSecurity.setCategory(getDefaultSecurityType());
194         pSecurity.setAssetCurrency(getReportingCurrency());
195         pSecurity.setSymbol(pSecurity.getName());
196         pSecurity.setClosed(Boolean.FALSE);
197         autoCorrect(pSecurity);
198     }
199 
200     @Override
201     public void autoCorrect(final MoneyWiseSecurity pSecurity) throws OceanusException {
202         /* Access category class and parent */
203         final MoneyWiseSecurityClass myClass = pSecurity.getCategoryClass();
204         final MoneyWisePayee myParent = pSecurity.getParent();
205 
206         /* Ensure that we have a valid parent */
207         if (myParent == null
208                 || myParent.getCategoryClass().canParentSecurity(myClass)) {
209             pSecurity.setParent(getDefaultParent(pSecurity));
210         }
211 
212         /* autoCorrect the infoSet */
213         theInfoSet.autoCorrect(pSecurity.getInfoSet());
214     }
215 
216     /**
217      * Obtain security type for new security account.
218      *
219      * @return the security type
220      */
221     private MoneyWiseSecurityType getDefaultSecurityType() {
222         /* loop through the security types */
223         final MoneyWiseSecurityTypeList myTypes
224                 = getEditSet().getDataList(MoneyWiseStaticDataType.SECURITYTYPE, MoneyWiseSecurityTypeList.class);
225         final Iterator<MoneyWiseSecurityType> myIterator = myTypes.iterator();
226         while (myIterator.hasNext()) {
227             final MoneyWiseSecurityType myType = myIterator.next();
228 
229             /* Ignore deleted types */
230             if (!myType.isDeleted()) {
231                 return myType;
232             }
233         }
234 
235         /* Return no category */
236         return null;
237     }
238 
239     /**
240      * Obtain default parent for new security.
241      *
242      * @param pSecurity the security
243      * @return the default parent
244      */
245     private MoneyWisePayee getDefaultParent(final MoneyWiseSecurity pSecurity) {
246         /* Access details */
247         final MoneyWisePayeeList myPayees = getEditSet().getDataList(MoneyWiseBasicDataType.PAYEE, MoneyWisePayeeList.class);
248         final MoneyWiseSecurityClass myClass = pSecurity.getCategoryClass();
249 
250         /* loop through the payees */
251         final Iterator<MoneyWisePayee> myIterator = myPayees.iterator();
252         while (myIterator.hasNext()) {
253             final MoneyWisePayee myPayee = myIterator.next();
254 
255             /* Ignore deleted and closed payees */
256             if (myPayee.isDeleted() || Boolean.TRUE.equals(myPayee.isClosed())) {
257                 continue;
258             }
259 
260             /* If the payee can parent */
261             if (myPayee.getCategoryClass().canParentSecurity(myClass)) {
262                 return myPayee;
263             }
264         }
265 
266         /* Return no payee */
267         return null;
268     }
269 }