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.field.MetisFieldItem;
20  import io.github.tonywasher.joceanus.metis.field.MetisFieldSet;
21  import io.github.tonywasher.joceanus.moneywise.data.statics.MoneyWiseCurrency;
22  import io.github.tonywasher.joceanus.moneywise.data.statics.MoneyWiseSecurityClass;
23  import io.github.tonywasher.joceanus.oceanus.format.OceanusDataFormatter;
24  import io.github.tonywasher.joceanus.prometheus.data.PrometheusDataItem;
25  import io.github.tonywasher.joceanus.prometheus.data.PrometheusDataResource;
26  
27  import java.util.Currency;
28  
29  /**
30   * Portfolio/Security combination.
31   */
32  public final class MoneyWiseSecurityHolding
33          implements MetisFieldItem, MoneyWiseTransAsset, Comparable<Object> {
34      /**
35       * Name separator.
36       */
37      public static final String SECURITYHOLDING_SEP = ":";
38  
39      /**
40       * New Security Holding text.
41       */
42      public static final String SECURITYHOLDING_NEW = MoneyWiseBasicResource.SECURITYHOLDING_NEW.getValue();
43  
44      /**
45       * Report fields.
46       */
47      private static final MetisFieldSet<MoneyWiseSecurityHolding> FIELD_DEFS = MetisFieldSet.newFieldSet(MoneyWiseSecurityHolding.class);
48  
49      /*
50       * UnderlyingMap Field Id.
51       */
52      static {
53          FIELD_DEFS.declareLocalField(PrometheusDataResource.DATAITEM_ID, MoneyWiseSecurityHolding::getExternalId);
54          FIELD_DEFS.declareLocalField(PrometheusDataResource.DATAITEM_FIELD_NAME, MoneyWiseSecurityHolding::getName);
55          FIELD_DEFS.declareLocalField(MoneyWiseBasicDataType.PORTFOLIO, MoneyWiseSecurityHolding::getPortfolio);
56          FIELD_DEFS.declareLocalField(MoneyWiseBasicDataType.SECURITY, MoneyWiseSecurityHolding::getSecurity);
57      }
58  
59      /**
60       * The id of the holding.
61       */
62      private final Long theId;
63  
64      /**
65       * The portfolio of the holding.
66       */
67      private final MoneyWisePortfolio thePortfolio;
68  
69      /**
70       * The security of the holding.
71       */
72      private final MoneyWiseSecurity theSecurity;
73  
74      /**
75       * Constructor.
76       *
77       * @param pPortfolio the portfolio
78       * @param pSecurity  the security
79       */
80      MoneyWiseSecurityHolding(final MoneyWisePortfolio pPortfolio,
81                               final MoneyWiseSecurity pSecurity) {
82          /* Set portfolio and security */
83          thePortfolio = pPortfolio;
84          theSecurity = pSecurity;
85  
86          /* Generate the id */
87          theId = MoneyWiseAssetType.createExternalId(MoneyWiseAssetType.SECURITYHOLDING, thePortfolio.getIndexedId(), theSecurity.getIndexedId());
88      }
89  
90      @Override
91      public MetisFieldSet<MoneyWiseSecurityHolding> getDataFieldSet() {
92          return FIELD_DEFS;
93      }
94  
95      @Override
96      public String formatObject(final OceanusDataFormatter pFormatter) {
97          return toString();
98      }
99  
100     @Override
101     public String toString() {
102         return getName();
103     }
104 
105     @Override
106     public Boolean isClosed() {
107         /* Access constituent parts */
108         final MoneyWisePortfolio myPortfolio = getPortfolio();
109         final MoneyWiseSecurity mySecurity = getSecurity();
110 
111         /* Test underlying items */
112         return myPortfolio.isClosed()
113                 || mySecurity.isClosed();
114     }
115 
116     /**
117      * Is the holding deleted?
118      *
119      * @return true/false
120      */
121     public boolean isDeleted() {
122         /* Access constituent parts */
123         final MoneyWisePortfolio myPortfolio = getPortfolio();
124         final MoneyWiseSecurity mySecurity = getSecurity();
125 
126         /* Test underlying items */
127         return myPortfolio.isDeleted()
128                 || mySecurity.isDeleted();
129     }
130 
131     @Override
132     public Long getExternalId() {
133         return theId;
134     }
135 
136     @Override
137     public String getName() {
138         return generateName();
139     }
140 
141     @Override
142     public MoneyWisePayee getParent() {
143         return theSecurity.getParent();
144     }
145 
146     @Override
147     public boolean isTaxFree() {
148         return thePortfolio.isTaxFree();
149     }
150 
151     @Override
152     public boolean isGross() {
153         return thePortfolio.isGross();
154     }
155 
156     @Override
157     public boolean isShares() {
158         return theSecurity.isShares();
159     }
160 
161     @Override
162     public boolean isCapital() {
163         return theSecurity.isCapital();
164     }
165 
166     @Override
167     public boolean isAutoExpense() {
168         return false;
169     }
170 
171     @Override
172     public boolean isHidden() {
173         return false;
174     }
175 
176     /**
177      * Obtain Portfolio.
178      *
179      * @return the portfolio
180      */
181     public MoneyWisePortfolio getPortfolio() {
182         return thePortfolio;
183     }
184 
185     /**
186      * Obtain Security.
187      *
188      * @return the security
189      */
190     public MoneyWiseSecurity getSecurity() {
191         return theSecurity;
192     }
193 
194     @Override
195     public MoneyWiseAssetType getAssetType() {
196         return MoneyWiseAssetType.SECURITYHOLDING;
197     }
198 
199     @Override
200     public MoneyWiseCurrency getAssetCurrency() {
201         return theSecurity.getAssetCurrency();
202     }
203 
204     @Override
205     public Currency getCurrency() {
206         return getAssetCurrency().getCurrency();
207     }
208 
209     @Override
210     public boolean isForeign() {
211         final MoneyWiseCurrency myDefault = thePortfolio.getDefaultCurrency();
212         return !myDefault.equals(getAssetCurrency());
213     }
214 
215     /**
216      * Generate the name.
217      *
218      * @return the name.
219      */
220     private String generateName() {
221         /* Build and return the name */
222         return thePortfolio.getName()
223                 + SECURITYHOLDING_SEP
224                 + theSecurity.getName();
225     }
226 
227     /**
228      * Obtain the security class.
229      *
230      * @return the security class.
231      */
232     private MoneyWiseSecurityClass getSecurityTypeClass() {
233         /* Check for match */
234         return theSecurity.getCategoryClass();
235     }
236 
237     /**
238      * Is this holding the required security class.
239      *
240      * @param pClass the required security class.
241      * @return true/false
242      */
243     public boolean isSecurityClass(final MoneyWiseSecurityClass pClass) {
244         /* Check for match */
245         return getSecurityTypeClass() == pClass;
246     }
247 
248     @Override
249     public void touchItem(final PrometheusDataItem pSource) {
250         /* Touch references */
251         thePortfolio.touchItem(pSource);
252         theSecurity.touchItem(pSource);
253     }
254 
255     @Override
256     public boolean equals(final Object pThat) {
257         /* Handle the trivial cases */
258         if (this == pThat) {
259             return true;
260         }
261         if (pThat == null) {
262             return false;
263         }
264         if (!(pThat instanceof MoneyWiseSecurityHolding myThat)) {
265             return false;
266         }
267 
268         /* Compare the Portfolios */
269         if (!getPortfolio().equals(myThat.getPortfolio())) {
270             return false;
271         }
272 
273         /* Compare securities */
274         return getSecurity().equals(myThat.getSecurity());
275     }
276 
277     @Override
278     public int hashCode() {
279         final int myHash = MetisFieldSet.HASH_PRIME * getPortfolio().hashCode();
280         return myHash + getSecurity().hashCode();
281     }
282 
283     @Override
284     public int compareTo(final Object pThat) {
285         /* Handle the trivial cases */
286         if (this.equals(pThat)) {
287             return 0;
288         }
289         if (pThat == null) {
290             return -1;
291         }
292 
293         /* If the Asset is not a SecurityHolding we are last */
294         if (!(pThat instanceof MoneyWiseSecurityHolding myThat)) {
295             return 1;
296         }
297 
298         /* Compare portfolios */
299         int iDiff = getPortfolio().compareTo(myThat.getPortfolio());
300         if (iDiff == 0) {
301             /* Compare securities */
302             iDiff = getSecurity().compareTo(myThat.getSecurity());
303         }
304 
305         /* Return the result */
306         return iDiff;
307     }
308 
309     /**
310      * Are the currencies the same?
311      *
312      * @return true/false
313      */
314     boolean validCurrencies() {
315         return thePortfolio.getCurrency().equals(theSecurity.getCurrency());
316     }
317 }