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.oceanus.base.OceanusException;
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.MoneyWisePortfolio;
27  import io.github.tonywasher.joceanus.moneywise.data.basic.MoneyWisePortfolio.MoneyWisePortfolioDataMap;
28  import io.github.tonywasher.joceanus.moneywise.data.basic.MoneyWisePortfolio.MoneyWisePortfolioList;
29  import io.github.tonywasher.joceanus.moneywise.data.basic.MoneyWiseSecurityHolding;
30  import io.github.tonywasher.joceanus.moneywise.data.statics.MoneyWiseCurrency;
31  import io.github.tonywasher.joceanus.moneywise.data.statics.MoneyWisePayeeClass;
32  import io.github.tonywasher.joceanus.moneywise.data.statics.MoneyWisePortfolioClass;
33  import io.github.tonywasher.joceanus.moneywise.data.statics.MoneyWisePortfolioType;
34  import io.github.tonywasher.joceanus.moneywise.data.statics.MoneyWisePortfolioType.MoneyWisePortfolioTypeList;
35  import io.github.tonywasher.joceanus.moneywise.data.statics.MoneyWiseStaticDataType;
36  import io.github.tonywasher.joceanus.prometheus.data.PrometheusDataItem;
37  import io.github.tonywasher.joceanus.prometheus.data.PrometheusDataResource;
38  import io.github.tonywasher.joceanus.prometheus.views.PrometheusEditSet;
39  
40  import java.util.Iterator;
41  
42  /**
43   * Validator for Payee.
44   */
45  public class MoneyWiseValidatePortfolio
46          extends MoneyWiseValidateAccount<MoneyWisePortfolio>
47          implements MoneyWiseDataValidatorAutoCorrect<MoneyWisePortfolio> {
48      /**
49       * New Account name.
50       */
51      private static final String NAME_NEWACCOUNT = MoneyWiseBasicResource.PORTFOLIO_NEWACCOUNT.getValue();
52  
53      /**
54       * Portfolio Cash account.
55       */
56      static final String NAME_CASHACCOUNT = MoneyWiseBasicResource.PORTFOLIO_CASHACCOUNT.getValue();
57  
58      /**
59       * The infoSet validator.
60       */
61      private final MoneyWiseValidatePortfolioInfoSet theInfoSet;
62  
63      /**
64       * Constructor.
65       */
66      MoneyWiseValidatePortfolio() {
67          theInfoSet = new MoneyWiseValidatePortfolioInfoSet();
68      }
69  
70      @Override
71      public void setEditSet(final PrometheusEditSet pEditSet) {
72          super.setEditSet(pEditSet);
73          theInfoSet.storeEditSet(pEditSet);
74      }
75  
76      @Override
77      public void validate(final PrometheusDataItem pPortfolio) {
78          final MoneyWisePortfolio myPortfolio = (MoneyWisePortfolio) pPortfolio;
79          final MoneyWisePortfolioList myList = myPortfolio.getList();
80          final MoneyWisePayee myParent = myPortfolio.getParent();
81          final MoneyWisePortfolioType myPortType = myPortfolio.getCategory();
82          final MoneyWiseCurrency myCurrency = myPortfolio.getAssetCurrency();
83  
84          /* Validate base components */
85          super.validate(pPortfolio);
86  
87          /* PortfolioType must be non-null */
88          if (myPortType == null) {
89              pPortfolio.addError(PrometheusDataItem.ERROR_MISSING, MoneyWiseBasicResource.CATEGORY_NAME);
90          } else {
91              /* Access the class */
92              final MoneyWisePortfolioClass myClass = myPortType.getPortfolioClass();
93  
94              /* PortfolioType must be enabled */
95              if (!myPortType.getEnabled()) {
96                  pPortfolio.addError(PrometheusDataItem.ERROR_DISABLED, MoneyWiseBasicResource.CATEGORY_NAME);
97              }
98  
99              /* If the PortfolioType is singular */
100             if (myClass.isSingular()) {
101                 /* Count the elements of this class */
102                 final MoneyWisePortfolioDataMap myMap = myList.getDataMap();
103                 if (!myMap.validSingularCount(myClass)) {
104                     pPortfolio.addError(PrometheusDataItem.ERROR_MULT, MoneyWiseBasicResource.CATEGORY_NAME);
105                 }
106             }
107         }
108 
109         /* Parent account must exist */
110         if (myParent == null) {
111             pPortfolio.addError(PrometheusDataItem.ERROR_MISSING, MoneyWiseBasicResource.ASSET_PARENT);
112         } else {
113             /* Parent must be suitable */
114             final MoneyWisePayeeClass myParClass = myParent.getCategoryClass();
115             if (!myParClass.canParentPortfolio()) {
116                 pPortfolio.addError(ERROR_BADPARENT, MoneyWiseBasicResource.ASSET_PARENT);
117             }
118 
119             /* If we are open then parent must be open */
120             if (!myPortfolio.isClosed() && Boolean.TRUE.equals(myParent.isClosed())) {
121                 pPortfolio.addError(ERROR_PARCLOSED, MoneyWiseBasicResource.ASSET_CLOSED);
122             }
123         }
124 
125         /* Currency must be non-null and enabled */
126         if (myCurrency == null) {
127             pPortfolio.addError(PrometheusDataItem.ERROR_MISSING, MoneyWiseStaticDataType.CURRENCY);
128         } else if (!myCurrency.getEnabled()) {
129             pPortfolio.addError(PrometheusDataItem.ERROR_DISABLED, MoneyWiseStaticDataType.CURRENCY);
130         }
131 
132         /* If we have an infoSet */
133         if (myPortfolio.getInfoSet() != null) {
134             /* Validate the InfoSet */
135             theInfoSet.validate(myPortfolio.getInfoSet());
136         }
137 
138         /* Set validation flag */
139         if (!pPortfolio.hasErrors()) {
140             pPortfolio.setValidEdit();
141         }
142     }
143 
144     @Override
145     public void validateName(final MoneyWiseAssetBase pPortfolio,
146                              final String pName) {
147         /* Perform basic checks */
148         super.validateName(pPortfolio, pName);
149 
150         /* Check that the name does not contain invalid characters */
151         if (pName.contains(MoneyWiseSecurityHolding.SECURITYHOLDING_SEP)) {
152             pPortfolio.addError(PrometheusDataItem.ERROR_INVALIDCHAR, PrometheusDataResource.DATAITEM_FIELD_NAME);
153         }
154     }
155 
156     @Override
157     public void setDefaults(final MoneyWisePortfolio pPortfolio) throws OceanusException {
158         /* Set values */
159         final MoneyWisePortfolioList myList = pPortfolio.getList();
160         pPortfolio.setName(getUniqueName(myList, NAME_NEWACCOUNT));
161         pPortfolio.setCategory(getDefaultPortfolioType());
162         pPortfolio.setParent(getDefaultParent());
163         pPortfolio.setAssetCurrency(getReportingCurrency());
164         pPortfolio.setClosed(Boolean.FALSE);
165     }
166 
167     @Override
168     public void autoCorrect(final MoneyWisePortfolio pPortfolio) throws OceanusException {
169         /* Ensure that we have a valid parent */
170         final MoneyWisePayee myParent = pPortfolio.getParent();
171         if (myParent == null
172                 || !myParent.getCategoryClass().canParentPortfolio()) {
173             pPortfolio.setParent(getDefaultParent());
174         }
175 
176         /* autoCorrect the infoSet */
177         theInfoSet.autoCorrect(pPortfolio.getInfoSet());
178     }
179 
180     /**
181      * Obtain default parent for portfolio.
182      *
183      * @return the default parent
184      */
185     private MoneyWisePayee getDefaultParent() {
186         /* loop through the payees */
187         final MoneyWisePayeeList myPayees = getEditSet().getDataList(MoneyWiseBasicDataType.PAYEE, MoneyWisePayeeList.class);
188         final Iterator<MoneyWisePayee> myIterator = myPayees.iterator();
189         while (myIterator.hasNext()) {
190             final MoneyWisePayee myPayee = myIterator.next();
191 
192             /* Ignore deleted and closed payees and those that cannot parent this portfolio */
193             boolean bIgnore = myPayee.isDeleted() || myPayee.isClosed();
194             bIgnore |= !myPayee.getCategoryClass().canParentPortfolio();
195             if (!bIgnore) {
196                 return myPayee;
197             }
198         }
199 
200         /* Return no payee */
201         return null;
202     }
203 
204     /**
205      * Obtain portfolio type for new portfolio account.
206      *
207      * @return the security type
208      */
209     private MoneyWisePortfolioType getDefaultPortfolioType() {
210         /* loop through the portfolio types */
211         final MoneyWisePortfolioTypeList myTypes
212                 = getEditSet().getDataList(MoneyWiseStaticDataType.PORTFOLIOTYPE, MoneyWisePortfolioTypeList.class);
213         final Iterator<MoneyWisePortfolioType> myIterator = myTypes.iterator();
214         while (myIterator.hasNext()) {
215             final MoneyWisePortfolioType myType = myIterator.next();
216 
217             /* Ignore deleted types */
218             if (!myType.isDeleted()) {
219                 return myType;
220             }
221         }
222 
223         /* Return no category */
224         return null;
225     }
226 }