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.quicken.file;
18  
19  import io.github.tonywasher.joceanus.moneywise.data.basic.MoneyWiseCash;
20  import io.github.tonywasher.joceanus.moneywise.data.basic.MoneyWiseDataSet;
21  import io.github.tonywasher.joceanus.moneywise.data.basic.MoneyWiseDeposit;
22  import io.github.tonywasher.joceanus.moneywise.data.basic.MoneyWisePayee;
23  import io.github.tonywasher.joceanus.moneywise.data.basic.MoneyWisePayee.MoneyWisePayeeList;
24  import io.github.tonywasher.joceanus.moneywise.data.basic.MoneyWisePortfolio;
25  import io.github.tonywasher.joceanus.moneywise.data.basic.MoneyWiseSecurityHolding;
26  import io.github.tonywasher.joceanus.moneywise.data.basic.MoneyWiseTransAsset;
27  import io.github.tonywasher.joceanus.moneywise.data.basic.MoneyWiseTransCategory;
28  import io.github.tonywasher.joceanus.moneywise.data.basic.MoneyWiseTransCategory.MoneyWiseTransCategoryList;
29  import io.github.tonywasher.joceanus.moneywise.data.basic.MoneyWiseTransTag;
30  import io.github.tonywasher.joceanus.moneywise.data.basic.MoneyWiseTransaction;
31  import io.github.tonywasher.joceanus.moneywise.data.statics.MoneyWisePayeeClass;
32  import io.github.tonywasher.joceanus.moneywise.data.statics.MoneyWiseTransCategoryClass;
33  import io.github.tonywasher.joceanus.moneywise.data.statics.MoneyWiseTransInfoClass;
34  import io.github.tonywasher.joceanus.moneywise.lethe.data.analysis.data.MoneyWiseAnalysis;
35  import io.github.tonywasher.joceanus.moneywise.quicken.definitions.MoneyWiseQIFType;
36  import io.github.tonywasher.joceanus.oceanus.date.OceanusDate;
37  import io.github.tonywasher.joceanus.oceanus.decimal.OceanusMoney;
38  
39  import java.util.ArrayList;
40  import java.util.Iterator;
41  import java.util.List;
42  import java.util.Objects;
43  
44  /**
45   * Builder class for QIF File.
46   */
47  public class MoneyWiseQIFBuilder
48          implements MoneyWiseQIFHelper {
49      /**
50       * Quicken Transfer.
51       */
52      private static final String QIF_XFER = "Transfer";
53  
54      /**
55       * Quicken Transfer from.
56       */
57      private static final String QIF_XFERFROM = " from ";
58  
59      /**
60       * Quicken Transfer to.
61       */
62      private static final String QIF_XFERTO = " to ";
63  
64      /**
65       * The QIF Register.
66       */
67      private final MoneyWiseQIFRegister theRegister;
68  
69      /**
70       * The QIF File Type.
71       */
72      private final MoneyWiseQIFType theFileType;
73  
74      /**
75       * The QIF Portfolio Builder.
76       */
77      private final MoneyWiseQIFPortfolioBuilder thePortBuilder;
78  
79      /**
80       * The TaxMan payee.
81       */
82      private final MoneyWisePayee theTaxMan;
83  
84      /**
85       * The TaxCredit category.
86       */
87      private final MoneyWiseTransCategory theTaxCategory;
88  
89      /**
90       * The NatInsurance category.
91       */
92      private final MoneyWiseTransCategory theNatInsCategory;
93  
94      /**
95       * The DeemedBenefit category.
96       */
97      private final MoneyWiseTransCategory theBenefitCategory;
98  
99      /**
100      * The Withheld category.
101      */
102     private final MoneyWiseTransCategory theWithheldCategory;
103 
104     /**
105      * The Opening category.
106      */
107     private final MoneyWiseTransCategory theOpeningCategory;
108 
109     /**
110      * Constructor.
111      *
112      * @param pRegister the QIF Register
113      * @param pData     the data
114      * @param pAnalysis the analysis
115      */
116     protected MoneyWiseQIFBuilder(final MoneyWiseQIFRegister pRegister,
117                                   final MoneyWiseDataSet pData,
118                                   final MoneyWiseAnalysis pAnalysis) {
119         /* Store parameters */
120         theRegister = pRegister;
121         theFileType = pRegister.getFileType();
122 
123         /* Create portfolio builder */
124         thePortBuilder = new MoneyWiseQIFPortfolioBuilder(this, pData, pAnalysis);
125 
126         /* Store Tax account */
127         final MoneyWisePayeeList myPayees = pData.getPayees();
128         theTaxMan = myPayees.getSingularClass(MoneyWisePayeeClass.TAXMAN);
129 
130         /* Store categories */
131         final MoneyWiseTransCategoryList myCategories = pData.getTransCategories();
132         theTaxCategory = myCategories.getEventInfoCategory(MoneyWiseTransInfoClass.TAXCREDIT);
133         theNatInsCategory = myCategories.getEventInfoCategory(MoneyWiseTransInfoClass.EMPLOYEENATINS);
134         theBenefitCategory = myCategories.getEventInfoCategory(MoneyWiseTransInfoClass.DEEMEDBENEFIT);
135         theWithheldCategory = myCategories.getEventInfoCategory(MoneyWiseTransInfoClass.WITHHELD);
136         theOpeningCategory = myCategories.getSingularClass(MoneyWiseTransCategoryClass.OPENINGBALANCE);
137     }
138 
139     @Override
140     public MoneyWiseQIFRegister getRegister() {
141         return theRegister;
142     }
143 
144     @Override
145     public MoneyWiseQIFEventCategory getTaxCategory() {
146         return theRegister.registerCategory(theTaxCategory);
147     }
148 
149     @Override
150     public MoneyWiseQIFPayee getTaxMan() {
151         return theRegister.registerPayee(theTaxMan);
152     }
153 
154     /**
155      * Process event.
156      *
157      * @param pTrans the transaction
158      */
159     protected void processEvent(final MoneyWiseTransaction pTrans) {
160         /* Access account and partner */
161         final MoneyWiseTransAsset myAccount = pTrans.getAccount();
162         final MoneyWiseTransAsset myPartner = pTrans.getPartner();
163         final boolean bFrom = pTrans.getDirection().isFrom();
164 
165         /* If this deals with a payee */
166         if (myPartner instanceof MoneyWisePayee myPayee) {
167             /* If this is expense */
168             if (bFrom) {
169                 /* Process Debit Payee */
170                 processDebitPayee(myPayee, myAccount, pTrans);
171             } else {
172                 /* Process Credit Payee */
173                 processCreditPayee(myPayee, myAccount, pTrans);
174             }
175 
176         } else if (bFrom) {
177             /* else process Transfer Partner -> Account */
178             processTransfer(myPartner, myAccount, pTrans);
179         } else {
180             /* else process Transfer Account -> Partner */
181             processTransfer(myAccount, myPartner, pTrans);
182         }
183     }
184 
185     /**
186      * Process opening balance.
187      *
188      * @param pDeposit   the deposit
189      * @param pStartDate the start date
190      * @param pBalance   the opening balance
191      */
192     protected void processBalance(final MoneyWiseDeposit pDeposit,
193                                   final OceanusDate pStartDate,
194                                   final OceanusMoney pBalance) {
195         /* Access the Account details */
196         final MoneyWiseQIFAccountEvents myAccount = theRegister.registerAccount(pDeposit);
197 
198         /* Create the event */
199         final MoneyWiseQIFEvent myEvent = new MoneyWiseQIFEvent(theRegister, pStartDate);
200         myEvent.recordAmount(pBalance);
201 
202         /* If we are using self-Opening balance */
203         if (theFileType.selfOpeningBalance()) {
204             /* Record self reference */
205             myEvent.recordAccount(myAccount.getAccount());
206 
207             /* else use an event */
208         } else {
209             /* Register category */
210             final MoneyWiseQIFEventCategory myCategory = theRegister.registerCategory(theOpeningCategory);
211             myEvent.recordCategory(myCategory);
212         }
213 
214         /* Add event to event list */
215         myAccount.addEvent(myEvent);
216     }
217 
218     /**
219      * Process debit payee event.
220      *
221      * @param pPayee  the payee
222      * @param pCredit the credit account
223      * @param pTrans  the transaction
224      */
225     protected void processDebitPayee(final MoneyWisePayee pPayee,
226                                      final MoneyWiseTransAsset pCredit,
227                                      final MoneyWiseTransaction pTrans) {
228         /* If this is a cash recovery */
229         if (pCredit instanceof MoneyWiseCash myCash
230                 && myCash.isAutoExpense()) {
231             /* process as cash recovery */
232             processCashRecovery(pPayee, myCash, pTrans);
233 
234             /* If this is an income to a security */
235         } else if (pCredit instanceof MoneyWiseSecurityHolding myHolding) {
236             /* process as income to security */
237             thePortBuilder.processIncomeToSecurity(pPayee, myHolding, pTrans);
238 
239             /* If this is an income to a portfolio */
240         } else if (pCredit instanceof MoneyWisePortfolio myPortfolio) {
241             /* process as income to portfolio */
242             thePortBuilder.processIncomeToPortfolio(pPayee, myPortfolio, pTrans);
243 
244             /* else if we have additional detail */
245         } else if (hasXtraDetail(pTrans)) {
246             /* process as detailed income */
247             processDetailedIncome(pPayee, pCredit, pTrans);
248 
249         } else {
250             /* process as standard income */
251             processStandardIncome(pPayee, pCredit, pTrans);
252         }
253     }
254 
255     /**
256      * Process credit payee event.
257      *
258      * @param pPayee the payee
259      * @param pDebit the debit account
260      * @param pTrans the transaction
261      */
262     protected void processCreditPayee(final MoneyWisePayee pPayee,
263                                       final MoneyWiseTransAsset pDebit,
264                                       final MoneyWiseTransaction pTrans) {
265         /* If this is a cash payment */
266         if (pDebit instanceof MoneyWiseCash myCash
267                 && myCash.isAutoExpense()) {
268             /* process as cash payment */
269             processCashPayment(pPayee, myCash, pTrans);
270 
271             /* If this is an expense from a security */
272         } else if (pDebit instanceof MoneyWiseSecurityHolding myHolding) {
273             /* process as expense from security */
274             thePortBuilder.processExpenseFromSecurity(pPayee, myHolding, pTrans);
275 
276             /* If this is an expense from a portfolio */
277         } else if (pDebit instanceof MoneyWisePortfolio myPortfolio) {
278             /* process as expense from portfolio */
279             thePortBuilder.processExpenseFromPortfolio(pPayee, myPortfolio, pTrans);
280 
281             /* else if we have additional detail */
282         } else if (hasXtraDetail(pTrans)) {
283             /* process as detailed income */
284             processDetailedExpense(pPayee, pDebit, pTrans);
285 
286         } else {
287             /* process as standard expense */
288             processStandardExpense(pPayee, pDebit, pTrans);
289         }
290     }
291 
292     /**
293      * Process transfer event.
294      *
295      * @param pDebit  the debit account
296      * @param pCredit the credit account
297      * @param pTrans  the transaction
298      */
299     protected void processTransfer(final MoneyWiseTransAsset pDebit,
300                                    final MoneyWiseTransAsset pCredit,
301                                    final MoneyWiseTransaction pTrans) {
302         /* If this is a cash AutoExpense */
303         if (pCredit instanceof MoneyWiseCash myCash
304                 && myCash.isAutoExpense()) {
305             /* Process as standard expense */
306             processCashExpense(myCash, pDebit, pTrans);
307 
308             /* If this is a cash AutoReceipt */
309         } else if (pDebit instanceof MoneyWiseCash myCash
310                 && myCash.isAutoExpense()) {
311             /* Process as standard expense */
312             processCashReceipt(myCash, pCredit, pTrans);
313 
314             /* If this is a transfer from a security */
315         } else if (pDebit instanceof MoneyWiseSecurityHolding myDebitHolding) {
316             /* Handle transfer between securities */
317             if (pCredit instanceof MoneyWiseSecurityHolding myCreditHolding) {
318                 /* process as transfer between securities */
319                 thePortBuilder.processTransferBetweenSecurities(myDebitHolding, myCreditHolding, pTrans);
320             } else {
321                 /* process as transfer from security */
322                 thePortBuilder.processTransferFromSecurity(myDebitHolding, pCredit, pTrans);
323             }
324             /* If this is a transfer to a security */
325         } else if (pCredit instanceof MoneyWiseSecurityHolding myCreditHolding) {
326             /* process as transfer to security */
327             thePortBuilder.processTransferToSecurity(myCreditHolding, pDebit, pTrans);
328 
329             /* If this is a transfer from a portfolio */
330         } else if (pDebit instanceof MoneyWisePortfolio myDebitPortfolio) {
331             /* Handle transfer between securities */
332             if (pCredit instanceof MoneyWisePortfolio myCreditPortfolio) {
333                 /* process as transfer between portfolios */
334                 thePortBuilder.processTransferBetweenPortfolios(myDebitPortfolio, myCreditPortfolio, pTrans);
335             } else {
336                 /* process as transfer from portfolio */
337                 thePortBuilder.processTransferFromPortfolio(myDebitPortfolio, pCredit, pTrans);
338             }
339             /* If this is a transfer to a portfolio */
340         } else if (pCredit instanceof MoneyWisePortfolio myCreditPortfolio) {
341             /* process as transfer to portfolio */
342             thePortBuilder.processTransferToPortfolio(myCreditPortfolio, pDebit, pTrans);
343 
344         } else {
345             /* Access details */
346             final MoneyWiseTransCategoryClass myCat = Objects.requireNonNull(pTrans.getCategoryClass());
347 
348             /* Switch on category class */
349             switch (myCat) {
350                 case CASHBACK:
351                     /* Process as cashBack payment */
352                     processCashBack(pDebit, pCredit, pTrans);
353                     break;
354                 case INTEREST:
355                 case LOYALTYBONUS:
356                     /* Process as interest payment */
357                     processInterest(pDebit, pCredit, pTrans);
358                     break;
359                 case LOANINTERESTEARNED:
360                 case RENTALINCOME:
361                 case ROOMRENTALINCOME:
362                     /* Process as income from parent of the credit */
363                     processStandardIncome((MoneyWisePayee) pCredit.getParent(), pCredit, pTrans);
364                     break;
365                 case WRITEOFF:
366                 case LOANINTERESTCHARGED:
367                     /* Process as expense to parent of the credit (recursive) */
368                     processStandardExpense((MoneyWisePayee) pCredit.getParent(), pDebit, pTrans);
369                     break;
370                 default:
371                     /* Process as standard transfer */
372                     processStandardTransfer(pDebit, pCredit, pTrans);
373                     break;
374             }
375         }
376     }
377 
378     /**
379      * Does the transaction have extra detail.
380      *
381      * @param pTrans the transaction
382      * @return true/false
383      */
384     protected static boolean hasXtraDetail(final MoneyWiseTransaction pTrans) {
385         if (pTrans.getTaxCredit() != null) {
386             return true;
387         }
388         if (pTrans.getEmployeeNatIns() != null) {
389             return true;
390         }
391         if (pTrans.getDeemedBenefit() != null) {
392             return true;
393         }
394         return pTrans.getWithheld() != null;
395     }
396 
397     /**
398      * Process standard income.
399      *
400      * @param pPayee  the payee
401      * @param pCredit the credit account
402      * @param pTrans  the transaction
403      */
404     protected void processStandardIncome(final MoneyWisePayee pPayee,
405                                          final MoneyWiseTransAsset pCredit,
406                                          final MoneyWiseTransaction pTrans) {
407         /* Access the Payee details */
408         final MoneyWiseQIFPayee myPayee = theRegister.registerPayee(pPayee);
409 
410         /* Access the Category details */
411         final MoneyWiseQIFEventCategory myCategory = theRegister.registerCategory(pTrans.getCategory());
412 
413         /* Access the Account details */
414         final MoneyWiseQIFAccountEvents myAccount = theRegister.registerAccount(pCredit);
415 
416         /* Obtain classes */
417         final List<MoneyWiseQIFClass> myList = getTransactionClasses(pTrans);
418 
419         /* Create a new event */
420         final MoneyWiseQIFEvent myEvent = new MoneyWiseQIFEvent(theRegister, pTrans);
421         myEvent.recordAmount(pTrans.getAmount());
422         myEvent.recordPayee(myPayee);
423         myEvent.recordCategory(myCategory, myList);
424 
425         /* Add event to event list */
426         myAccount.addEvent(myEvent);
427     }
428 
429     /**
430      * Process detailed income.
431      *
432      * @param pPayee  the payee
433      * @param pCredit the credit account
434      * @param pTrans  the transaction
435      */
436     protected void processDetailedIncome(final MoneyWisePayee pPayee,
437                                          final MoneyWiseTransAsset pCredit,
438                                          final MoneyWiseTransaction pTrans) {
439         /* Access the Payee details */
440         final MoneyWiseQIFPayee myPayee = theRegister.registerPayee(pPayee);
441         final MoneyWiseQIFPayee myTaxPayee = theRegister.registerPayee(theTaxMan);
442 
443         /* Access the Category details */
444         final MoneyWiseQIFEventCategory myCategory = theRegister.registerCategory(pTrans.getCategory());
445 
446         /* Access the Account details */
447         final MoneyWiseQIFAccountEvents myAccount = theRegister.registerAccount(pCredit);
448 
449         /* Obtain classes */
450         final List<MoneyWiseQIFClass> myList = getTransactionClasses(pTrans);
451 
452         /* Obtain basic amount */
453         OceanusMoney myAmount = pTrans.getAmount();
454 
455         /* Create a new event */
456         final MoneyWiseQIFEvent myEvent = new MoneyWiseQIFEvent(theRegister, pTrans);
457         myEvent.recordPayee(myPayee);
458         myEvent.recordAmount(myAmount);
459 
460         /* Add Split event */
461         myAmount = new OceanusMoney(myAmount);
462         myEvent.recordSplitRecord(myCategory, myList, myAmount, myPayee.getName());
463 
464         /* Handle Tax Credit */
465         OceanusMoney myTaxCredit = pTrans.getTaxCredit();
466         if (myTaxCredit != null) {
467             /* Add to amount */
468             myAmount.addAmount(myTaxCredit);
469             myTaxCredit = new OceanusMoney(myTaxCredit);
470             myTaxCredit.negate();
471 
472             /* Access the Category details */
473             final MoneyWiseQIFEventCategory myTaxCategory = theRegister.registerCategory(theTaxCategory);
474 
475             /* Add Split event */
476             myEvent.recordSplitRecord(myTaxCategory, myTaxCredit, myTaxPayee.getName());
477         }
478 
479         /* Handle National Insurance */
480         OceanusMoney myNatIns = pTrans.getEmployeeNatIns();
481         if (myNatIns != null) {
482             /* Add to amount */
483             myAmount.addAmount(myNatIns);
484             myNatIns = new OceanusMoney(myNatIns);
485             myNatIns.negate();
486 
487             /* Access the Category details */
488             final MoneyWiseQIFEventCategory myInsCategory = theRegister.registerCategory(theNatInsCategory);
489 
490             /* Add Split event */
491             myEvent.recordSplitRecord(myInsCategory, myNatIns, myTaxPayee.getName());
492         }
493 
494         /* Handle Deemed Benefit */
495         OceanusMoney myBenefit = pTrans.getDeemedBenefit();
496         if (myBenefit != null) {
497             /* Access the Category details */
498             final MoneyWiseQIFEventCategory myBenCategory = theRegister.registerCategory(theBenefitCategory);
499 
500             /* Add Split event */
501             myEvent.recordSplitRecord(myBenCategory, myBenefit, myPayee.getName());
502 
503             /* Add to amount */
504             myBenefit = new OceanusMoney(myBenefit);
505             myBenefit.negate();
506 
507             /* Access the Category details */
508             final MoneyWiseQIFEventCategory myWithCategory = theRegister.registerCategory(theBenefitCategory);
509 
510             /* Add Split event */
511             myEvent.recordSplitRecord(myWithCategory, myBenefit, myPayee.getName());
512         }
513 
514         /* Handle Withheld */
515         OceanusMoney myWithheld = pTrans.getWithheld();
516         if (myWithheld != null) {
517             /* Add to amount */
518             myAmount.addAmount(myWithheld);
519             myWithheld = new OceanusMoney(myWithheld);
520             myWithheld.negate();
521 
522             /* Access the Category details */
523             final MoneyWiseQIFEventCategory myWithCategory = theRegister.registerCategory(theWithheldCategory);
524 
525             /* Add Split event */
526             myEvent.recordSplitRecord(myWithCategory, myWithheld, myPayee.getName());
527         }
528 
529         /* Add event to event list */
530         myAccount.addEvent(myEvent);
531     }
532 
533     /**
534      * Process standard expense.
535      *
536      * @param pPayee the payee
537      * @param pDebit the debit account
538      * @param pTrans the transaction
539      */
540     protected void processStandardExpense(final MoneyWisePayee pPayee,
541                                           final MoneyWiseTransAsset pDebit,
542                                           final MoneyWiseTransaction pTrans) {
543         /* Access the Payee details */
544         final MoneyWiseQIFPayee myPayee = theRegister.registerPayee(pPayee);
545 
546         /* Access the Category details */
547         final MoneyWiseQIFEventCategory myCategory = theRegister.registerCategory(pTrans.getCategory());
548 
549         /* Access the Account details */
550         final MoneyWiseQIFAccountEvents myAccount = theRegister.registerAccount(pDebit);
551 
552         /* Obtain classes */
553         final List<MoneyWiseQIFClass> myList = getTransactionClasses(pTrans);
554 
555         /* Access the amount */
556         final OceanusMoney myAmount = new OceanusMoney(pTrans.getAmount());
557         myAmount.negate();
558 
559         /* Create a new event */
560         final MoneyWiseQIFEvent myEvent = new MoneyWiseQIFEvent(theRegister, pTrans);
561         myEvent.recordAmount(myAmount);
562         myEvent.recordPayee(myPayee);
563         myEvent.recordCategory(myCategory, myList);
564 
565         /* Add event to event list */
566         myAccount.addEvent(myEvent);
567     }
568 
569     /**
570      * Process detailed expense.
571      *
572      * @param pPayee the payee
573      * @param pDebit the debit account
574      * @param pTrans the expense
575      */
576     protected void processDetailedExpense(final MoneyWisePayee pPayee,
577                                           final MoneyWiseTransAsset pDebit,
578                                           final MoneyWiseTransaction pTrans) {
579         /* Access the Payee details */
580         final MoneyWiseQIFPayee myPayee = theRegister.registerPayee(pPayee);
581         final MoneyWiseQIFPayee myTaxPayee = theRegister.registerPayee(theTaxMan);
582 
583         /* Access the Category details */
584         final MoneyWiseQIFEventCategory myCategory = theRegister.registerCategory(pTrans.getCategory());
585 
586         /* Access the Account details */
587         final MoneyWiseQIFAccountEvents myAccount = theRegister.registerAccount(pDebit);
588 
589         /* Obtain classes */
590         final List<MoneyWiseQIFClass> myList = getTransactionClasses(pTrans);
591 
592         /* Obtain basic amount */
593         OceanusMoney myAmount = new OceanusMoney(pTrans.getAmount());
594         myAmount.negate();
595 
596         /* Create a new event */
597         final MoneyWiseQIFEvent myEvent = new MoneyWiseQIFEvent(theRegister, pTrans);
598         myEvent.recordPayee(myPayee);
599         myEvent.recordAmount(myAmount);
600 
601         /* Add Split event */
602         myAmount = new OceanusMoney(myAmount);
603         myEvent.recordSplitRecord(myCategory, myList, myAmount, myPayee.getName());
604 
605         /* Handle Tax Credit */
606         final OceanusMoney myTaxCredit = pTrans.getTaxCredit();
607         if (myTaxCredit != null) {
608             /* Subtract from amount */
609             myAmount.subtractAmount(myTaxCredit);
610 
611             /* Access the Category details */
612             final MoneyWiseQIFEventCategory myTaxCategory = theRegister.registerCategory(theTaxCategory);
613 
614             /* Add Split event */
615             myEvent.recordSplitRecord(myTaxCategory, myTaxCredit, myTaxPayee.getName());
616         }
617 
618         /* Handle National Insurance */
619         final OceanusMoney myNatIns = pTrans.getEmployeeNatIns();
620         if (myNatIns != null) {
621             /* Subtract from amount */
622             myAmount.subtractAmount(myNatIns);
623 
624             /* Access the Category details */
625             final MoneyWiseQIFEventCategory myInsCategory = theRegister.registerCategory(theNatInsCategory);
626 
627             /* Add Split event */
628             myEvent.recordSplitRecord(myInsCategory, myNatIns, myTaxPayee.getName());
629         }
630 
631         /* Handle Deemed Benefit */
632         final OceanusMoney myBenefit = pTrans.getDeemedBenefit();
633         if (myBenefit != null) {
634             /* Subtract from amount */
635             myAmount.subtractAmount(myBenefit);
636 
637             /* Access the Category details */
638             final MoneyWiseQIFEventCategory myBenCategory = theRegister.registerCategory(theBenefitCategory);
639 
640             /* Add Split event */
641             myEvent.recordSplitRecord(myBenCategory, myBenefit, myPayee.getName());
642         }
643 
644         /* Add event to event list */
645         myAccount.addEvent(myEvent);
646     }
647 
648     /**
649      * Process standard transfer.
650      *
651      * @param pDebit  the debit account
652      * @param pCredit the credit account
653      * @param pTrans  the transaction
654      */
655     protected void processStandardTransfer(final MoneyWiseTransAsset pDebit,
656                                            final MoneyWiseTransAsset pCredit,
657                                            final MoneyWiseTransaction pTrans) {
658         /* Access details */
659         final OceanusMoney myAmount = pTrans.getAmount();
660 
661         /* Access the Account details */
662         final MoneyWiseQIFAccountEvents myDebitAccount = theRegister.registerAccount(pDebit);
663         final MoneyWiseQIFAccountEvents myCreditAccount = theRegister.registerAccount(pCredit);
664 
665         /* Obtain classes */
666         final List<MoneyWiseQIFClass> myList = getTransactionClasses(pTrans);
667 
668         /* Create a new event */
669         MoneyWiseQIFEvent myEvent = new MoneyWiseQIFEvent(theRegister, pTrans);
670         myEvent.recordAmount(myAmount);
671         myEvent.recordAccount(myDebitAccount.getAccount(), myList);
672 
673         /* Build payee description */
674         myEvent.recordPayee(buildXferFromPayee(pDebit));
675 
676         /* Add event to event list */
677         myCreditAccount.addEvent(myEvent);
678 
679         /* Build out amount */
680         final OceanusMoney myOutAmount = new OceanusMoney(myAmount);
681         myOutAmount.negate();
682 
683         /* Create a new event */
684         myEvent = new MoneyWiseQIFEvent(theRegister, pTrans);
685         myEvent.recordAmount(myOutAmount);
686         myEvent.recordAccount(myCreditAccount.getAccount(), myList);
687 
688         /* Build payee description */
689         myEvent.recordPayee(buildXferToPayee(pCredit));
690 
691         /* Add event to event list */
692         myDebitAccount.addEvent(myEvent);
693     }
694 
695     @Override
696     public String buildXferFromPayee(final MoneyWiseTransAsset pPartner) {
697         /* Determine mode */
698         final boolean useSimpleTransfer = theFileType.useSimpleTransfer();
699 
700         /* Build payee description */
701         final StringBuilder myBuilder = new StringBuilder();
702         myBuilder.append(QIF_XFER);
703         if (!useSimpleTransfer) {
704             myBuilder.append(QIF_XFERFROM);
705             myBuilder.append(pPartner.getName());
706         }
707 
708         /* Return the payee */
709         return myBuilder.toString();
710     }
711 
712     @Override
713     public String buildXferToPayee(final MoneyWiseTransAsset pPartner) {
714         /* Determine mode */
715         final boolean useSimpleTransfer = theFileType.useSimpleTransfer();
716 
717         /* Build payee description */
718         final StringBuilder myBuilder = new StringBuilder();
719         myBuilder.append(QIF_XFER);
720         if (!useSimpleTransfer) {
721             myBuilder.append(QIF_XFERTO);
722             myBuilder.append(pPartner.getName());
723         }
724 
725         /* Return the payee */
726         return myBuilder.toString();
727     }
728 
729     /**
730      * Process interest.
731      *
732      * @param pDebit  the debit account
733      * @param pCredit the credit account
734      * @param pTrans  the transaction
735      */
736     protected void processInterest(final MoneyWiseTransAsset pDebit,
737                                    final MoneyWiseTransAsset pCredit,
738                                    final MoneyWiseTransaction pTrans) {
739         /* Access details */
740         OceanusMoney myAmount = pTrans.getAmount();
741 
742         /* Determine mode */
743         final boolean isRecursive = pDebit.equals(pCredit);
744         final boolean hideBalancingTransfer = theFileType.hideBalancingSplitTransfer();
745         final boolean hasXtraDetail = hasXtraDetail(pTrans);
746 
747         /* Access the Account details */
748         final MoneyWiseQIFAccountEvents myIntAccount = theRegister.registerAccount(pDebit);
749 
750         /* Access the payee */
751         final MoneyWiseQIFPayee myPayee = theRegister.registerPayee((MoneyWisePayee) pDebit.getParent());
752 
753         /* Access the category */
754         final MoneyWiseQIFEventCategory myCategory = theRegister.registerCategory(pTrans.getCategory());
755 
756         /* Obtain classes */
757         final List<MoneyWiseQIFClass> myList = getTransactionClasses(pTrans);
758 
759         /* If this is a simple interest */
760         if (isRecursive && !hasXtraDetail) {
761             /* Create a new event */
762             final MoneyWiseQIFEvent myEvent = new MoneyWiseQIFEvent(theRegister, pTrans);
763 
764             /* Build simple event and add it */
765             myEvent.recordAmount(myAmount);
766             myEvent.recordPayee(myPayee);
767             myEvent.recordCategory(myCategory, myList);
768 
769             /* Add event to event list */
770             myIntAccount.addEvent(myEvent);
771 
772             /* Else we need splits */
773         } else {
774             /* Create a new event */
775             final MoneyWiseQIFEvent myEvent = new MoneyWiseQIFEvent(theRegister, pTrans);
776 
777             /* Record basic details */
778             myEvent.recordAmount(isRecursive
779                     ? myAmount
780                     : new OceanusMoney());
781             myEvent.recordPayee(myPayee);
782 
783             /* Add Split event */
784             myAmount = new OceanusMoney(myAmount);
785             myEvent.recordSplitRecord(myCategory, myList, myAmount, myPayee.getName());
786 
787             /* Handle Tax Credit */
788             OceanusMoney myTaxCredit = pTrans.getTaxCredit();
789             if (myTaxCredit != null) {
790                 /* Access tax payee */
791                 final MoneyWiseQIFPayee myTaxPayee = theRegister.registerPayee(theTaxMan);
792 
793                 /* Add to amount */
794                 myAmount.addAmount(myTaxCredit);
795                 myTaxCredit = new OceanusMoney(myTaxCredit);
796                 myTaxCredit.negate();
797 
798                 /* Access the Category details */
799                 final MoneyWiseQIFEventCategory myTaxCategory = theRegister.registerCategory(theTaxCategory);
800 
801                 /* Add Split event */
802                 myEvent.recordSplitRecord(myTaxCategory, myTaxCredit, myTaxPayee.getName());
803             }
804 
805             /* Handle Withheld */
806             OceanusMoney myWithheld = pTrans.getWithheld();
807             if (myWithheld != null) {
808                 /* Add to amount */
809                 myAmount.addAmount(myWithheld);
810                 myWithheld = new OceanusMoney(myWithheld);
811                 myWithheld.negate();
812 
813                 /* Access the Category details */
814                 final MoneyWiseQIFEventCategory myWithCategory = theRegister.registerCategory(theWithheldCategory);
815 
816                 /* Add Split event */
817                 myEvent.recordSplitRecord(myWithCategory, myWithheld, myPayee.getName());
818             }
819 
820             /* Handle Non-Recursion */
821             if (!isRecursive) {
822                 /* Add to amount */
823                 final OceanusMoney myOutAmount = new OceanusMoney(pTrans.getAmount());
824                 myOutAmount.negate();
825 
826                 /* Access the Account details */
827                 final MoneyWiseQIFAccountEvents myAccount = theRegister.registerAccount(pCredit);
828 
829                 /* Add Split event */
830                 myEvent.recordSplitRecord(myAccount.getAccount(), myOutAmount, null);
831             }
832 
833             /* Add event to event list */
834             myIntAccount.addEvent(myEvent);
835         }
836 
837         /* If we need a balancing transfer */
838         if (!isRecursive && !hideBalancingTransfer) {
839             /* Access the Account details */
840             final MoneyWiseQIFAccountEvents myAccount = theRegister.registerAccount(pCredit);
841 
842             /* Create a new event */
843             final MoneyWiseQIFEvent myEvent = new MoneyWiseQIFEvent(theRegister, pTrans);
844 
845             /* Build simple event and add it */
846             myEvent.recordAmount(pTrans.getAmount());
847             myEvent.recordAccount(myIntAccount.getAccount(), myList);
848 
849             /* Build payee description */
850             myEvent.recordPayee(buildXferFromPayee(pDebit));
851 
852             /* Add event to event list */
853             myAccount.addEvent(myEvent);
854         }
855     }
856 
857     /**
858      * Process cashBack.
859      *
860      * @param pDebit  the debit account
861      * @param pCredit the credit account
862      * @param pTrans  the transaction
863      */
864     protected void processCashBack(final MoneyWiseTransAsset pDebit,
865                                    final MoneyWiseTransAsset pCredit,
866                                    final MoneyWiseTransaction pTrans) {
867         /* Access details */
868         OceanusMoney myAmount = pTrans.getAmount();
869 
870         /* Determine mode */
871         final boolean isRecursive = pDebit.equals(pCredit);
872         final boolean hideBalancingTransfer = theFileType.hideBalancingSplitTransfer();
873 
874         /* Access the Account details */
875         final MoneyWiseQIFAccountEvents myBaseAccount = theRegister.registerAccount(pDebit);
876 
877         /* Access the payee */
878         final MoneyWiseQIFPayee myPayee = theRegister.registerPayee((MoneyWisePayee) pDebit.getParent());
879 
880         /* Access the category */
881         final MoneyWiseQIFEventCategory myCategory = theRegister.registerCategory(pTrans.getCategory());
882 
883         /* Obtain classes */
884         final List<MoneyWiseQIFClass> myList = getTransactionClasses(pTrans);
885 
886         /* If this is a simple cashBack */
887         if (isRecursive) {
888             /* Create a new event */
889             final MoneyWiseQIFEvent myEvent = new MoneyWiseQIFEvent(theRegister, pTrans);
890 
891             /* Build simple event and add it */
892             myEvent.recordAmount(myAmount);
893             myEvent.recordPayee(myPayee);
894             myEvent.recordCategory(myCategory, myList);
895 
896             /* Add event to event list */
897             myBaseAccount.addEvent(myEvent);
898 
899             /* Else we need splits */
900         } else {
901             /* Create a new event */
902             final MoneyWiseQIFEvent myEvent = new MoneyWiseQIFEvent(theRegister, pTrans);
903 
904             /* Record basic details */
905             myEvent.recordAmount(new OceanusMoney());
906             myEvent.recordPayee(myPayee);
907 
908             /* Add Split event */
909             myAmount = new OceanusMoney(myAmount);
910             myEvent.recordSplitRecord(myCategory, myList, myAmount, myPayee.getName());
911 
912             /* Add to amount */
913             final OceanusMoney myOutAmount = new OceanusMoney(pTrans.getAmount());
914             myOutAmount.negate();
915 
916             /* Access the Account details */
917             final MoneyWiseQIFAccountEvents myAccount = theRegister.registerAccount(pCredit);
918 
919             /* Add Split event */
920             myEvent.recordSplitRecord(myAccount.getAccount(), myOutAmount, null);
921 
922             /* Add event to event list */
923             myBaseAccount.addEvent(myEvent);
924         }
925 
926         /* If we need a balancing transfer */
927         if (!isRecursive && !hideBalancingTransfer) {
928             /* Access the Account details */
929             final MoneyWiseQIFAccountEvents myAccount = theRegister.registerAccount(pCredit);
930 
931             /* Create a new event */
932             final MoneyWiseQIFEvent myEvent = new MoneyWiseQIFEvent(theRegister, pTrans);
933 
934             /* Build simple event and add it */
935             myEvent.recordAmount(pTrans.getAmount());
936             myEvent.recordAccount(myBaseAccount.getAccount(), myList);
937 
938             /* Build payee description */
939             myEvent.recordPayee(buildXferFromPayee(pDebit));
940 
941             /* Add event to event list */
942             myAccount.addEvent(myEvent);
943         }
944     }
945 
946     /**
947      * Process cash recovery.
948      *
949      * @param pPayee the payee
950      * @param pCash  the cash account
951      * @param pTrans the transaction
952      */
953     protected void processCashRecovery(final MoneyWisePayee pPayee,
954                                        final MoneyWiseCash pCash,
955                                        final MoneyWiseTransaction pTrans) {
956         /* Access the Payee details */
957         final MoneyWiseQIFPayee myPayee = theRegister.registerPayee(pPayee);
958 
959         /* Access the Category details */
960         final MoneyWiseQIFEventCategory myCategory = theRegister.registerCategory(pTrans.getCategory());
961         final MoneyWiseQIFEventCategory myAutoCategory = theRegister.registerCategory(pCash.getAutoExpense());
962 
963         /* Access the Account details */
964         final MoneyWiseQIFAccountEvents myAccount = theRegister.registerAccount(pCash);
965 
966         /* Obtain classes */
967         final List<MoneyWiseQIFClass> myList = getTransactionClasses(pTrans);
968 
969         /* Access the amount */
970         final OceanusMoney myInAmount = pTrans.getAmount();
971         final OceanusMoney myOutAmount = new OceanusMoney(myInAmount);
972         myOutAmount.negate();
973 
974         /* Create a new event */
975         final MoneyWiseQIFEvent myEvent = new MoneyWiseQIFEvent(theRegister, pTrans);
976         myEvent.recordAmount(new OceanusMoney());
977         myEvent.recordPayee(myPayee);
978         myEvent.recordSplitRecord(myCategory, myList, myInAmount, myPayee.getName());
979         myEvent.recordSplitRecord(myAutoCategory, myList, myOutAmount, pCash.getAutoPayee().getName());
980 
981         /* Add event to event list */
982         myAccount.addEvent(myEvent);
983     }
984 
985     /**
986      * Process cash payment.
987      *
988      * @param pPayee the payee
989      * @param pCash  the cash account
990      * @param pTrans the transaction
991      */
992     protected void processCashPayment(final MoneyWisePayee pPayee,
993                                       final MoneyWiseCash pCash,
994                                       final MoneyWiseTransaction pTrans) {
995         /* Access the Payee details */
996         final MoneyWiseQIFPayee myPayee = theRegister.registerPayee(pPayee);
997 
998         /* Access the Category details */
999         final MoneyWiseQIFEventCategory myCategory = theRegister.registerCategory(pTrans.getCategory());
1000         final MoneyWiseQIFEventCategory myAutoCategory = theRegister.registerCategory(pCash.getAutoExpense());
1001 
1002         /* Access the Account details */
1003         final MoneyWiseQIFAccountEvents myAccount = theRegister.registerAccount(pCash);
1004 
1005         /* Obtain classes */
1006         final List<MoneyWiseQIFClass> myList = getTransactionClasses(pTrans);
1007 
1008         /* Access the amount */
1009         final OceanusMoney myInAmount = pTrans.getAmount();
1010         final OceanusMoney myOutAmount = new OceanusMoney(myInAmount);
1011         myOutAmount.negate();
1012 
1013         /* Create a new event */
1014         final MoneyWiseQIFEvent myEvent = new MoneyWiseQIFEvent(theRegister, pTrans);
1015         myEvent.recordAmount(new OceanusMoney());
1016         myEvent.recordPayee(myPayee);
1017         myEvent.recordSplitRecord(myAutoCategory, myList, myInAmount, pCash.getAutoPayee().getName());
1018         myEvent.recordSplitRecord(myCategory, myList, myOutAmount, myPayee.getName());
1019 
1020         /* Add event to event list */
1021         myAccount.addEvent(myEvent);
1022     }
1023 
1024     /**
1025      * Process cash expense.
1026      *
1027      * @param pCash  the cash account
1028      * @param pDebit the debit account
1029      * @param pTrans the transaction
1030      */
1031     protected void processCashExpense(final MoneyWiseCash pCash,
1032                                       final MoneyWiseTransAsset pDebit,
1033                                       final MoneyWiseTransaction pTrans) {
1034         /* Access the Payee details */
1035         final MoneyWiseQIFPayee myPayee = theRegister.registerPayee(pCash.getAutoPayee());
1036 
1037         /* Access the Category details */
1038         final MoneyWiseQIFEventCategory myCategory = theRegister.registerCategory(pCash.getAutoExpense());
1039 
1040         /* Obtain classes */
1041         final List<MoneyWiseQIFClass> myList = getTransactionClasses(pTrans);
1042 
1043         /* Access the Account details */
1044         final MoneyWiseQIFAccountEvents myAccount = theRegister.registerAccount(pDebit);
1045 
1046         /* Access the amount */
1047         final OceanusMoney myAmount = new OceanusMoney(pTrans.getAmount());
1048         myAmount.negate();
1049 
1050         /* Create a new event */
1051         final MoneyWiseQIFEvent myEvent = new MoneyWiseQIFEvent(theRegister, pTrans);
1052         myEvent.recordAmount(myAmount);
1053         myEvent.recordPayee(myPayee);
1054         myEvent.recordCategory(myCategory, myList);
1055 
1056         /* Add event to event list */
1057         myAccount.addEvent(myEvent);
1058     }
1059 
1060     /**
1061      * Process cash receipt.
1062      *
1063      * @param pCash   the cash account
1064      * @param pCredit the credit account
1065      * @param pTrans  the transaction
1066      */
1067     protected void processCashReceipt(final MoneyWiseCash pCash,
1068                                       final MoneyWiseTransAsset pCredit,
1069                                       final MoneyWiseTransaction pTrans) {
1070         /* Access the Payee details */
1071         final MoneyWiseQIFPayee myPayee = theRegister.registerPayee(pCash.getAutoPayee());
1072 
1073         /* Access the Category details */
1074         final MoneyWiseQIFEventCategory myCategory = theRegister.registerCategory(pCash.getAutoExpense());
1075 
1076         /* Access the Account details */
1077         final MoneyWiseQIFAccountEvents myAccount = theRegister.registerAccount(pCredit);
1078 
1079         /* Obtain classes */
1080         final List<MoneyWiseQIFClass> myList = getTransactionClasses(pTrans);
1081 
1082         /* Create a new event */
1083         final MoneyWiseQIFEvent myEvent = new MoneyWiseQIFEvent(theRegister, pTrans);
1084         myEvent.recordAmount(pTrans.getAmount());
1085         myEvent.recordPayee(myPayee);
1086         myEvent.recordCategory(myCategory, myList);
1087 
1088         /* Add event to event list */
1089         myAccount.addEvent(myEvent);
1090     }
1091 
1092     @Override
1093     public List<MoneyWiseQIFClass> getTransactionClasses(final MoneyWiseTransaction pTrans) {
1094         /* Create return value */
1095         List<MoneyWiseQIFClass> myList = null;
1096 
1097         /* Obtain the tags for the transaction */
1098         final List<MoneyWiseTransTag> myTags = pTrans.getTransactionTags();
1099 
1100         /* If we have tags */
1101         if (myTags != null) {
1102             /* Allocate the list */
1103             myList = new ArrayList<>();
1104 
1105             /* Loop through the tags */
1106             final Iterator<MoneyWiseTransTag> myIterator = myTags.iterator();
1107             while (myIterator.hasNext()) {
1108                 final MoneyWiseTransTag myTag = myIterator.next();
1109 
1110                 /* Access the transaction tag */
1111                 final MoneyWiseQIFClass myClass = theRegister.registerClass(myTag);
1112 
1113                 /* Add to the list */
1114                 myList.add(myClass);
1115             }
1116         }
1117 
1118         /* Return the list */
1119         return myList;
1120     }
1121 }