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