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.atlas.data.analysis.buckets;
18  
19  import io.github.tonywasher.joceanus.metis.data.MetisDataFieldValue;
20  import io.github.tonywasher.joceanus.metis.data.MetisDataItem.MetisDataFieldId;
21  import io.github.tonywasher.joceanus.metis.field.MetisFieldItem.MetisFieldTableItem;
22  import io.github.tonywasher.joceanus.metis.field.MetisFieldSet;
23  import io.github.tonywasher.joceanus.moneywise.atlas.data.analysis.base.MoneyWiseXAnalysisEvent;
24  import io.github.tonywasher.joceanus.moneywise.atlas.data.analysis.base.MoneyWiseXAnalysisHistory;
25  import io.github.tonywasher.joceanus.moneywise.atlas.data.analysis.buckets.MoneyWiseXAnalysisInterfaces.MoneyWiseXAnalysisBucketRegister;
26  import io.github.tonywasher.joceanus.moneywise.atlas.data.analysis.values.MoneyWiseXAnalysisTaxBasisAttr;
27  import io.github.tonywasher.joceanus.moneywise.atlas.data.analysis.values.MoneyWiseXAnalysisTaxBasisValues;
28  import io.github.tonywasher.joceanus.moneywise.data.basic.MoneyWiseAssetType;
29  import io.github.tonywasher.joceanus.moneywise.data.basic.MoneyWiseTransAsset;
30  import io.github.tonywasher.joceanus.moneywise.data.statics.MoneyWiseCurrency;
31  import io.github.tonywasher.joceanus.moneywise.data.statics.MoneyWiseStaticDataType;
32  import io.github.tonywasher.joceanus.moneywise.data.statics.MoneyWiseTaxBasis;
33  import io.github.tonywasher.joceanus.oceanus.date.OceanusDate;
34  import io.github.tonywasher.joceanus.oceanus.date.OceanusDateRange;
35  import io.github.tonywasher.joceanus.oceanus.decimal.OceanusDecimal;
36  import io.github.tonywasher.joceanus.oceanus.decimal.OceanusMoney;
37  import io.github.tonywasher.joceanus.oceanus.format.OceanusDataFormatter;
38  
39  import java.util.Currency;
40  
41  /**
42   * The TaxBasis Bucket class.
43   */
44  public abstract class MoneyWiseXAnalysisTaxBasisBaseBucket
45          implements MetisFieldTableItem, MoneyWiseXAnalysisBucketRegister {
46      /**
47       * Local Report fields.
48       */
49      private static final MetisFieldSet<MoneyWiseXAnalysisTaxBasisBaseBucket> FIELD_DEFS = MetisFieldSet.newFieldSet(MoneyWiseXAnalysisTaxBasisBaseBucket.class);
50  
51      /*
52       * Declare Fields.
53       */
54      static {
55          FIELD_DEFS.declareLocalField(MoneyWiseXAnalysisBucketResource.ANALYSIS_NAME, MoneyWiseXAnalysisTaxBasisBaseBucket::getAnalysis);
56          FIELD_DEFS.declareLocalField(MoneyWiseStaticDataType.TAXBASIS, MoneyWiseXAnalysisTaxBasisBaseBucket::getTaxBasis);
57          FIELD_DEFS.declareLocalField(MoneyWiseXAnalysisBucketResource.BUCKET_BASEVALUES, MoneyWiseXAnalysisTaxBasisBaseBucket::getBaseValues);
58          FIELD_DEFS.declareLocalField(MoneyWiseXAnalysisBucketResource.BUCKET_HISTORY, MoneyWiseXAnalysisTaxBasisBaseBucket::getHistoryMap);
59          FIELD_DEFS.declareLocalFieldsForEnum(MoneyWiseXAnalysisTaxBasisAttr.class, MoneyWiseXAnalysisTaxBasisBaseBucket::getAttributeValue);
60      }
61  
62      /**
63       * Totals bucket name.
64       */
65      private static final MetisDataFieldId NAME_TOTALS = MoneyWiseXAnalysisBucketResource.ANALYSIS_TOTALS;
66  
67      /**
68       * The analysis.
69       */
70      private final MoneyWiseXAnalysisHolder theAnalysis;
71  
72      /**
73       * Tax Basis.
74       */
75      private final MoneyWiseTaxBasis theTaxBasis;
76  
77      /**
78       * Values.
79       */
80      private final MoneyWiseXAnalysisTaxBasisValues theValues;
81  
82      /**
83       * The base values.
84       */
85      private final MoneyWiseXAnalysisTaxBasisValues theBaseValues;
86  
87      /**
88       * History Map.
89       */
90      private final MoneyWiseXAnalysisHistory<MoneyWiseXAnalysisTaxBasisValues, MoneyWiseXAnalysisTaxBasisAttr> theHistory;
91  
92      /**
93       * Are we an expense bucket?
94       */
95      private final boolean isExpense;
96  
97      /**
98       * Constructor.
99       *
100      * @param pAnalysis the analysis
101      * @param pTaxBasis the basis
102      */
103     protected MoneyWiseXAnalysisTaxBasisBaseBucket(final MoneyWiseXAnalysisHolder pAnalysis,
104                                                    final MoneyWiseTaxBasis pTaxBasis) {
105         /* Store the parameters */
106         theTaxBasis = pTaxBasis;
107         theAnalysis = pAnalysis;
108         isExpense = theTaxBasis != null
109                 && theTaxBasis.getTaxClass().isExpense();
110 
111         /* Create the history map */
112         final MoneyWiseCurrency myDefault = theAnalysis.getCurrency();
113         final Currency myCurrency = myDefault == null
114                 ? MoneyWiseXAnalysisAccountBucket.DEFAULT_CURRENCY
115                 : myDefault.getCurrency();
116         final MoneyWiseXAnalysisTaxBasisValues myValues = new MoneyWiseXAnalysisTaxBasisValues(myCurrency);
117         theHistory = new MoneyWiseXAnalysisHistory<>(myValues);
118 
119         /* Access the key value maps */
120         theValues = theHistory.getValues();
121         theBaseValues = theHistory.getBaseValues();
122     }
123 
124     /**
125      * Constructor.
126      *
127      * @param pAnalysis the analysis
128      * @param pBase     the underlying bucket
129      * @param pDate     the date for the bucket
130      */
131     protected MoneyWiseXAnalysisTaxBasisBaseBucket(final MoneyWiseXAnalysisHolder pAnalysis,
132                                                    final MoneyWiseXAnalysisTaxBasisBaseBucket pBase,
133                                                    final OceanusDate pDate) {
134         /* Copy details from base */
135         theTaxBasis = pBase.getTaxBasis();
136         theAnalysis = pAnalysis;
137         isExpense = pBase.isExpense();
138 
139         /* Access the relevant history */
140         theHistory = new MoneyWiseXAnalysisHistory<>(pBase.getHistoryMap(), pDate);
141 
142         /* Access the key value maps */
143         theValues = theHistory.getValues();
144         theBaseValues = theHistory.getBaseValues();
145     }
146 
147     /**
148      * Constructor.
149      *
150      * @param pAnalysis the analysis
151      * @param pBase     the underlying bucket
152      * @param pRange    the range for the bucket
153      */
154     protected MoneyWiseXAnalysisTaxBasisBaseBucket(final MoneyWiseXAnalysisHolder pAnalysis,
155                                                    final MoneyWiseXAnalysisTaxBasisBaseBucket pBase,
156                                                    final OceanusDateRange pRange) {
157         /* Copy details from base */
158         theTaxBasis = pBase.getTaxBasis();
159         theAnalysis = pAnalysis;
160         isExpense = pBase.isExpense();
161 
162         /* Access the relevant history */
163         theHistory = new MoneyWiseXAnalysisHistory<>(pBase.getHistoryMap(), pRange);
164 
165         /* Access the key value maps */
166         theValues = theHistory.getValues();
167         theBaseValues = theHistory.getBaseValues();
168     }
169 
170     @Override
171     public MetisFieldSet<? extends MoneyWiseXAnalysisTaxBasisBaseBucket> getDataFieldSet() {
172         return FIELD_DEFS;
173     }
174 
175     @Override
176     public String formatObject(final OceanusDataFormatter pFormatter) {
177         return toString();
178     }
179 
180     @Override
181     public String toString() {
182         return getName() + " " + theValues;
183     }
184 
185     @Override
186     public Integer getIndexedId() {
187         return theTaxBasis.getIndexedId();
188     }
189 
190     @Override
191     public Long getBucketId() {
192         return MoneyWiseAssetType.createExternalId(MoneyWiseAssetType.TAXBASIS, getIndexedId());
193     }
194 
195     /**
196      * Obtain name.
197      *
198      * @return the name
199      */
200     public String getName() {
201         return theTaxBasis == null
202                 ? NAME_TOTALS.getId()
203                 : theTaxBasis.getName();
204     }
205 
206     /**
207      * Obtain tax basis.
208      *
209      * @return the basis
210      */
211     public MoneyWiseTaxBasis getTaxBasis() {
212         return theTaxBasis;
213     }
214 
215     /**
216      * Is this an expense bucket.
217      *
218      * @return true/false
219      */
220     public boolean isExpense() {
221         return isExpense;
222     }
223 
224     /**
225      * Is this bucket idle?
226      *
227      * @return true/false
228      */
229     public boolean isIdle() {
230         return theHistory.isIdle();
231     }
232 
233     /**
234      * Obtain the value map.
235      *
236      * @return the value map
237      */
238     public MoneyWiseXAnalysisTaxBasisValues getValues() {
239         return theValues;
240     }
241 
242     /**
243      * Obtain the value for a particular attribute.
244      *
245      * @param pAttr the attribute
246      * @return the value
247      */
248     public OceanusMoney getMoneyValue(final MoneyWiseXAnalysisTaxBasisAttr pAttr) {
249         return theValues.getMoneyValue(pAttr);
250     }
251 
252     /**
253      * Obtain the base value map.
254      *
255      * @return the base value map
256      */
257     public MoneyWiseXAnalysisTaxBasisValues getBaseValues() {
258         return theBaseValues;
259     }
260 
261     /**
262      * Obtain values for event.
263      *
264      * @param pEvent the event
265      * @return the values (or null)
266      */
267     public MoneyWiseXAnalysisTaxBasisValues getValuesForEvent(final MoneyWiseXAnalysisEvent pEvent) {
268         /* Obtain values for event */
269         return theHistory.getValuesForEvent(pEvent);
270     }
271 
272     /**
273      * Obtain previous values for event.
274      *
275      * @param pEvent the event
276      * @return the values (or null)
277      */
278     public MoneyWiseXAnalysisTaxBasisValues getPreviousValuesForEvent(final MoneyWiseXAnalysisEvent pEvent) {
279         return theHistory.getPreviousValuesForEvent(pEvent);
280     }
281 
282     /**
283      * Obtain delta for event.
284      *
285      * @param pEvent the event
286      * @param pAttr  the attribute
287      * @return the delta (or null)
288      */
289     public OceanusDecimal getDeltaForEvent(final MoneyWiseXAnalysisEvent pEvent,
290                                            final MoneyWiseXAnalysisTaxBasisAttr pAttr) {
291         /* Obtain delta for event */
292         return theHistory.getDeltaValue(pEvent, pAttr);
293     }
294 
295     /**
296      * Obtain the history map.
297      *
298      * @return the history map
299      */
300     private MoneyWiseXAnalysisHistory<MoneyWiseXAnalysisTaxBasisValues, MoneyWiseXAnalysisTaxBasisAttr> getHistoryMap() {
301         return theHistory;
302     }
303 
304     /**
305      * Obtain the analysis.
306      *
307      * @return the analysis
308      */
309     protected MoneyWiseXAnalysisHolder getAnalysis() {
310         return theAnalysis;
311     }
312 
313     /**
314      * Obtain date range.
315      *
316      * @return the range
317      */
318     public OceanusDateRange getDateRange() {
319         return theAnalysis.getDateRange();
320     }
321 
322     /**
323      * Set Attribute.
324      *
325      * @param pAttr  the attribute
326      * @param pValue the value of the attribute
327      */
328     protected void setValue(final MoneyWiseXAnalysisTaxBasisAttr pAttr,
329                             final OceanusMoney pValue) {
330         /* Set the value into the list */
331         theValues.setValue(pAttr, pValue);
332     }
333 
334     /**
335      * Get an attribute value.
336      *
337      * @param pAttr the attribute
338      * @return the value to set
339      */
340     private Object getAttributeValue(final MoneyWiseXAnalysisTaxBasisAttr pAttr) {
341         /* Access value of object */
342         final Object myValue = getValue(pAttr);
343 
344         /* Return the value */
345         return myValue != null
346                 ? myValue
347                 : MetisDataFieldValue.SKIP;
348     }
349 
350     /**
351      * Obtain an attribute value.
352      *
353      * @param pAttr the attribute
354      * @return the value of the attribute or null
355      */
356     private Object getValue(final MoneyWiseXAnalysisTaxBasisAttr pAttr) {
357         /* Obtain the attribute */
358         return theValues.getValue(pAttr);
359     }
360 
361     /**
362      * Adjust Gross and Nett values by amount.
363      *
364      * @param pAmount the amount
365      */
366     public void adjustGrossAndNett(final OceanusMoney pAmount) {
367         adjustGrossAndNett(null, pAmount);
368     }
369 
370     /**
371      * Adjust Gross value by amount.
372      *
373      * @param pAmount the amount
374      */
375     public void adjustGross(final OceanusMoney pAmount) {
376         adjustGross(null, pAmount);
377     }
378 
379     /**
380      * Adjust Gross and Tax values by amount.
381      *
382      * @param pAmount the amount
383      */
384     public void adjustGrossAndTax(final OceanusMoney pAmount) {
385         adjustGrossAndTax(null, pAmount);
386     }
387 
388     /**
389      * Adjust Gross and Nett values by amount.
390      *
391      * @param pAccount the relevant account
392      * @param pAmount  the amount
393      * @return the adjusted taxBasisAccountBucket (or null)
394      */
395     public MoneyWiseXAnalysisTaxBasisBaseBucket adjustGrossAndNett(final MoneyWiseTransAsset pAccount,
396                                                                    final OceanusMoney pAmount) {
397         return adjustValue(pAccount, pAmount, MoneyWiseXTaxBasisAdjust.STANDARD);
398     }
399 
400     /**
401      * Adjust Gross value by amount.
402      *
403      * @param pAccount the relevant account
404      * @param pAmount  the amount
405      * @return the adjusted taxBasisAccountBucket (or null)
406      */
407     public MoneyWiseXAnalysisTaxBasisBaseBucket adjustGross(final MoneyWiseTransAsset pAccount,
408                                                             final OceanusMoney pAmount) {
409         return adjustValue(pAccount, pAmount, MoneyWiseXTaxBasisAdjust.GROSS);
410     }
411 
412     /**
413      * Adjust Gross and Tax values by amount.
414      *
415      * @param pAccount the relevant account
416      * @param pAmount  the amount
417      * @return the adjusted taxBasisAccountBucket (or null)
418      */
419     public MoneyWiseXAnalysisTaxBasisBaseBucket adjustGrossAndTax(final MoneyWiseTransAsset pAccount,
420                                                                   final OceanusMoney pAmount) {
421         return adjustValue(pAccount, pAmount, MoneyWiseXTaxBasisAdjust.TAXCREDIT);
422     }
423 
424     /**
425      * Adjust value.
426      *
427      * @param pAccount the relevant account
428      * @param pValue   the value
429      * @param pAdjust  adjustment control
430      * @return the adjusted taxBasisAccountBucket (or null)
431      */
432     MoneyWiseXAnalysisTaxBasisBaseBucket adjustValue(final MoneyWiseTransAsset pAccount,
433                                                      final OceanusMoney pValue,
434                                                      final MoneyWiseXTaxBasisAdjust pAdjust) {
435         /* Access the existing value */
436         OceanusMoney myGross = theValues.getMoneyValue(MoneyWiseXAnalysisTaxBasisAttr.GROSS);
437         myGross = new OceanusMoney(myGross);
438 
439         /* Subtract or add the value depending as to whether we are an expense bucket */
440         if (isExpense) {
441             myGross.subtractAmount(pValue);
442         } else {
443             myGross.addAmount(pValue);
444         }
445 
446         /* Record the new value */
447         setValue(MoneyWiseXAnalysisTaxBasisAttr.GROSS, myGross);
448 
449         /* If we are adjusting Nett */
450         if (pAdjust.adjustNett()) {
451             /* Access the existing value */
452             OceanusMoney myNett = theValues.getMoneyValue(MoneyWiseXAnalysisTaxBasisAttr.NETT);
453             myNett = new OceanusMoney(myNett);
454 
455             /* Subtract or add the value if we are an expense/income bucket */
456             if (isExpense) {
457                 myNett.subtractAmount(pValue);
458             } else {
459                 myNett.addAmount(pValue);
460             }
461 
462             /* Record the new value */
463             setValue(MoneyWiseXAnalysisTaxBasisAttr.NETT, myNett);
464         }
465 
466         /* If we are adjusting TaxCredit */
467         if (pAdjust.adjustTaxCredit()) {
468             /* Access the existing value */
469             OceanusMoney myTax = theValues.getMoneyValue(MoneyWiseXAnalysisTaxBasisAttr.TAXCREDIT);
470             myTax = new OceanusMoney(myTax);
471 
472             /* Subtract or add the value if we are an expense/income bucket */
473             if (isExpense) {
474                 myTax.subtractAmount(pValue);
475             } else {
476                 myTax.addAmount(pValue);
477             }
478 
479             /* Record the new value */
480             setValue(MoneyWiseXAnalysisTaxBasisAttr.TAXCREDIT, myTax);
481         }
482 
483         /* Adjust the account value */
484         return adjustAccountValue(pAccount, pValue, pAdjust);
485     }
486 
487     /**
488      * Adjust account value.
489      *
490      * @param pAccount the relevant account
491      * @param pValue   the value
492      * @param pAdjust  adjustment control
493      * @return the adjusted taxBasisAccountBucket (or null)
494      */
495     MoneyWiseXAnalysisTaxBasisBaseBucket adjustAccountValue(final MoneyWiseTransAsset pAccount,
496                                                             final OceanusMoney pValue,
497                                                             final MoneyWiseXTaxBasisAdjust pAdjust) {
498         return null;
499     }
500 
501     @Override
502     public void registerEvent(final MoneyWiseXAnalysisEvent pEvent) {
503         /* Register the transaction in the history */
504         theHistory.registerEvent(pEvent, theValues);
505     }
506 
507     /**
508      * Add values.
509      *
510      * @param pBucket tax category bucket
511      */
512     protected void addValues(final MoneyWiseXAnalysisTaxBasisBaseBucket pBucket) {
513         /* Add the values */
514         OceanusMoney myAmount = theValues.getMoneyValue(MoneyWiseXAnalysisTaxBasisAttr.GROSS);
515         myAmount.addAmount(pBucket.getMoneyValue(MoneyWiseXAnalysisTaxBasisAttr.GROSS));
516         myAmount = theValues.getMoneyValue(MoneyWiseXAnalysisTaxBasisAttr.NETT);
517         myAmount.addAmount(pBucket.getMoneyValue(MoneyWiseXAnalysisTaxBasisAttr.NETT));
518     }
519 
520     /**
521      * Adjust to base.
522      */
523     protected void adjustToBase() {
524         /* Adjust to base values */
525         theValues.adjustToBaseValues(theBaseValues);
526         theBaseValues.resetBaseValues();
527     }
528 
529     /**
530      * Value adjust Modes.
531      */
532     public enum MoneyWiseXTaxBasisAdjust {
533         /**
534          * Adjust both Gross and Nett.
535          */
536         STANDARD,
537 
538         /**
539          * Adjust Gross only.
540          */
541         GROSS,
542 
543         /**
544          * Adjust Gross and Tax.
545          */
546         TAXCREDIT;
547 
548         /**
549          * should we adjust Nett?
550          *
551          * @return true/false
552          */
553         private boolean adjustNett() {
554             return this == STANDARD;
555         }
556 
557         /**
558          * should we adjust TaxCredit?
559          *
560          * @return true/false
561          */
562         private boolean adjustTaxCredit() {
563             return this == TAXCREDIT;
564         }
565     }
566 }