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.basic;
18  
19  import io.github.tonywasher.joceanus.metis.data.MetisDataDifference;
20  import io.github.tonywasher.joceanus.metis.data.MetisDataEditState;
21  import io.github.tonywasher.joceanus.metis.data.MetisDataItem.MetisDataFieldId;
22  import io.github.tonywasher.joceanus.metis.data.MetisDataResource;
23  import io.github.tonywasher.joceanus.metis.data.MetisDataState;
24  import io.github.tonywasher.joceanus.metis.field.MetisFieldItem;
25  import io.github.tonywasher.joceanus.metis.field.MetisFieldSet;
26  import io.github.tonywasher.joceanus.metis.field.MetisFieldVersionedSet;
27  import io.github.tonywasher.joceanus.moneywise.data.basic.MoneyWiseDepositCategory.MoneyWiseDepositCategoryList;
28  import io.github.tonywasher.joceanus.moneywise.data.basic.MoneyWiseDepositInfo.MoneyWiseDepositInfoList;
29  import io.github.tonywasher.joceanus.moneywise.data.basic.MoneyWisePayee.MoneyWisePayeeList;
30  import io.github.tonywasher.joceanus.moneywise.data.basic.MoneyWiseTax.MoneyWiseTaxCredit;
31  import io.github.tonywasher.joceanus.moneywise.data.basic.MoneyWiseTransCategory.MoneyWiseTransCategoryList;
32  import io.github.tonywasher.joceanus.moneywise.data.statics.MoneyWiseAccountInfoClass;
33  import io.github.tonywasher.joceanus.moneywise.data.statics.MoneyWiseAccountInfoType.MoneyWiseAccountInfoTypeList;
34  import io.github.tonywasher.joceanus.moneywise.data.statics.MoneyWiseCurrency;
35  import io.github.tonywasher.joceanus.moneywise.data.statics.MoneyWiseCurrency.MoneyWiseCurrencyList;
36  import io.github.tonywasher.joceanus.moneywise.data.statics.MoneyWiseDepositCategoryClass;
37  import io.github.tonywasher.joceanus.moneywise.data.statics.MoneyWiseStaticDataType;
38  import io.github.tonywasher.joceanus.moneywise.data.statics.MoneyWiseTransCategoryClass;
39  import io.github.tonywasher.joceanus.moneywise.exc.MoneyWiseDataException;
40  import io.github.tonywasher.joceanus.moneywise.exc.MoneyWiseLogicException;
41  import io.github.tonywasher.joceanus.oceanus.base.OceanusException;
42  import io.github.tonywasher.joceanus.oceanus.date.OceanusDate;
43  import io.github.tonywasher.joceanus.oceanus.decimal.OceanusMoney;
44  import io.github.tonywasher.joceanus.oceanus.format.OceanusDataFormatter;
45  import io.github.tonywasher.joceanus.prometheus.data.PrometheusDataItem;
46  import io.github.tonywasher.joceanus.prometheus.data.PrometheusDataMapItem;
47  import io.github.tonywasher.joceanus.prometheus.data.PrometheusDataResource;
48  import io.github.tonywasher.joceanus.prometheus.data.PrometheusDataSet;
49  import io.github.tonywasher.joceanus.prometheus.data.PrometheusDataValues;
50  import io.github.tonywasher.joceanus.prometheus.data.PrometheusDataValues.PrometheusInfoItem;
51  import io.github.tonywasher.joceanus.prometheus.data.PrometheusEncrypted.PrometheusDataInfoSetItemCtl;
52  import io.github.tonywasher.joceanus.prometheus.data.PrometheusListStyle;
53  import io.github.tonywasher.joceanus.prometheus.views.PrometheusEditSet;
54  
55  import java.util.Iterator;
56  import java.util.Objects;
57  
58  /**
59   * Deposit class.
60   */
61  public class MoneyWiseDeposit
62          extends MoneyWiseAssetBase
63          implements PrometheusDataInfoSetItemCtl<MoneyWiseDepositInfo> {
64      /**
65       * Object name.
66       */
67      public static final String OBJECT_NAME = MoneyWiseBasicDataType.DEPOSIT.getItemName();
68  
69      /**
70       * List name.
71       */
72      public static final String LIST_NAME = MoneyWiseBasicDataType.DEPOSIT.getListName();
73  
74      /**
75       * Local Report fields.
76       */
77      private static final MetisFieldVersionedSet<MoneyWiseDeposit> FIELD_DEFS = MetisFieldVersionedSet.newVersionedFieldSet(MoneyWiseDeposit.class);
78  
79      /*
80       * FieldIds.
81       */
82      static {
83          FIELD_DEFS.declareLocalField(PrometheusDataResource.DATAINFOSET_NAME, MoneyWiseDeposit::getInfoSet);
84          FIELD_DEFS.buildFieldMap(MoneyWiseAccountInfoClass.class, MoneyWiseDeposit::getFieldValue);
85      }
86  
87      /**
88       * Do we have an InfoSet.
89       */
90      private final boolean hasInfoSet;
91  
92      /**
93       * Should we use infoSet for DataState etc.
94       */
95      private final boolean useInfoSet;
96  
97      /**
98       * DepositInfoSet.
99       */
100     private final MoneyWiseDepositInfoSet theInfoSet;
101 
102     /**
103      * Copy Constructor.
104      *
105      * @param pList    the list
106      * @param pDeposit The Deposit to copy
107      */
108     protected MoneyWiseDeposit(final MoneyWiseDepositList pList,
109                                final MoneyWiseDeposit pDeposit) {
110         /* Set standard values */
111         super(pList, pDeposit);
112 
113         /* switch on list type */
114         switch (getList().getStyle()) {
115             case EDIT:
116                 theInfoSet = new MoneyWiseDepositInfoSet(this, pList.getActInfoTypes(), pList.getDepositInfo());
117                 theInfoSet.cloneDataInfoSet(pDeposit.getInfoSet());
118                 hasInfoSet = true;
119                 useInfoSet = true;
120                 break;
121             case CLONE, CORE:
122                 theInfoSet = new MoneyWiseDepositInfoSet(this, pList.getActInfoTypes(), pList.getDepositInfo());
123                 hasInfoSet = true;
124                 useInfoSet = false;
125                 break;
126             default:
127                 theInfoSet = null;
128                 hasInfoSet = false;
129                 useInfoSet = false;
130                 break;
131         }
132     }
133 
134     /**
135      * Values constructor.
136      *
137      * @param pList   the List to add to
138      * @param pValues the values constructor
139      * @throws OceanusException on error
140      */
141     private MoneyWiseDeposit(final MoneyWiseDepositList pList,
142                              final PrometheusDataValues pValues) throws OceanusException {
143         /* Initialise the item */
144         super(pList, pValues);
145 
146         /* Create the InfoSet */
147         theInfoSet = new MoneyWiseDepositInfoSet(this, pList.getActInfoTypes(), pList.getDepositInfo());
148         hasInfoSet = true;
149         useInfoSet = false;
150     }
151 
152     /**
153      * Edit Constructor.
154      *
155      * @param pList the list
156      */
157     public MoneyWiseDeposit(final MoneyWiseDepositList pList) {
158         super(pList);
159 
160         /* Build InfoSet */
161         theInfoSet = new MoneyWiseDepositInfoSet(this, pList.getActInfoTypes(), pList.getDepositInfo());
162         hasInfoSet = true;
163         useInfoSet = true;
164     }
165 
166     @Override
167     public MetisFieldSetDef getDataFieldSet() {
168         return FIELD_DEFS;
169     }
170 
171     @Override
172     public boolean includeXmlField(final MetisDataFieldId pField) {
173         /* Determine whether fields should be included */
174         if (MoneyWiseBasicResource.CATEGORY_NAME.equals(pField)) {
175             return true;
176         }
177         if (MoneyWiseStaticDataType.CURRENCY.equals(pField)) {
178             return true;
179         }
180         if (MoneyWiseBasicResource.ASSET_PARENT.equals(pField)) {
181             return true;
182         }
183 
184         /* Pass call on */
185         return super.includeXmlField(pField);
186     }
187 
188     @Override
189     public Long getExternalId() {
190         return MoneyWiseAssetType.createExternalId(MoneyWiseAssetType.DEPOSIT, getIndexedId());
191     }
192 
193     @Override
194     public MoneyWiseDepositInfoSet getInfoSet() {
195         return theInfoSet;
196     }
197 
198     @Override
199     public MoneyWisePayee getParent() {
200         return (MoneyWisePayee) super.getParent();
201     }
202 
203     /**
204      * Obtain fieldValue for infoSet.
205      *
206      * @param pFieldId the fieldId
207      * @return the value
208      */
209     private Object getFieldValue(final MetisDataFieldId pFieldId) {
210         return theInfoSet != null ? theInfoSet.getFieldValue(pFieldId) : null;
211     }
212 
213     /**
214      * Obtain Maturity.
215      *
216      * @return the maturity date
217      */
218     public OceanusDate getMaturity() {
219         return hasInfoSet
220                 ? theInfoSet.getValue(MoneyWiseAccountInfoClass.MATURITY, OceanusDate.class)
221                 : null;
222     }
223 
224     /**
225      * Obtain SortCode.
226      *
227      * @return the sort code
228      */
229     public char[] getSortCode() {
230         return hasInfoSet
231                 ? theInfoSet.getValue(MoneyWiseAccountInfoClass.SORTCODE, char[].class)
232                 : null;
233     }
234 
235     /**
236      * Obtain Reference.
237      *
238      * @return the reference
239      */
240     public char[] getReference() {
241         return hasInfoSet
242                 ? theInfoSet.getValue(MoneyWiseAccountInfoClass.REFERENCE, char[].class)
243                 : null;
244     }
245 
246     /**
247      * Obtain Account.
248      *
249      * @return the account
250      */
251     public char[] getAccount() {
252         return hasInfoSet
253                 ? theInfoSet.getValue(MoneyWiseAccountInfoClass.ACCOUNT, char[].class)
254                 : null;
255     }
256 
257     /**
258      * Obtain Notes.
259      *
260      * @return the notes
261      */
262     public char[] getNotes() {
263         return hasInfoSet
264                 ? theInfoSet.getValue(MoneyWiseAccountInfoClass.NOTES, char[].class)
265                 : null;
266     }
267 
268     @Override
269     public OceanusMoney getOpeningBalance() {
270         return hasInfoSet
271                 ? theInfoSet.getValue(MoneyWiseAccountInfoClass.OPENINGBALANCE, OceanusMoney.class)
272                 : null;
273     }
274 
275     @Override
276     public MoneyWiseDepositCategory getCategory() {
277         return getValues().getValue(MoneyWiseBasicResource.CATEGORY_NAME, MoneyWiseDepositCategory.class);
278     }
279 
280     /**
281      * Obtain CategoryId.
282      *
283      * @return the categoryId
284      */
285     public Integer getCategoryId() {
286         final MoneyWiseDepositCategory myCategory = getCategory();
287         return myCategory == null
288                 ? null
289                 : myCategory.getIndexedId();
290     }
291 
292     /**
293      * Obtain CategoryName.
294      *
295      * @return the categoryName
296      */
297     public String getCategoryName() {
298         final MoneyWiseDepositCategory myCategory = getCategory();
299         return myCategory == null
300                 ? null
301                 : myCategory.getName();
302     }
303 
304     /**
305      * Obtain DepositCategoryClass.
306      *
307      * @return the categoryClass
308      */
309     public MoneyWiseDepositCategoryClass getCategoryClass() {
310         final MoneyWiseDepositCategory myCategory = getCategory();
311         return myCategory == null
312                 ? null
313                 : myCategory.getCategoryTypeClass();
314     }
315 
316     @Override
317     public boolean isGross() {
318         final MoneyWiseDepositCategory myCategory = getCategory();
319         final MoneyWiseDepositCategoryClass myClass = myCategory == null ? null : myCategory.getCategoryTypeClass();
320         return myClass != null && myClass.isGross();
321     }
322 
323     @Override
324     public boolean isTaxFree() {
325         final MoneyWiseDepositCategory myCategory = getCategory();
326         final MoneyWiseDepositCategoryClass myClass = myCategory == null ? null : myCategory.getCategoryTypeClass();
327         return myClass != null && myClass.isTaxFree();
328     }
329 
330     @Override
331     public boolean isForeign() {
332         final MoneyWiseCurrency myDefault = getDefaultCurrency();
333         return !myDefault.equals(getAssetCurrency());
334     }
335 
336     @Override
337     public MoneyWiseDeposit getBase() {
338         return (MoneyWiseDeposit) super.getBase();
339     }
340 
341     @Override
342     public MoneyWiseDepositList getList() {
343         return (MoneyWiseDepositList) super.getList();
344     }
345 
346     @Override
347     public MetisDataState getState() {
348         /* Pop history for self */
349         MetisDataState myState = super.getState();
350 
351         /* If we should use the InfoSet */
352         if ((myState == MetisDataState.CLEAN) && useInfoSet) {
353             /* Get state for infoSet */
354             myState = theInfoSet.getState();
355         }
356 
357         /* Return the state */
358         return myState;
359     }
360 
361     @Override
362     public MetisDataEditState getEditState() {
363         /* Pop history for self */
364         MetisDataEditState myState = super.getEditState();
365 
366         /* If we should use the InfoSet */
367         if (myState == MetisDataEditState.CLEAN
368                 && useInfoSet) {
369             /* Get state for infoSet */
370             myState = theInfoSet.getEditState();
371         }
372 
373         /* Return the state */
374         return myState;
375     }
376 
377     @Override
378     public boolean hasHistory() {
379         /* Check for history for self */
380         boolean hasHistory = super.hasHistory();
381 
382         /* If we should use the InfoSet */
383         if (!hasHistory && useInfoSet) {
384             /* Check history for infoSet */
385             hasHistory = theInfoSet.hasHistory();
386         }
387 
388         /* Return details */
389         return hasHistory;
390     }
391 
392     @Override
393     public void pushHistory() {
394         /* Push history for self */
395         super.pushHistory();
396 
397         /* If we should use the InfoSet */
398         if (useInfoSet) {
399             /* Push history for infoSet */
400             theInfoSet.pushHistory();
401         }
402     }
403 
404     @Override
405     public void popHistory() {
406         /* Pop history for self */
407         super.popHistory();
408 
409         /* If we should use the InfoSet */
410         if (useInfoSet) {
411             /* Pop history for infoSet */
412             theInfoSet.popHistory();
413         }
414     }
415 
416     @Override
417     public boolean checkForHistory() {
418         /* Check for history for self */
419         boolean bChanges = super.checkForHistory();
420 
421         /* If we should use the InfoSet */
422         if (useInfoSet) {
423             /* Check for history for infoSet */
424             bChanges |= theInfoSet.checkForHistory();
425         }
426 
427         /* return result */
428         return bChanges;
429     }
430 
431     @Override
432     public MetisDataDifference fieldChanged(final MetisDataFieldId pField) {
433         /* Handle InfoSet fields */
434         final MoneyWiseAccountInfoClass myClass = MoneyWiseDepositInfoSet.getClassForField(pField);
435         if (myClass != null) {
436             return useInfoSet
437                     ? theInfoSet.fieldChanged(myClass)
438                     : MetisDataDifference.IDENTICAL;
439         }
440 
441         /* Check super fields */
442         return super.fieldChanged(pField);
443     }
444 
445     @Override
446     public void setDeleted(final boolean bDeleted) {
447         /* Pass call to infoSet if required */
448         if (useInfoSet) {
449             theInfoSet.setDeleted(bDeleted);
450         }
451 
452         /* Pass call onwards */
453         super.setDeleted(bDeleted);
454     }
455 
456     /**
457      * Is this deposit the required class.
458      *
459      * @param pClass the required deposit class.
460      * @return true/false
461      */
462     public boolean isDepositClass(final MoneyWiseDepositCategoryClass pClass) {
463         /* Check for match */
464         return getCategoryClass() == pClass;
465     }
466 
467     /**
468      * Set defaults.
469      *
470      * @throws OceanusException on error
471      */
472     public void setDefaults() throws OceanusException {
473         getList().getValidator().setDefaults(this);
474     }
475 
476     /**
477      * autoCorrect values after change.
478      *
479      * @throws OceanusException on error
480      */
481     public void autoCorrect() throws OceanusException {
482         getList().getValidator().autoCorrect(this);
483     }
484 
485     @Override
486     public int compareValues(final PrometheusDataItem pThat) {
487         /* Check the category and then the name */
488         final MoneyWiseDeposit myThat = (MoneyWiseDeposit) pThat;
489         int iDiff = MetisDataDifference.compareObject(getCategory(), myThat.getCategory());
490         if (iDiff == 0) {
491             iDiff = MetisDataDifference.compareObject(getName(), myThat.getName());
492         }
493         return iDiff;
494     }
495 
496     @Override
497     public void resolveDataSetLinks() throws OceanusException {
498         /* Update the Encryption details */
499         super.resolveDataSetLinks();
500 
501         /* Resolve data links */
502         resolveDataLink(MoneyWiseBasicResource.CATEGORY_NAME, MoneyWiseBasicDataType.DEPOSITCATEGORY);
503         resolveDataLink(MoneyWiseStaticDataType.CURRENCY, MoneyWiseStaticDataType.CURRENCY);
504         resolveDataLink(MoneyWiseBasicResource.ASSET_PARENT, MoneyWiseBasicDataType.PAYEE);
505     }
506 
507     @Override
508     protected void resolveEditSetLinks() throws OceanusException {
509         /* Access the editSet */
510         final PrometheusEditSet myEditSet = getList().getEditSet();
511 
512         /* Resolve Parent/Category/Currency if required */
513         resolveDataLink(MoneyWiseBasicResource.ASSET_PARENT, myEditSet.getDataList(MoneyWiseBasicDataType.PAYEE, MoneyWisePayeeList.class));
514         if (myEditSet.hasDataType(MoneyWiseBasicDataType.DEPOSITCATEGORY)) {
515             resolveDataLink(MoneyWiseBasicResource.CATEGORY_NAME, myEditSet.getDataList(MoneyWiseBasicDataType.DEPOSITCATEGORY, MoneyWiseDepositCategoryList.class));
516         }
517         if (myEditSet.hasDataType(MoneyWiseStaticDataType.CURRENCY)) {
518             resolveDataLink(MoneyWiseStaticDataType.CURRENCY, myEditSet.getDataList(MoneyWiseStaticDataType.CURRENCY, MoneyWiseCurrencyList.class));
519         }
520 
521         /* Resolve links in infoSet */
522         theInfoSet.resolveEditSetLinks(myEditSet);
523     }
524 
525     /**
526      * Set a new Maturity.
527      *
528      * @param pMaturity the new maturity
529      * @throws OceanusException on error
530      */
531     public void setMaturity(final OceanusDate pMaturity) throws OceanusException {
532         setInfoSetValue(MoneyWiseAccountInfoClass.MATURITY, pMaturity);
533     }
534 
535     /**
536      * Set a new SortCode.
537      *
538      * @param pSortCode the new sort code
539      * @throws OceanusException on error
540      */
541     public void setSortCode(final char[] pSortCode) throws OceanusException {
542         setInfoSetValue(MoneyWiseAccountInfoClass.SORTCODE, pSortCode);
543     }
544 
545     /**
546      * Set a new Account.
547      *
548      * @param pAccount the new account
549      * @throws OceanusException on error
550      */
551     public void setAccount(final char[] pAccount) throws OceanusException {
552         setInfoSetValue(MoneyWiseAccountInfoClass.ACCOUNT, pAccount);
553     }
554 
555     /**
556      * Set a new Reference.
557      *
558      * @param pReference the new reference
559      * @throws OceanusException on error
560      */
561     public void setReference(final char[] pReference) throws OceanusException {
562         setInfoSetValue(MoneyWiseAccountInfoClass.REFERENCE, pReference);
563     }
564 
565     /**
566      * Set a new Notes.
567      *
568      * @param pNotes the new notes
569      * @throws OceanusException on error
570      */
571     public void setNotes(final char[] pNotes) throws OceanusException {
572         setInfoSetValue(MoneyWiseAccountInfoClass.NOTES, pNotes);
573     }
574 
575     /**
576      * Set a new opening balance.
577      *
578      * @param pBalance the new opening balance
579      * @throws OceanusException on error
580      */
581     public void setOpeningBalance(final OceanusMoney pBalance) throws OceanusException {
582         setInfoSetValue(MoneyWiseAccountInfoClass.OPENINGBALANCE, pBalance);
583     }
584 
585     /**
586      * Set an infoSet value.
587      *
588      * @param pInfoClass the class of info to set
589      * @param pValue     the value to set
590      * @throws OceanusException on error
591      */
592     private void setInfoSetValue(final MoneyWiseAccountInfoClass pInfoClass,
593                                  final Object pValue) throws OceanusException {
594         /* Reject if there is no infoSet */
595         if (!hasInfoSet) {
596             throw new MoneyWiseLogicException(ERROR_BADINFOSET);
597         }
598 
599         /* Set the value */
600         theInfoSet.setValue(pInfoClass, pValue);
601     }
602 
603     @Override
604     public void adjustClosed() throws OceanusException {
605         /* Adjust closed date */
606         super.adjustClosed();
607 
608         /* If the maturity is null for a bond set it to close date */
609         if (isDepositClass(MoneyWiseDepositCategoryClass.BOND) && getMaturity() == null) {
610             /* Record a date for maturity */
611             setMaturity(getCloseDate());
612         }
613     }
614 
615     @Override
616     public MoneyWiseTransCategory getDetailedCategory(final MoneyWiseTransCategory pCategory,
617                                                       final MoneyWiseTaxCredit pYear) {
618         /* Switch on category type */
619         final MoneyWiseTransCategoryList myCategories = getDataSet().getDataList(MoneyWiseBasicDataType.TRANSCATEGORY, MoneyWiseTransCategoryList.class);
620         switch (Objects.requireNonNull(pCategory.getCategoryTypeClass())) {
621             case INTEREST:
622                 if (isTaxFree()) {
623                     return myCategories.getSingularClass(MoneyWiseTransCategoryClass.TAXFREEINTEREST);
624                 }
625                 if (isDepositClass(MoneyWiseDepositCategoryClass.PEER2PEER)) {
626                     return myCategories.getSingularClass(MoneyWiseTransCategoryClass.PEER2PEERINTEREST);
627                 }
628                 return myCategories.getSingularClass(isGross()
629                         || !pYear.isTaxCreditRequired()
630                         ? MoneyWiseTransCategoryClass.GROSSINTEREST
631                         : MoneyWiseTransCategoryClass.TAXEDINTEREST);
632             case LOYALTYBONUS:
633                 if (isTaxFree()) {
634                     return myCategories.getSingularClass(MoneyWiseTransCategoryClass.TAXFREELOYALTYBONUS);
635                 }
636                 return myCategories.getSingularClass(isGross()
637                         || !pYear.isTaxCreditRequired()
638                         ? MoneyWiseTransCategoryClass.GROSSLOYALTYBONUS
639                         : MoneyWiseTransCategoryClass.TAXEDLOYALTYBONUS);
640             default:
641                 return pCategory;
642         }
643     }
644 
645     @Override
646     public void touchUnderlyingItems() {
647         /* touch the category and currency */
648         getCategory().touchItem(this);
649         getAssetCurrency().touchItem(this);
650 
651         /* Touch parent */
652         getParent().touchItem(this);
653 
654         /* touch infoSet items */
655         theInfoSet.touchUnderlyingItems();
656     }
657 
658     @Override
659     public void touchOnUpdate() {
660         /* Reset touches from update set */
661         clearTouches(MoneyWiseBasicDataType.DEPOSITRATE);
662         clearTouches(MoneyWiseBasicDataType.PORTFOLIO);
663 
664         /* Touch parent */
665         getParent().touchItem(this);
666     }
667 
668     /**
669      * Update base deposit from an edited deposit.
670      *
671      * @param pDeposit the edited deposit
672      * @return whether changes have been made
673      */
674     @Override
675     public boolean applyChanges(final PrometheusDataItem pDeposit) {
676         /* Can only update from a deposit */
677         if (!(pDeposit instanceof MoneyWiseDeposit myDeposit)) {
678             return false;
679         }
680 
681         /* Store the current detail into history */
682         pushHistory();
683 
684         /* Apply basic changes */
685         applyBasicChanges(myDeposit);
686 
687         /* Check for changes */
688         return checkForHistory();
689     }
690 
691     @Override
692     public void adjustMapForItem() {
693         final MoneyWiseDepositList myList = getList();
694         final MoneyWiseDepositDataMap myMap = myList.getDataMap();
695         myMap.adjustForItem(this);
696     }
697 
698     @Override
699     public void removeItem() {
700         theInfoSet.removeItems();
701         super.removeItem();
702     }
703 
704     /**
705      * The Deposit List class.
706      */
707     public static class MoneyWiseDepositList
708             extends MoneyWiseAssetBaseList<MoneyWiseDeposit> {
709         /**
710          * Report fields.
711          */
712         private static final MetisFieldSet<MoneyWiseDepositList> FIELD_DEFS = MetisFieldSet.newFieldSet(MoneyWiseDepositList.class);
713 
714         /**
715          * The DepositInfo List.
716          */
717         private MoneyWiseDepositInfoList theInfoList;
718 
719         /**
720          * The AccountInfoType list.
721          */
722         private MoneyWiseAccountInfoTypeList theInfoTypeList;
723 
724         /**
725          * Construct an empty CORE list.
726          *
727          * @param pData the DataSet for the list
728          */
729         public MoneyWiseDepositList(final PrometheusDataSet pData) {
730             super(pData, MoneyWiseDeposit.class, MoneyWiseBasicDataType.DEPOSIT);
731         }
732 
733         /**
734          * Constructor for a cloned List.
735          *
736          * @param pSource the source List
737          */
738         protected MoneyWiseDepositList(final MoneyWiseDepositList pSource) {
739             super(pSource);
740         }
741 
742         @Override
743         public MetisFieldSet<MoneyWiseDepositList> getDataFieldSet() {
744             return FIELD_DEFS;
745         }
746 
747         @Override
748         public String listName() {
749             return LIST_NAME;
750         }
751 
752         @Override
753         public MetisFieldSetDef getItemFields() {
754             return MoneyWiseDeposit.FIELD_DEFS;
755         }
756 
757         @Override
758         protected MoneyWiseDepositDataMap getDataMap() {
759             return (MoneyWiseDepositDataMap) super.getDataMap();
760         }
761 
762         /**
763          * Obtain the depositInfoList.
764          *
765          * @return the deposit info list
766          */
767         public MoneyWiseDepositInfoList getDepositInfo() {
768             if (theInfoList == null) {
769                 theInfoList = getDataSet().getDataList(MoneyWiseBasicDataType.DEPOSITINFO, MoneyWiseDepositInfoList.class);
770             }
771             return theInfoList;
772         }
773 
774         /**
775          * Obtain the accountInfoTypeList.
776          *
777          * @return the account info type list
778          */
779         public MoneyWiseAccountInfoTypeList getActInfoTypes() {
780             if (theInfoTypeList == null) {
781                 theInfoTypeList = getEditSet() == null
782                         ? getDataSet().getDataList(MoneyWiseStaticDataType.ACCOUNTINFOTYPE, MoneyWiseAccountInfoTypeList.class)
783                         : getEditSet().getDataList(MoneyWiseStaticDataType.ACCOUNTINFOTYPE, MoneyWiseAccountInfoTypeList.class);
784             }
785             return theInfoTypeList;
786         }
787 
788         @Override
789         protected MoneyWiseDepositList getEmptyList(final PrometheusListStyle pStyle) {
790             final MoneyWiseDepositList myList = new MoneyWiseDepositList(this);
791             myList.setStyle(pStyle);
792             return myList;
793         }
794 
795         /**
796          * Derive Edit list.
797          *
798          * @param pEditSet the editSet
799          * @return the edit list
800          * @throws OceanusException on error
801          */
802         public MoneyWiseDepositList deriveEditList(final PrometheusEditSet pEditSet) throws OceanusException {
803             /* Build an empty List */
804             final MoneyWiseDepositList myList = getEmptyList(PrometheusListStyle.EDIT);
805             final MoneyWisePayeeList myPayees = pEditSet.getDataList(MoneyWiseBasicDataType.PAYEE, MoneyWisePayeeList.class);
806             myList.ensureMap(myPayees);
807             pEditSet.setEditEntryList(MoneyWiseBasicDataType.DEPOSIT, myList);
808             myList.getValidator().setEditSet(pEditSet);
809 
810             /* Store InfoType list */
811             myList.theInfoTypeList = pEditSet.getDataList(MoneyWiseStaticDataType.ACCOUNTINFOTYPE, MoneyWiseAccountInfoTypeList.class);
812 
813             /* Create info List */
814             final MoneyWiseDepositInfoList myDepInfo = getDepositInfo();
815             myList.theInfoList = myDepInfo.getEmptyList(PrometheusListStyle.EDIT);
816             pEditSet.setEditEntryList(MoneyWiseBasicDataType.DEPOSITINFO, myList.theInfoList);
817 
818             /* Store the editSet */
819             myList.setEditSet(pEditSet);
820 
821             /* Loop through the deposits */
822             final Iterator<MoneyWiseDeposit> myIterator = iterator();
823             while (myIterator.hasNext()) {
824                 final MoneyWiseDeposit myCurr = myIterator.next();
825 
826                 /* Ignore deleted deposits */
827                 if (myCurr.isDeleted()) {
828                     continue;
829                 }
830 
831                 /* Build the new linked deposit and add it to the list */
832                 final MoneyWiseDeposit myDeposit = new MoneyWiseDeposit(myList, myCurr);
833                 myList.add(myDeposit);
834                 myDeposit.resolveEditSetLinks();
835 
836                 /* Adjust the map */
837                 myDeposit.adjustMapForItem();
838             }
839 
840             /* Return the list */
841             return myList;
842         }
843 
844         @Override
845         public MoneyWiseDeposit findItemByName(final String pName) {
846             /* look up the name in the map */
847             return getDataMap().findItemByName(pName);
848         }
849 
850         @Override
851         public boolean checkAvailableName(final String pName) {
852             /* check availability in map */
853             return getDataMap().availableName(pName);
854         }
855 
856         @Override
857         public boolean validNameCount(final String pName) {
858             /* check availability in map */
859             return getDataMap().validNameCount(pName);
860         }
861 
862         @Override
863         public MoneyWiseDeposit addCopyItem(final PrometheusDataItem pDeposit) {
864             /* Can only clone a Deposit */
865             if (!(pDeposit instanceof MoneyWiseDeposit)) {
866                 throw new UnsupportedOperationException();
867             }
868 
869             final MoneyWiseDeposit myDeposit = new MoneyWiseDeposit(this, (MoneyWiseDeposit) pDeposit);
870             add(myDeposit);
871             return myDeposit;
872         }
873 
874         @Override
875         public MoneyWiseDeposit addNewItem() {
876             final MoneyWiseDeposit myDeposit = new MoneyWiseDeposit(this);
877             add(myDeposit);
878             return myDeposit;
879         }
880 
881         @Override
882         public MoneyWiseDeposit addValuesItem(final PrometheusDataValues pValues) throws OceanusException {
883             /* Create the deposit */
884             final MoneyWiseDeposit myDeposit = new MoneyWiseDeposit(this, pValues);
885 
886             /* Check that this DepositId has not been previously added */
887             if (!isIdUnique(myDeposit.getIndexedId())) {
888                 myDeposit.addError(ERROR_DUPLICATE, MetisDataResource.DATA_ID);
889                 throw new MoneyWiseDataException(myDeposit, ERROR_VALIDATION);
890             }
891 
892             /* Add to the list */
893             add(myDeposit);
894 
895             /* Loop through the info items */
896             if (pValues.hasInfoItems()) {
897                 /* Loop through the items */
898                 final Iterator<PrometheusInfoItem> myIterator = pValues.infoIterator();
899                 while (myIterator.hasNext()) {
900                     final PrometheusInfoItem myItem = myIterator.next();
901 
902                     /* Build info */
903                     final PrometheusDataValues myValues = myItem.getValues(myDeposit);
904                     theInfoList.addValuesItem(myValues);
905                 }
906             }
907 
908             /* Return it */
909             return myDeposit;
910         }
911 
912         /**
913          * Obtain default holding for portfolio.
914          *
915          * @param pParent   the parent
916          * @param isTaxFree should holding be taxFree?
917          * @return the default holding
918          */
919         public MoneyWiseDeposit getDefaultHolding(final MoneyWisePayee pParent,
920                                                   final boolean isTaxFree) {
921             /* loop through the deposits */
922             final Iterator<MoneyWiseDeposit> myIterator = iterator();
923             while (myIterator.hasNext()) {
924                 final MoneyWiseDeposit myDeposit = myIterator.next();
925 
926                 /* Ignore deleted and closed deposits and wrong taxFree status */
927                 boolean bIgnore = myDeposit.isDeleted() || myDeposit.isClosed();
928                 bIgnore |= !pParent.equals(myDeposit.getParent());
929                 bIgnore |= !isTaxFree == myDeposit.isTaxFree();
930                 if (!bIgnore) {
931                     return myDeposit;
932                 }
933             }
934 
935             /* Return no deposit */
936             return null;
937         }
938 
939         /**
940          * Ensure Map based on the payee list.
941          *
942          * @param pPayees the payee list
943          */
944         private void ensureMap(final MoneyWisePayeeList pPayees) {
945             setDataMap(new MoneyWiseDepositDataMap(pPayees));
946         }
947 
948         @Override
949         protected MoneyWiseDepositDataMap allocateDataMap() {
950             return new MoneyWiseDepositDataMap(getDataSet().getDataList(MoneyWiseBasicDataType.PAYEE, MoneyWisePayeeList.class));
951         }
952 
953         @Override
954         public void postProcessOnLoad() throws OceanusException {
955             /* Resolve links and sort the data */
956             super.resolveDataSetLinks();
957             reSort();
958         }
959     }
960 
961     /**
962      * The dataMap class.
963      */
964     protected static class MoneyWiseDepositDataMap
965             implements PrometheusDataMapItem, MetisFieldItem {
966         /**
967          * Report fields.
968          */
969         private static final MetisFieldSet<MoneyWiseDepositDataMap> FIELD_DEFS = MetisFieldSet.newFieldSet(MoneyWiseDepositDataMap.class);
970 
971         /*
972          * UnderlyingMap Field Id.
973          */
974         static {
975             FIELD_DEFS.declareLocalField(MoneyWiseBasicResource.MONEYWISEDATA_MAP_UNDERLYING, MoneyWiseDepositDataMap::getUnderlyingMap);
976         }
977 
978         /**
979          * The assetMap.
980          */
981         private final MoneyWiseAssetDataMap theUnderlyingMap;
982 
983         /**
984          * Constructor.
985          *
986          * @param pPayees the payee list
987          */
988         protected MoneyWiseDepositDataMap(final MoneyWisePayeeList pPayees) {
989             theUnderlyingMap = pPayees.getDataMap().getUnderlyingMap();
990         }
991 
992         @Override
993         public MetisFieldSet<MoneyWiseDepositDataMap> getDataFieldSet() {
994             return FIELD_DEFS;
995         }
996 
997         @Override
998         public String formatObject(final OceanusDataFormatter pFormatter) {
999             return FIELD_DEFS.getName();
1000         }
1001 
1002         /**
1003          * Obtain the underlying map.
1004          *
1005          * @return the underlying map
1006          */
1007         private MoneyWiseAssetDataMap getUnderlyingMap() {
1008             return theUnderlyingMap;
1009         }
1010 
1011         @Override
1012         public void resetMap() {
1013             /* No action */
1014         }
1015 
1016         @Override
1017         public void adjustForItem(final PrometheusDataItem pItem) {
1018             /* Adjust name count */
1019             theUnderlyingMap.adjustForItem(pItem);
1020         }
1021 
1022         /**
1023          * find item by name.
1024          *
1025          * @param pName the name to look up
1026          * @return the matching item
1027          */
1028         public MoneyWiseDeposit findItemByName(final String pName) {
1029             final MoneyWiseAssetBase myAsset = theUnderlyingMap.findAssetByName(pName);
1030             return myAsset instanceof MoneyWiseDeposit myDeposit
1031                     ? myDeposit
1032                     : null;
1033         }
1034 
1035         /**
1036          * Check validity of name.
1037          *
1038          * @param pName the name to look up
1039          * @return true/false
1040          */
1041         public boolean validNameCount(final String pName) {
1042             return theUnderlyingMap.validNameCount(pName);
1043         }
1044 
1045         /**
1046          * Check availability of name.
1047          *
1048          * @param pName the key to look up
1049          * @return true/false
1050          */
1051         public boolean availableName(final String pName) {
1052             return theUnderlyingMap.availableKey(pName);
1053         }
1054     }
1055 }