View Javadoc
1   /*
2    * Copyright 2005-2006 The Kuali Foundation
3    * 
4    * Licensed under the Educational Community License, Version 2.0 (the "License");
5    * you may not use this file except in compliance with the License.
6    * You may obtain a copy of the License at
7    * 
8    * http://www.opensource.org/licenses/ecl2.php
9    * 
10   * Unless required by applicable law or agreed to in writing, software
11   * distributed under the License is distributed on an "AS IS" BASIS,
12   * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13   * See the License for the specific language governing permissions and
14   * limitations under the License.
15   */
16  package org.kuali.ole.fp.document;
17  
18  import java.util.ArrayList;
19  import java.util.Collection;
20  import java.util.HashMap;
21  import java.util.Iterator;
22  import java.util.List;
23  import java.util.Map;
24  
25  import org.kuali.ole.fp.businessobject.Check;
26  import org.kuali.ole.fp.businessobject.CheckBase;
27  import org.kuali.ole.fp.businessobject.CoinDetail;
28  import org.kuali.ole.fp.businessobject.CurrencyDetail;
29  import org.kuali.ole.fp.businessobject.DepositCashReceiptControl;
30  import org.kuali.ole.fp.document.service.CashReceiptService;
31  import org.kuali.ole.fp.document.validation.event.AddCheckEvent;
32  import org.kuali.ole.fp.document.validation.event.DeleteCheckEvent;
33  import org.kuali.ole.fp.document.validation.event.UpdateCheckEvent;
34  import org.kuali.ole.fp.service.CheckService;
35  import org.kuali.ole.sys.OLEConstants;
36  import org.kuali.ole.sys.OLEConstants.DocumentStatusCodes.CashReceipt;
37  import org.kuali.ole.sys.businessobject.ChartOrgHolder;
38  import org.kuali.ole.sys.businessobject.SufficientFundsItem;
39  import org.kuali.ole.sys.context.SpringContext;
40  import org.kuali.ole.sys.document.AmountTotaling;
41  import org.kuali.rice.core.api.datetime.DateTimeService;
42  import org.kuali.rice.core.api.util.type.KualiDecimal;
43  import org.kuali.rice.core.web.format.CurrencyFormatter;
44  import org.kuali.rice.kew.api.WorkflowDocument;
45  import org.kuali.rice.kew.api.exception.WorkflowException;
46  import org.kuali.rice.kew.framework.postprocessor.DocumentRouteStatusChange;
47  import org.kuali.rice.kim.api.identity.Person;
48  import org.kuali.rice.kns.service.DataDictionaryService;
49  import org.kuali.rice.krad.document.Copyable;
50  import org.kuali.rice.krad.rules.rule.event.KualiDocumentEvent;
51  import org.kuali.rice.krad.rules.rule.event.SaveDocumentEvent;
52  import org.kuali.rice.krad.service.BusinessObjectService;
53  import org.kuali.rice.krad.util.GlobalVariables;
54  import org.kuali.rice.krad.util.ObjectUtils;
55  
56  /**
57   * This is the business object that represents the CashReceiptDocument in Kuali. This is a transactional document that will
58   * eventually post transactions to the G/L. It integrates with workflow. Since a Cash Receipt is a one sided transactional document,
59   * only accepting funds into the university, the accounting line data will be held in the source accounting line data structure
60   * only.
61   */
62  public class CashReceiptDocument extends CashReceiptFamilyBase implements Copyable, AmountTotaling, CapitalAssetEditable {
63      private static final org.apache.log4j.Logger LOG = org.apache.log4j.Logger.getLogger(CashReceiptDocument.class);
64  
65      public static final String CHECK_ENTRY_DETAIL = "individual";
66      public static final String CHECK_ENTRY_TOTAL = "totals";
67  
68      public static final String DOCUMENT_TYPE = "OLE_CR";
69  
70      // child object containers - for all the different reconciliation detail sections
71      protected String checkEntryMode = CHECK_ENTRY_DETAIL;
72      protected List<Check> checks = new ArrayList<Check>();
73      protected List<Check> confirmedChecks = new ArrayList<Check>();
74      
75      // deposit controls
76      protected List<DepositCashReceiptControl> depositCashReceiptControl = new ArrayList<DepositCashReceiptControl>();
77  
78      // incrementers for detail lines
79      protected Integer nextCheckSequenceId = new Integer(1);
80      protected Integer nextConfirmedCheckSequenceId = new Integer(1);
81  
82      // monetary attributes
83      protected KualiDecimal totalCashAmount = KualiDecimal.ZERO;
84      protected KualiDecimal totalCheckAmount = KualiDecimal.ZERO;
85      protected KualiDecimal totalCoinAmount = KualiDecimal.ZERO;
86      protected KualiDecimal sumTotalAmount = KualiDecimal.ZERO;
87      
88      protected KualiDecimal totalConfirmedCashAmount = KualiDecimal.ZERO;
89      protected KualiDecimal totalConfirmedCheckAmount = KualiDecimal.ZERO;
90      protected KualiDecimal totalConfirmedCoinAmount = KualiDecimal.ZERO;
91      
92      protected KualiDecimal totalChangeAmount = KualiDecimal.ZERO;
93  
94      protected CurrencyDetail currencyDetail;
95      protected CoinDetail coinDetail;
96      
97      protected CurrencyDetail confirmedCurrencyDetail;
98      protected CoinDetail confirmedCoinDetail;
99      
100     protected CurrencyDetail changeCurrencyDetail;
101     protected CoinDetail changeCoinDetail;
102     
103     protected boolean recategorized;
104 
105     protected String createDate;
106     
107     /**
108      * Initializes the array lists and line incrementers.
109      */
110     public CashReceiptDocument() {
111         super();
112 
113         initializeCampusLocationCode();
114         
115         currencyDetail = new CurrencyDetail();
116         coinDetail = new CoinDetail();
117         
118         confirmedCurrencyDetail = new CurrencyDetail();
119         confirmedCoinDetail = new CoinDetail();
120         
121         changeCurrencyDetail = new CurrencyDetail();
122         changeCoinDetail = new CoinDetail();
123     }
124 
125     /**
126      * Gets the totalCashAmount attribute.
127      * 
128      * @return Returns the totalCashAmount.
129      */
130     public KualiDecimal getTotalCashAmount() {
131         return (currencyDetail != null) ? currencyDetail.getTotalAmount() : KualiDecimal.ZERO;
132     }
133     
134     /**
135      * Gets the totalConfirmedCashAmount attribute.
136      * 
137      * @return Returns the totalConfirmedCashAmount.
138      */
139     public KualiDecimal getTotalConfirmedCashAmount() {
140         return (confirmedCurrencyDetail != null) ? confirmedCurrencyDetail.getTotalAmount() : KualiDecimal.ZERO;
141     }
142     
143     /**
144      * Gets the totalChangeCashAmount attribute.
145      * 
146      * @return Returns the totalChangeCashAmount.
147      */
148     public KualiDecimal getTotalChangeCashAmount() {
149         return (changeCurrencyDetail != null) ? changeCurrencyDetail.getTotalAmount() : KualiDecimal.ZERO;
150     }
151     
152     /**
153      * Gets the total amount of depositable checks
154      * @return
155      */
156     public KualiDecimal getTotalDepositableCheckAmount() {
157         KualiDecimal totalDepositableCheckAmount = KualiDecimal.ZERO;
158         List<Check> checks = getConfirmedChecks();
159         if (checks != null && !checks.isEmpty()) {
160             for (Check check : checks) {
161                 if(check.getCashieringStatus().equals("C")) {
162                     totalDepositableCheckAmount = totalDepositableCheckAmount.add(check.getAmount());
163                 }
164             }
165         }
166         return totalDepositableCheckAmount;        
167     }
168     
169     /**
170      * Checks if there are checks to be deposited
171      * @return
172      */
173     public boolean existDepositableChecks() {        
174         return getTotalDepositableCheckAmount().isGreaterThan(KualiDecimal.ZERO) ? true : false;        
175     }
176 
177     /**
178      * This method returns the total depositable check amount as a currency formatted string.
179      * 
180      * @return
181      */
182     public String getCurrencyFormattedTotalDepositableCheckAmount() {
183         return (String) new CurrencyFormatter().format(getTotalDepositableCheckAmount());
184     }
185 
186     /**
187      * This method returns the cash total amount as a currency formatted string.
188      * 
189      * @return String
190      */
191     public String getCurrencyFormattedTotalCashAmount() {
192         return (String) new CurrencyFormatter().format(getTotalCashAmount());
193     }
194     
195     
196     public String getCurrencyFormattedTotalConfirmedCashAmount() {
197         return (String) new CurrencyFormatter().format(getTotalConfirmedCashAmount());
198     }
199     
200     /**
201      * Sets the totalCashAmount attribute value.
202      * 
203      * @param cashAmount The totalCashAmount to set.
204      */
205     public void setTotalCashAmount(KualiDecimal cashAmount) {
206         this.totalCashAmount = cashAmount;
207     }
208     
209     /**
210      * Sets the totalConfirmedCashAmount attribute value.
211      * 
212      * @param cashAmount The totalConfirmedCashAmount to set.
213      */
214     public void setTotalConfirmedCashAmount(KualiDecimal confirmedCashAmount) {
215         this.totalConfirmedCashAmount = confirmedCashAmount;
216     }
217 
218 
219     /**
220      * @param checkEntryMode
221      */
222     public void setCheckEntryMode(String checkEntryMode) {
223         this.checkEntryMode = checkEntryMode;
224     }
225 
226     /**
227      * @return checkEntryMode
228      */
229     public String getCheckEntryMode() {
230         return checkEntryMode;
231     }
232 
233 
234     /**
235      * Gets the checks attribute.
236      * 
237      * @return Returns the checks.
238      */
239     public List<Check> getChecks() {
240         return checks;
241     }
242 
243     /**
244      * Sets the checks attribute value.
245      * 
246      * @param checks The checks to set.
247      */
248     public void setChecks(List<Check> checks) {
249         this.checks = checks;
250     }
251     
252     /**
253      * Gets the confirmed checks attribute.
254      * 
255      * @return Returns the confirmed checks.
256      */
257     public List<Check> getConfirmedChecks() {
258         return confirmedChecks;
259     }
260 
261     /**
262      * Sets the confirmed checks attribute value.
263      * 
264      * @param confirmedChecks The checks to set.
265      */
266     public void setConfirmedChecks(List<Check> confirmedChecks) {
267         this.confirmedChecks = confirmedChecks;
268     }
269 
270     /**
271      * Gets the number of checks, since Sun doesn't have a direct getter for collection size
272      * 
273      * @return the number of checks
274      */
275     public int getCheckCount() {
276         int count = 0;
277         if (ObjectUtils.isNotNull(checks)) {
278             count = checks.size();
279         }
280         return count;
281     }
282     
283     /**
284      * Gets the number of confirmed checks
285      * 
286      * @return the number of checks
287      */
288     public int getConfirmedCheckCount() {
289         int count = 0;
290         if (ObjectUtils.isNotNull(confirmedChecks)) {
291             count = confirmedChecks.size();
292         }
293         return count;
294     }
295 
296 
297     /**
298      * Adds a new check to the list.
299      * 
300      * @param check
301      */
302     public void addCheck(Check check) {
303         check.setSequenceId(this.nextCheckSequenceId);
304 
305         this.checks.add(check);
306 
307         this.nextCheckSequenceId = new Integer(this.nextCheckSequenceId.intValue() + 1);
308 
309         setTotalCheckAmount(getTotalCheckAmount().add(check.getAmount()));
310     }
311     
312     /**
313      * Adds a new confirmed check to the list.
314      * 
315      * @param check
316      */
317     public void addConfirmedCheck(Check check) {
318         check.setSequenceId(this.nextConfirmedCheckSequenceId);
319 
320         this.confirmedChecks.add(check);
321 
322         this.nextConfirmedCheckSequenceId = new Integer(this.nextConfirmedCheckSequenceId.intValue() + 1);
323 
324         setTotalConfirmedCheckAmount(getTotalConfirmedCheckAmount().add(check.getAmount()));
325     }
326 
327     /**
328      * Retrieve a particular check at a given index in the list of checks.
329      * 
330      * @param index
331      * @return Check
332      */
333     public Check getCheck(int index) {
334         while (this.checks.size() <= index) {
335             checks.add(createNewCheck());
336         }
337         return (Check) checks.get(index);
338     }
339     
340     /**
341      * Retrieve a particular check at a given index in the list of confirmed checks.
342      * 
343      * @param index
344      * @return Check
345      */
346     public Check getConfirmedCheck(int index) {
347         while (this.confirmedChecks.size() <= index) {
348             confirmedChecks.add(createNewConfirmedCheck());
349         }
350         return (Check) confirmedChecks.get(index);
351     }
352 
353 
354     /**
355      * @see org.kuali.ole.sys.document.AccountingDocumentBase#checkSufficientFunds()
356      */
357     @Override
358     public List<SufficientFundsItem> checkSufficientFunds() {
359         LOG.debug("checkSufficientFunds() started");
360 
361         // This document does not do sufficient funds checking
362         return new ArrayList<SufficientFundsItem>();
363     }
364 
365     
366     /**
367      * This method removes a check from the list and updates the total appropriately.
368      * 
369      * @param index
370      */
371     public void removeCheck(int index) {
372         Check check = (Check) checks.remove(index);
373         KualiDecimal newTotalCheckAmount = getTotalCheckAmount().subtract(check.getAmount());
374         // if the totalCheckAmount goes negative, bring back to zero.
375         if (newTotalCheckAmount.isNegative()) {
376             newTotalCheckAmount = KualiDecimal.ZERO;
377         }
378         setTotalCheckAmount(newTotalCheckAmount);
379     }
380     
381     /**
382      * This method removes a confirmed check from the list and updates the total appropriately.
383      * 
384      * @param index
385      */
386     public void removeConfirmedCheck(int index) {
387         Check check = (Check) confirmedChecks.remove(index);
388         KualiDecimal newTotalCheckAmount = getTotalConfirmedCheckAmount().subtract(check.getAmount());
389         // if the totalCheckAmount goes negative, bring back to zero.
390         if (newTotalCheckAmount.isNegative()) {
391             newTotalCheckAmount = KualiDecimal.ZERO;
392         }
393         setTotalConfirmedCheckAmount(newTotalCheckAmount);
394     }
395 
396     /**
397      * Gets the nextCheckSequenceId attribute.
398      * 
399      * @return Returns the nextCheckSequenceId.
400      */
401     public Integer getNextCheckSequenceId() {
402         return nextCheckSequenceId;
403     }
404 
405     /**
406      * Sets the nextCheckSequenceId attribute value.
407      * 
408      * @param nextCheckSequenceId The nextCheckSequenceId to set.
409      */
410     public void setNextCheckSequenceId(Integer nextCheckSequenceId) {
411         this.nextCheckSequenceId = nextCheckSequenceId;
412     }
413     
414     /**
415      * Gets the nextConfirmedCheckSequenceId attribute.
416      * 
417      * @return Returns the nextConfirmedCheckSequenceId.
418      */
419     public Integer getNextConfirmedCheckSequenceId() {
420         return nextConfirmedCheckSequenceId;
421     }
422 
423     /**
424      * Sets the nextCheckSequenceId attribute value.
425      * 
426      * @param nextCheckSequenceId The nextCheckSequenceId to set.
427      */
428     public void setNextConfirmedCheckSequenceId(Integer nextConfirmedCheckSequenceId) {
429         this.nextConfirmedCheckSequenceId = nextConfirmedCheckSequenceId;
430     }
431 
432     /**
433      * Gets the totalCheckAmount attribute.
434      * 
435      * @return Returns the totalCheckAmount.
436      */
437     public KualiDecimal getTotalCheckAmount() {
438         if (totalCheckAmount == null) {
439             setTotalCheckAmount(KualiDecimal.ZERO);
440         }
441         return totalCheckAmount;
442     }
443     
444     /**
445      * Gets the totalConfirmedCheckAmount attribute.
446      * 
447      * @return Returns the totalCheckAmount.
448      */
449     public KualiDecimal getTotalConfirmedCheckAmount() {
450         if (totalConfirmedCheckAmount == null) {
451             setTotalConfirmedCheckAmount(KualiDecimal.ZERO);
452         }
453         return totalConfirmedCheckAmount;
454     }
455 
456     /**
457      * Gets the totalConfirmedCheckAmount attribute.
458      * 
459      * @return Returns the totalCheckAmount.
460      */
461     public KualiDecimal getTotalConfirmedCheckAmountForInterim() {
462         if (totalConfirmedCheckAmount == null || getFinancialSystemDocumentHeader().getFinancialDocumentStatusCode().equals(CashReceipt.INTERIM)) {
463             setTotalConfirmedCheckAmount(KualiDecimal.ZERO);
464         }
465         return totalConfirmedCheckAmount;
466     }
467     
468     /**
469      * This method returns the check total amount as a currency formatted string.
470      * 
471      * @return String
472      */
473     public String getCurrencyFormattedTotalCheckAmount() {
474         return (String) new CurrencyFormatter().format(getTotalCheckAmount());
475     }
476     
477     /**
478      * This method returns the confirmed check total amount as a currency formatted string.
479      * 
480      * @return String
481      */
482     public String getCurrencyFormattedTotalConfirmedCheckAmount() {
483         String amountString = (String) new CurrencyFormatter().format(getTotalConfirmedCheckAmount());        
484         return amountString;
485         
486     }
487 
488     /**
489      * Sets the totalCheckAmount attribute value.
490      * 
491      * @param totalCheckAmount The totalCheckAmount to set.
492      */
493     public void setTotalCheckAmount(KualiDecimal totalCheckAmount) {
494         this.totalCheckAmount = totalCheckAmount;
495     }
496     
497     /**
498      * Sets the totalCheckAmount attribute value.
499      * 
500      * @param totalCheckAmount The totalCheckAmount to set.
501      */
502     public void setTotalConfirmedCheckAmount(KualiDecimal totalConfirmedCheckAmount) {
503         this.totalConfirmedCheckAmount = totalConfirmedCheckAmount;
504     }
505 
506     /**
507      * Gets the totalCoinAmount attribute.
508      * 
509      * @return Returns the totalCoinAmount.
510      */
511     public KualiDecimal getTotalCoinAmount() {
512         return (coinDetail != null) ? coinDetail.getTotalAmount() : KualiDecimal.ZERO;
513     }
514     
515     /**
516      * Gets the totalConfirmedCoinAmount attribute.
517      * 
518      * @return Returns the totalConfirmedCoinAmount.
519      */
520     public KualiDecimal getTotalConfirmedCoinAmount() {
521         return (confirmedCoinDetail != null) ? confirmedCoinDetail.getTotalAmount() : KualiDecimal.ZERO;
522     }
523     
524     /**
525      * Gets the totalChangeCoinAmount attribute.
526      * 
527      * @return Returns the totalChangeCoinAmount.
528      */
529     public KualiDecimal getTotalChangeCoinAmount() {
530         return (changeCoinDetail != null) ? changeCoinDetail.getTotalAmount() : KualiDecimal.ZERO;
531     }
532 
533     /**
534      * This method returns the coin total amount as a currency formatted string.
535      * 
536      * @return String
537      */
538     public String getCurrencyFormattedTotalCoinAmount() {
539         return (String) new CurrencyFormatter().format(getTotalCoinAmount());
540     }
541     
542     /**
543      * This method returns the confirmed coin total amount as a currency formatted string.
544      * 
545      * @return String
546      */
547     public String getCurrencyFormattedTotalConfirmedCoinAmount() {
548         return (String) new CurrencyFormatter().format(getTotalConfirmedCoinAmount());
549     }
550     
551     /**
552      * returns (confirmed currency + confirmed coin - change amount)
553      * 
554      * @return
555      */
556     public KualiDecimal getGrandTotalConfirmedCashAmount() {
557         return getTotalConfirmedCashAmount().add(getTotalConfirmedCoinAmount()).subtract(getTotalChangeAmount());
558     }
559 
560     /**
561      * returns (confirmed currency + confirmed coin - change amount) as a currency formatted string
562      * @return
563      */
564     public String getCurrencyFormattedGrandTotalConfirmedCashAmount() {
565         return (String) new CurrencyFormatter().format(getGrandTotalConfirmedCashAmount());
566     }
567     
568     /**
569      * Sets the totalCoinAmount attribute value.
570      * 
571      * @param totalCoinAmount The totalCoinAmount to set.
572      */
573     public void setTotalCoinAmount(KualiDecimal totalCoinAmount) {
574         this.totalCoinAmount = totalCoinAmount;
575     }
576     
577     /**
578      * Sets the totalConfirmedCoinAmount attribute value.
579      * 
580      * @param totalCoinAmount The totalConfirmedCoinAmount to set.
581      */
582     public void setTotalConfirmedCoinAmount(KualiDecimal totalConfirmedCoinAmount) {
583         this.totalConfirmedCoinAmount = totalConfirmedCoinAmount;
584     }
585 
586     /**
587      * This method returns the overall total of the document - coin plus check plus cash.
588      * 
589      * @see org.kuali.ole.sys.document.AccountingDocumentBase#getTotalDollarAmount()
590      * @return KualiDecimal
591      */
592     @Override
593     public KualiDecimal getTotalDollarAmount() {
594         if(getFinancialSystemDocumentHeader().getFinancialDocumentStatusCode().equals(OLEConstants.DocumentStatusCodes.CashReceipt.VERIFIED)) {
595             return getTotalConfirmedDollarAmount();
596         } else {
597             return getTotalCoinAmount().add(getTotalCheckAmount()).add(getTotalCashAmount());
598         }
599     }
600     
601     /**
602      * This method returns the overall confirmed total of the document - coin plus check plus cash.
603      * 
604      * @return KualiDecimal
605      */
606     public KualiDecimal getTotalConfirmedDollarAmount() {
607         KualiDecimal sumTotalAmount = getTotalConfirmedCoinAmount().add(getTotalConfirmedCheckAmount()).add(getTotalConfirmedCashAmount());
608         return sumTotalAmount;
609     }
610     
611     public KualiDecimal getTotalChangeAmount() {
612         return getTotalChangeCoinAmount().add(getTotalChangeCashAmount());
613     }
614 
615     /**
616      * Gets the coinDetail attribute.
617      * 
618      * @return Returns the coinDetail.
619      */
620     public CoinDetail getCoinDetail() {
621         return coinDetail;
622     }
623 
624     /**
625      * Sets the coinDetail attribute value.
626      * 
627      * @param coinDetail The coinDetail to set.
628      */
629     public void setCoinDetail(CoinDetail coinDetail) {
630         this.coinDetail = coinDetail;
631     }
632     
633     /**
634      * Gets the confirmedCoinDetail attribute.
635      * 
636      * @return Returns the confirmedCoinDetail.
637      */
638     public CoinDetail getConfirmedCoinDetail() {
639         return confirmedCoinDetail;
640     }
641 
642     /**
643      * Sets the confirmedCoinDetail attribute value.
644      * 
645      * @param coinDetail The confirmedCoinDetail to set.
646      */
647     public void setConfirmedCoinDetail(CoinDetail coinDetail) {
648         this.confirmedCoinDetail = coinDetail;
649     }
650     
651     /**
652      * Gets the changeCoinDetail attribute.
653      * 
654      * @return Returns the changeCoinDetail.
655      */
656     public CoinDetail getChangeCoinDetail() {
657         return changeCoinDetail;
658     }
659 
660     /**
661      * Sets the changeCoinDetail attribute value.
662      * 
663      * @param coinDetail The changeCoinDetail to set.
664      */
665     public void setChangeCoinDetail(CoinDetail changeCoinDetail) {
666         this.changeCoinDetail = changeCoinDetail;
667     }
668 
669     /**
670      * Gets the currencyDetail attribute.
671      * 
672      * @return Returns the currencyDetail.
673      */
674     public CurrencyDetail getCurrencyDetail() {
675         return currencyDetail;
676     }
677 
678     /**
679      * Sets the currencyDetail attribute value.
680      * 
681      * @param currencyDetail The currencyDetail to set.
682      */
683     public void setCurrencyDetail(CurrencyDetail currencyDetail) {
684         this.currencyDetail = currencyDetail;
685     }
686     
687     /**
688      * Gets the confirmedCurrencyDetail attribute.
689      * 
690      * @return Returns the confirmedCurrencyDetail.
691      */
692     public CurrencyDetail getConfirmedCurrencyDetail() {
693         return confirmedCurrencyDetail;
694     }
695 
696     /**
697      * Sets the confirmedCurrencyDetail attribute value.
698      * 
699      * @param currencyDetail The confirmedCurrencyDetail to set.
700      */
701     public void setConfirmedCurrencyDetail(CurrencyDetail confirmedCurrencyDetail) {
702         this.confirmedCurrencyDetail = confirmedCurrencyDetail;
703     }
704     
705     /**
706      * Gets the changeCurrencyDetail attribute.
707      * 
708      * @return Returns the changeCurrencyDetail.
709      */
710     public CurrencyDetail getChangeCurrencyDetail() {
711         return changeCurrencyDetail;
712     }
713 
714     /**
715      * Sets the changeCurrencyDetail attribute value.
716      * 
717      * @param currencyDetail The changeCurrencyDetail to set.
718      */
719     public void setChangeCurrencyDetail(CurrencyDetail changeCurrencyDetail) {
720         this.changeCurrencyDetail = changeCurrencyDetail;
721     }
722 
723     /**
724      * Retrieves the summed total amount in a currency format with commas.
725      * 
726      * @return String
727      */
728     public String getCurrencyFormattedSumTotalAmount() {
729         return (String) new CurrencyFormatter().format(getTotalDollarAmount());
730     }
731     
732     /**
733      * Retrieves the confirmed summed total amount in a currency format with commas.
734      * 
735      * @return String
736      */
737     public String getCurrencyFormattedConfirmedSumTotalAmount() {
738         return (String) new CurrencyFormatter().format(getTotalConfirmedDollarAmount());
739     }
740     
741     /**
742      * Retrieves the final summed total amount (after subtracting change amount)in currency format with commas.
743      * 
744      * @return String
745      */
746     public String getCurrencyFormattedFinalSumTotalAmount() {
747         return (String) new CurrencyFormatter().format(getTotalConfirmedDollarAmount().subtract(getTotalChangeAmount()));
748     }
749     
750     
751     /**
752      * Retrieves the change total amount in a currency format with commas.
753      * 
754      * @return String
755      */
756     public String getCurrencyFormattedChangeTotalAmount() {
757         return (String) new CurrencyFormatter().format(getTotalChangeAmount());
758     }
759 
760     /**
761      * Gets the recategorized attribute. 
762      * @return Returns the recategorized.
763      */
764     public boolean isRecategorized() {
765         return recategorized;
766     }
767 
768     /**
769      * Sets the recategorized attribute value.
770      * @param recategorized The recategorized to set.
771      */
772     public void setRecategorized(boolean recategorized) {
773         this.recategorized = recategorized;
774     }
775 
776     /**
777      * @return sum of the amounts of the current list of checks
778      */
779     public KualiDecimal calculateCheckTotal() {
780         KualiDecimal total = KualiDecimal.ZERO;
781         for (Iterator<Check> i = getChecks().iterator(); i.hasNext();) {
782             Check c = i.next();
783             if (null != c.getAmount()) {
784                 total = total.add(c.getAmount());
785             }
786         }
787         return total;
788     }
789     
790     /**
791      * @return sum of the amounts of the current list of checks
792      */
793     public KualiDecimal calculateConfirmedCheckTotal() {
794         KualiDecimal total = KualiDecimal.ZERO;
795         for (Iterator<Check> i = getConfirmedChecks().iterator(); i.hasNext();) {
796             Check c = i.next();
797             if (null != c.getAmount()) {
798                 total = total.add(c.getAmount());
799             }
800         }
801         return total;
802     }
803 
804 
805     /**
806      * @see org.kuali.rice.kns.document.DocumentBase#prepareForSave()
807      */
808     @Override
809     public void prepareForSave() {
810         super.prepareForSave();
811 
812         // clear check list if mode is checkTotal
813         if (CHECK_ENTRY_TOTAL.equals(getCheckEntryMode())) {
814             getChecks().clear();
815         }
816         // update total if mode is checkDetail
817         else {
818             setTotalCheckAmount(calculateCheckTotal());
819         }
820     }
821 
822     /**
823      * @see org.kuali.rice.kns.document.DocumentBase#processAfterRetrieve()
824      */
825     @Override
826     public void processAfterRetrieve() {
827         super.processAfterRetrieve();
828 
829         // set to checkTotal mode if no checks
830         List<Check> checkList = getChecks();
831         if (ObjectUtils.isNull(checkList) || checkList.isEmpty()) {
832             setCheckEntryMode(CHECK_ENTRY_TOTAL);
833         }
834         // set to checkDetail mode if checks (and update the checkTotal, while you're here)
835         else {
836             setCheckEntryMode(CHECK_ENTRY_DETAIL);
837             setTotalCheckAmount(calculateCheckTotal());
838         }
839         refreshCashDetails();
840     }
841 
842     /**
843      * Override to set the document status to VERIFIED ("V") when the document is FINAL. When the Cash Management document that this
844      * is associated with is FINAL approved, this status will be set to APPROVED ("A") to be picked up by the GL for processing.
845      * That's done in the doRouteStatusChange() method in the CashManagementDocument.
846      * 
847      * @see org.kuali.rice.kns.document.Document#doRouteStatusChange()
848      */
849     @Override
850     public void doRouteStatusChange(DocumentRouteStatusChange statusChangeEvent) {
851         super.doRouteStatusChange(statusChangeEvent);        
852         WorkflowDocument workflowDocument = getDocumentHeader().getWorkflowDocument();
853         
854         // Workflow Status of PROCESSED --> Kuali Doc Status of Verified
855         if (workflowDocument.isProcessed()) {
856             this.getFinancialSystemDocumentHeader().setFinancialDocumentStatusCode(OLEConstants.DocumentStatusCodes.CashReceipt.VERIFIED);
857             LOG.info("Adding Cash to Cash Drawer");
858             SpringContext.getBean(CashReceiptService.class).addCashDetailsToCashDrawer(this);
859         }
860 
861         this.getCapitalAssetManagementModuleService().deleteDocumentAssetLocks(this);        
862     }
863     
864     /**
865      * @see org.kuali.rice.kns.document.DocumentBase#postProcessSave(org.kuali.rice.kns.rule.event.KualiDocumentEvent)
866      */
867     @Override
868     public void postProcessSave(KualiDocumentEvent event) {
869         super.postProcessSave(event);
870         
871         boolean cM_veifies = (getTotalConfirmedDollarAmount().compareTo(KualiDecimal.ZERO) != 0); 
872         if (retrieveCurrencyDetail() == null) {
873             getCurrencyDetail().setDocumentNumber(this.getDocumentNumber());
874             getCurrencyDetail().setFinancialDocumentTypeCode(CashReceiptDocument.DOCUMENT_TYPE);
875             getCurrencyDetail().setCashieringStatus(OLEConstants.CurrencyCoinSources.CASH_RECEIPTS);
876         }
877 
878         if (retrieveCoinDetail() == null) {
879             getCoinDetail().setDocumentNumber(this.getDocumentNumber());
880             getCoinDetail().setFinancialDocumentTypeCode(CashReceiptDocument.DOCUMENT_TYPE);
881             getCoinDetail().setCashieringStatus(OLEConstants.CurrencyCoinSources.CASH_RECEIPTS); 
882         }
883         
884         if(cM_veifies) {
885             getConfirmedCurrencyDetail().setDocumentNumber(this.getDocumentNumber());
886             getConfirmedCurrencyDetail().setFinancialDocumentTypeCode(CashReceiptDocument.DOCUMENT_TYPE);
887             getConfirmedCurrencyDetail().setCashieringStatus(OLEConstants.CurrencyCoinSources.CASH_MANAGEMENT_IN);
888             
889             getConfirmedCoinDetail().setDocumentNumber(this.getDocumentNumber());
890             getConfirmedCoinDetail().setFinancialDocumentTypeCode(CashReceiptDocument.DOCUMENT_TYPE);
891             getConfirmedCoinDetail().setCashieringStatus(OLEConstants.CurrencyCoinSources.CASH_MANAGEMENT_IN);
892             
893             SpringContext.getBean(BusinessObjectService.class).save(getConfirmedCurrencyDetail());
894             SpringContext.getBean(BusinessObjectService.class).save(getConfirmedCoinDetail());
895         } 
896         if(!(getTotalChangeAmount().compareTo(KualiDecimal.ZERO) == 0)) {
897             getChangeCurrencyDetail().setDocumentNumber(this.getDocumentNumber());
898             getChangeCurrencyDetail().setFinancialDocumentTypeCode(CashReceiptDocument.DOCUMENT_TYPE);
899             getChangeCoinDetail().setDocumentNumber(this.getDocumentNumber());
900             getChangeCoinDetail().setFinancialDocumentTypeCode(CashReceiptDocument.DOCUMENT_TYPE);
901             if (cM_veifies) {
902                 getChangeCurrencyDetail().setCashieringStatus(OLEConstants.CurrencyCoinSources.CASH_CHANGE_GRANTED);
903                 getChangeCoinDetail().setCashieringStatus(OLEConstants.CurrencyCoinSources.CASH_CHANGE_GRANTED);
904             } else {
905                 getChangeCurrencyDetail().setCashieringStatus(OLEConstants.CurrencyCoinSources.CASH_CHANGE_REQUEST);
906                 getChangeCoinDetail().setCashieringStatus(OLEConstants.CurrencyCoinSources.CASH_CHANGE_REQUEST);
907             }
908             SpringContext.getBean(BusinessObjectService.class).save(getChangeCurrencyDetail());
909             SpringContext.getBean(BusinessObjectService.class).save(getChangeCoinDetail());
910         }
911         
912         SpringContext.getBean(BusinessObjectService.class).save(getCurrencyDetail());
913         SpringContext.getBean(BusinessObjectService.class).save(getCoinDetail());
914         
915         if (!(event instanceof SaveDocumentEvent)) { // don't lock until they route
916             String documentTypeName = SpringContext.getBean(DataDictionaryService.class).getDocumentTypeNameByClass(this.getClass());
917             this.getCapitalAssetManagementModuleService().generateCapitalAssetLock(this,documentTypeName);
918         }        
919     }
920 
921     /**
922      * This method refreshes the currency/coin details for this cash receipt document
923      */
924     public void refreshCashDetails() {
925         this.currencyDetail = retrieveCurrencyDetail();
926         this.coinDetail = retrieveCoinDetail();
927         CurrencyDetail retrievedCurrencyDetail = retrieveConfirmedCurrencyDetail();
928         CoinDetail retrievedCoinDetail = retrieveConfirmedCoinDetail();
929         CurrencyDetail retrievedChangeCurrDetail = retrieveChangeCurrencyDetail();
930         CoinDetail retrievedChangeCoinDetail = retrieveChangeCoinDetail();
931         //If this method is called before the cash-in record is inserted into the DB, it should not assign null
932         if(retrievedCurrencyDetail != null) {
933             this.confirmedCurrencyDetail = retrievedCurrencyDetail;
934         }
935         if(retrievedCoinDetail != null) {
936             this.confirmedCoinDetail = retrievedCoinDetail;
937         }
938         if(retrievedChangeCurrDetail != null) {
939             this.changeCurrencyDetail = retrievedChangeCurrDetail;
940         }
941         if(retrievedChangeCoinDetail != null) {
942             this.changeCoinDetail = retrievedChangeCoinDetail;
943         }
944     }
945 
946     /**
947      * Get this document's currency detail from the database
948      * 
949      * @return the currency detail record for this cash receipt document
950      */
951     protected CurrencyDetail retrieveCurrencyDetail() {
952         return (CurrencyDetail) SpringContext.getBean(BusinessObjectService.class).findByPrimaryKey(CurrencyDetail.class, getCashDetailPrimaryKey());
953     }
954 
955     /**
956      * Grab this document's coin detail from the database
957      * 
958      * @return the coin detail record for this cash receipt document
959      */
960     protected CoinDetail retrieveCoinDetail() {
961         return (CoinDetail) SpringContext.getBean(BusinessObjectService.class).findByPrimaryKey(CoinDetail.class, getCashDetailPrimaryKey());
962     }
963     
964     /**
965      * Get this document's confirmed currency detail from the database
966      * 
967      * @return the currency detail record for this cash receipt document
968      */
969     protected CurrencyDetail retrieveConfirmedCurrencyDetail() {
970         return (CurrencyDetail) SpringContext.getBean(BusinessObjectService.class).findByPrimaryKey(CurrencyDetail.class, getConfirmedCashDetailPrimaryKey());
971     }
972     
973     /**
974      * Get this document's confirmed coin detail from the database
975      * 
976      * @return the coin detail record for this cash receipt document
977      */
978     protected CoinDetail retrieveConfirmedCoinDetail() {
979         return (CoinDetail) SpringContext.getBean(BusinessObjectService.class).findByPrimaryKey(CoinDetail.class, getConfirmedCashDetailPrimaryKey());
980     }
981     
982     /**
983      * Get this document's change currency detail from the database
984      * 
985      * @return the change currency detail record for this cash receipt document
986      */
987     protected CurrencyDetail retrieveChangeCurrencyDetail() {
988         return (CurrencyDetail) SpringContext.getBean(BusinessObjectService.class).findByPrimaryKey(CurrencyDetail.class, getChangeCashDetailPrimaryKey());
989     }
990     
991     /**
992      * Get this document's change coin detail from the database
993      * 
994      * @return the change coin detail record for this cash receipt document
995      */
996     protected CoinDetail retrieveChangeCoinDetail() {
997         return (CoinDetail) SpringContext.getBean(BusinessObjectService.class).findByPrimaryKey(CoinDetail.class, getChangeCashDetailPrimaryKey());
998     }
999 
1000     /**
1001      * 
1002      * This method...
1003      * @return
1004      */
1005     public String getCreateDate() {
1006         return SpringContext.getBean(DateTimeService.class).toDateString(getDocumentHeader().getWorkflowDocument().getDateCreated().toDate());
1007     }
1008     
1009     /**
1010      * Generate the primary key for a currency or coin detail related to this document
1011      * 
1012      * @return a map with a representation of the proper primary key
1013      */
1014     protected Map getCashDetailPrimaryKey() {
1015         Map pk = new HashMap();
1016         pk.put("documentNumber", this.getDocumentNumber());
1017         pk.put("financialDocumentTypeCode", CashReceiptDocument.DOCUMENT_TYPE);
1018         pk.put("cashieringStatus", OLEConstants.CurrencyCoinSources.CASH_RECEIPTS); 
1019         return pk;
1020     }
1021     
1022     protected Map getConfirmedCashDetailPrimaryKey() {
1023         Map pk = new HashMap();
1024         pk.put("documentNumber", this.getDocumentNumber());
1025         pk.put("financialDocumentTypeCode", CashReceiptDocument.DOCUMENT_TYPE);
1026         pk.put("cashieringStatus", OLEConstants.CurrencyCoinSources.CASH_MANAGEMENT_IN); 
1027         return pk;
1028     }
1029     
1030     protected Map getChangeCashDetailPrimaryKey() {
1031         Map pk = new HashMap();
1032         pk.put("documentNumber", this.getDocumentNumber());
1033         pk.put("financialDocumentTypeCode", CashReceiptDocument.DOCUMENT_TYPE);
1034         pk.put("cashieringStatus", OLEConstants.CurrencyCoinSources.CASH_CHANGE_REQUEST); 
1035         return pk;
1036     }
1037 
1038     /**
1039      * @see org.kuali.rice.kns.document.TransactionalDocumentBase#buildListOfDeletionAwareLists()
1040      */
1041     @Override
1042     public List buildListOfDeletionAwareLists() {
1043         List managedLists = super.buildListOfDeletionAwareLists();
1044         managedLists.add(getChecks());
1045 
1046         return managedLists;
1047     }
1048 
1049     @Override
1050     public List generateSaveEvents() {
1051         // 1. retrieve persisted checks for document
1052         // 2. retrieve current checks from given document
1053         // 3. compare, creating add/delete/update events as needed
1054         // 4. apply rules as appropriate returned events
1055         Collection<CheckBase> persistedChecks = SpringContext.getBean(CheckService.class).getByDocumentHeaderId(getDocumentNumber());
1056         List currentChecks = getChecks();
1057 
1058         List events = generateEvents(persistedChecks, currentChecks, OLEConstants.EXISTING_CHECK_PROPERTY_NAME, this);
1059 
1060         events.addAll(super.generateSaveEvents()); 
1061         
1062         return events;
1063     }
1064 
1065     /**
1066      * Generates a List of instances of CheckEvent subclasses, one for each changed check in the union of the persistedLines and
1067      * currentLines lists. Events in the list will be grouped in order by event-type (update, add, delete).
1068      * 
1069      * @param persistedChecks
1070      * @param currentChecks
1071      * @param errorPathPrefix
1072      * @param crdoc
1073      * @return List of CheckEvent subclass instances
1074      */
1075     protected List generateEvents(Collection persistedChecks, List currentChecks, String errorPathPrefix, CashReceiptFamilyBase crdoc) {
1076         List addEvents = new ArrayList();
1077         List updateEvents = new ArrayList();
1078         List deleteEvents = new ArrayList();
1079 
1080         //
1081         // generate events
1082         Map persistedCheckMap = buildCheckMap(persistedChecks);
1083 
1084         // (iterate through current lines to detect additions and updates, removing affected lines from persistedLineMap as we go
1085         // so deletions can be detected by looking at whatever remains in persistedLineMap)
1086         int index = 0;
1087         for (Iterator i = currentChecks.iterator(); i.hasNext(); index++) {
1088             Check currentCheck = (Check) i.next();
1089             Integer key = currentCheck.getSequenceId();
1090 
1091             Check persistedCheck = (Check) persistedCheckMap.get(key);
1092             // if line is both current and persisted...
1093             if (persistedCheck != null) {
1094                 // ...check for updates
1095                 if (!currentCheck.isLike(persistedCheck)) {
1096                     UpdateCheckEvent updateEvent = new UpdateCheckEvent(errorPathPrefix, crdoc, currentCheck);
1097                     updateEvents.add(updateEvent);
1098                 }
1099                 else {
1100                     // do nothing, since this line hasn't changed
1101                 }
1102 
1103                 persistedCheckMap.remove(key);
1104             }
1105             else {
1106                 // it must be a new addition
1107                 AddCheckEvent addEvent = new AddCheckEvent(errorPathPrefix, crdoc, currentCheck);
1108                 addEvents.add(addEvent);
1109             }
1110         }
1111 
1112         // detect deletions
1113         for (Iterator i = persistedCheckMap.entrySet().iterator(); i.hasNext();) {
1114             Map.Entry e = (Map.Entry) i.next();
1115             Check persistedCheck = (Check) e.getValue();
1116             DeleteCheckEvent deleteEvent = new DeleteCheckEvent(errorPathPrefix, crdoc, persistedCheck);
1117             deleteEvents.add(deleteEvent);
1118         }
1119 
1120 
1121         //
1122         // merge the lists
1123         List lineEvents = new ArrayList();
1124         lineEvents.addAll(updateEvents);
1125         lineEvents.addAll(addEvents);
1126         lineEvents.addAll(deleteEvents);
1127 
1128         return lineEvents;
1129     }
1130 
1131 
1132     /**
1133      * @param checks
1134      * @return Map containing Checks from the given List, indexed by their sequenceId
1135      */
1136     protected Map buildCheckMap(Collection checks) {
1137         Map checkMap = new HashMap();
1138 
1139         for (Iterator i = checks.iterator(); i.hasNext();) {
1140             Check check = (Check) i.next();
1141             Integer sequenceId = check.getSequenceId();
1142 
1143             Object oldCheck = checkMap.put(sequenceId, check);
1144 
1145             // verify that sequence numbers are unique...
1146             if (oldCheck != null) {
1147                 throw new IllegalStateException("sequence id collision detected for sequence id " + sequenceId);
1148             }
1149         }
1150 
1151         return checkMap;
1152     }
1153 
1154     public Check createNewCheck() {
1155         Check newCheck = new CheckBase();
1156         newCheck.setFinancialDocumentTypeCode(DOCUMENT_TYPE);
1157         newCheck.setCashieringStatus(OLEConstants.CheckSources.CASH_RECEIPTS);
1158         return newCheck;
1159     }
1160     
1161     public Check createNewConfirmedCheck() {
1162         Check newCheck = new CheckBase();
1163         newCheck.setFinancialDocumentTypeCode(DOCUMENT_TYPE);
1164         newCheck.setCashieringStatus(OLEConstants.CheckSources.CASH_MANAGEMENT);
1165         return newCheck;
1166     }
1167 
1168     /**
1169      * Gets the depositCashReceiptControl attribute. 
1170      * @return Returns the depositCashReceiptControl.
1171      */
1172     public List getDepositCashReceiptControl() {
1173         return depositCashReceiptControl;
1174     }
1175 
1176     /**
1177      * Sets the depositCashReceiptControl attribute value.
1178      * @param depositCashReceiptControl The depositCashReceiptControl to set.
1179      */
1180     public void setDepositCashReceiptControl(List depositCashReceiptControl) {
1181         this.depositCashReceiptControl = depositCashReceiptControl;
1182     }
1183 
1184     /**
1185      * Override the campus code on the copied document to whatever the campus of the copying user is
1186      * @see org.kuali.ole.sys.document.AccountingDocumentBase#toCopy()
1187      */
1188     @Override
1189     public void toCopy() throws WorkflowException {
1190         super.toCopy();
1191         
1192         initializeCampusLocationCode();
1193         
1194         if ((getChecks() == null || getChecks().isEmpty()) && getTotalCheckAmount().equals(KualiDecimal.ZERO)) {
1195             setCheckEntryMode(CashReceiptDocument.CHECK_ENTRY_DETAIL);
1196         }
1197     }
1198 
1199     /**
1200      * Initializes the campus location code based on ole user role chart org
1201      * 
1202      */
1203     public void initializeCampusLocationCode(){
1204         
1205         if (GlobalVariables.getUserSession() != null && GlobalVariables.getUserSession().getPerson() != null) {        
1206          
1207             Person currentUser = GlobalVariables.getUserSession().getPerson();
1208             ChartOrgHolder chartOrg = SpringContext.getBean(org.kuali.ole.sys.service.FinancialSystemUserService.class).getPrimaryOrganization(currentUser, OLEConstants.ParameterNamespaces.FINANCIAL);
1209             
1210             // Does a valid campus code exist for this person?  If so, simply grab
1211             // the campus code via the business object service.  
1212             if (chartOrg != null && chartOrg.getOrganization() != null) {
1213                 setCampusLocationCode(chartOrg.getOrganization().getOrganizationPhysicalCampusCode());
1214             }
1215             // A valid campus code was not found; therefore, use the default affiliated
1216             // campus code.
1217             else {
1218                 String affiliatedCampusCode = currentUser.getCampusCode();
1219                 setCampusLocationCode(affiliatedCampusCode);
1220             }
1221         }
1222     }
1223 
1224     /**
1225      * Gets the sumTotalAmount attribute.
1226      * 
1227      * @return Returns the sumTotalAmount
1228      */
1229     
1230     public KualiDecimal getSumTotalAmount() {
1231         return sumTotalAmount;
1232     }
1233 
1234     /**	
1235      * Sets the sumTotalAmount attribute.
1236      * 
1237      * @param sumTotalAmount The sumTotalAmount to set.
1238      */
1239     public void setSumTotalAmount(KualiDecimal sumTotalAmount) {
1240         this.sumTotalAmount = sumTotalAmount;
1241     }
1242 }
1243