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