001 /*
002 * Copyright 2011 The Kuali Foundation.
003 *
004 * Licensed under the Educational Community License, Version 2.0 (the "License");
005 * you may not use this file except in compliance with the License.
006 * You may obtain a copy of the License at
007 *
008 * http://www.opensource.org/licenses/ecl2.php
009 *
010 * Unless required by applicable law or agreed to in writing, software
011 * distributed under the License is distributed on an "AS IS" BASIS,
012 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
013 * See the License for the specific language governing permissions and
014 * limitations under the License.
015 */
016 package org.kuali.kfs.fp.businessobject;
017
018 import java.util.ArrayList;
019 import java.util.HashMap;
020 import java.util.Iterator;
021 import java.util.LinkedHashMap;
022 import java.util.List;
023 import java.util.Map;
024
025 import org.kuali.kfs.sys.KFSConstants;
026 import org.kuali.kfs.sys.context.SpringContext;
027 import org.kuali.rice.kns.bo.TransientBusinessObjectBase;
028 import org.kuali.rice.kns.service.DateTimeService;
029 import org.kuali.rice.kns.util.KualiDecimal;
030
031 /**
032 * This class represents a cashiering-related transaction used in the cash management document
033 */
034 public class CashieringTransaction extends TransientBusinessObjectBase {
035 public static final String DETAIL_DOCUMENT_TYPE = "CM";
036
037 private String campusCode;
038 private String referenceFinancialDocumentNumber;
039
040 // money in properties
041 private List<Check> moneyInChecks;
042 private CoinDetail moneyInCoin;
043 private CurrencyDetail moneyInCurrency;
044 private CashieringItemInProcess newItemInProcess;
045 private List<Check> baselineChecks;
046 private Check newCheck;
047 private KualiDecimal checkTotal;
048
049 // money out properties
050 private CoinDetail moneyOutCoin;
051 private CurrencyDetail moneyOutCurrency;
052 private List<CashieringItemInProcess> openItemsInProcess;
053
054 private java.util.Date transactionStarted;
055 private java.util.Date transactionEnded;
056
057 // incrementers for detail lines
058 private Integer nextCheckSequenceId;
059
060
061 /**
062 * Constructs a CashieringTransaction
063 */
064 public CashieringTransaction(String campusCode, String referenceFinancialDocumentNumber) {
065 super();
066 this.campusCode = campusCode;
067 this.referenceFinancialDocumentNumber = referenceFinancialDocumentNumber;
068 this.transactionStarted = SpringContext.getBean(DateTimeService.class).getCurrentDate();
069
070 moneyInCoin = new CoinDetail();
071 moneyInCurrency = new CurrencyDetail();
072
073 moneyOutCoin = new CoinDetail();
074 moneyOutCurrency = new CurrencyDetail();
075
076 newItemInProcess = new CashieringItemInProcess();
077 moneyInChecks = new ArrayList<Check>();
078 newCheck = new CheckBase();
079 baselineChecks = new ArrayList<Check>();
080 openItemsInProcess = new ArrayList<CashieringItemInProcess>();
081 nextCheckSequenceId = new Integer(1);
082 }
083
084 /**
085 * Gets the moneyInChecks attribute.
086 *
087 * @return Returns the moneyInChecks.
088 */
089 public List<Check> getMoneyInChecks() {
090 return moneyInChecks;
091 }
092
093 /**
094 * Sets the moneyInChecks attribute value.
095 *
096 * @param moneyInChecks The moneyInChecks to set.
097 */
098 public void setMoneyInChecks(List<Check> moneyInChecks) {
099 this.moneyInChecks = moneyInChecks;
100 }
101
102 /**
103 * Retrieves a specific check from the list, by array index
104 *
105 * @param index the index of the checks array to retrieve the check from
106 * @return a Check
107 */
108 public Check getMoneyInCheck(int index) {
109 if (index >= moneyInChecks.size()) {
110 for (int i = moneyInChecks.size(); i <= index; i++) {
111 moneyInChecks.add(createNewCheck());
112 }
113 }
114 return moneyInChecks.get(index);
115 }
116
117 /**
118 * Gets the moneyInCoin attribute.
119 *
120 * @return Returns the moneyInCoin.
121 */
122 public CoinDetail getMoneyInCoin() {
123 return moneyInCoin;
124 }
125
126 /**
127 * Sets the moneyInCoin attribute value.
128 *
129 * @param moneyInCoin The moneyInCoin to set.
130 */
131 public void setMoneyInCoin(CoinDetail moneyInCoin) {
132 this.moneyInCoin = moneyInCoin;
133 }
134
135 /**
136 * Gets the moneyInCurrency attribute.
137 *
138 * @return Returns the moneyInCurrency.
139 */
140 public CurrencyDetail getMoneyInCurrency() {
141 return moneyInCurrency;
142 }
143
144 /**
145 * Sets the moneyInCurrency attribute value.
146 *
147 * @param moneyInCurrency The moneyInCurrency to set.
148 */
149 public void setMoneyInCurrency(CurrencyDetail moneyInCurrency) {
150 this.moneyInCurrency = moneyInCurrency;
151 }
152
153 /**
154 * Gets the moneyOutCoin attribute.
155 *
156 * @return Returns the moneyOutCoin.
157 */
158 public CoinDetail getMoneyOutCoin() {
159 return moneyOutCoin;
160 }
161
162 /**
163 * Sets the moneyOutCoin attribute value.
164 *
165 * @param moneyOutCoin The moneyOutCoin to set.
166 */
167 public void setMoneyOutCoin(CoinDetail moneyOutCoin) {
168 this.moneyOutCoin = moneyOutCoin;
169 }
170
171 /**
172 * Gets the transactionEnded attribute.
173 *
174 * @return Returns the transactionEnded.
175 */
176 public java.util.Date getTransactionEnded() {
177 return transactionEnded;
178 }
179
180 /**
181 * Sets the transactionEnded attribute value.
182 *
183 * @param transactionEnded The transactionEnded to set.
184 */
185 public void setTransactionEnded(java.util.Date transactionEnded) {
186 this.transactionEnded = transactionEnded;
187 }
188
189 /**
190 * Gets the transactionStarted attribute.
191 *
192 * @return Returns the transactionStarted.
193 */
194 public java.util.Date getTransactionStarted() {
195 return transactionStarted;
196 }
197
198 /**
199 * Sets the transactionStarted attribute value.
200 *
201 * @param transactionStarted The transactionStarted to set.
202 */
203 public void setTransactionStarted(java.util.Date transactionStarted) {
204 this.transactionStarted = transactionStarted;
205 }
206
207 /**
208 * Gets the campusCode attribute.
209 *
210 * @return Returns the campusCode.
211 */
212 public String getCampusCode() {
213 return campusCode;
214 }
215
216 /**
217 * Sets the campusCode attribute value.
218 *
219 * @param campusCode The campusCode to set.
220 */
221 public void setCampusCode(String campusCode) {
222 this.campusCode = campusCode;
223 }
224
225 /**
226 * Sets the moneyOutCurrency attribute value.
227 *
228 * @param moneyOutCurrency The moneyOutCurrency to set.
229 */
230 public void setMoneyOutCurrency(CurrencyDetail moneyOutCurrency) {
231 this.moneyOutCurrency = moneyOutCurrency;
232 }
233
234 /**
235 * Gets the referenceFinancialDocumentNumber attribute.
236 *
237 * @return Returns the referenceFinancialDocumentNumber.
238 */
239 public String getReferenceFinancialDocumentNumber() {
240 return referenceFinancialDocumentNumber;
241 }
242
243 /**
244 * Sets the referenceFinancialDocumentNumber attribute value.
245 *
246 * @param referenceFinancialDocumentNumber The referenceFinancialDocumentNumber to set.
247 */
248 public void setReferenceFinancialDocumentNumber(String referenceFinancialDocumentNumber) {
249 this.referenceFinancialDocumentNumber = referenceFinancialDocumentNumber;
250 }
251
252 /**
253 * Gets the moneyOutCurrency attribute.
254 *
255 * @return Returns the moneyOutCurrency.
256 */
257 public CurrencyDetail getMoneyOutCurrency() {
258 return moneyOutCurrency;
259 }
260
261 /**
262 * Gets the newItemInProcess attribute.
263 *
264 * @return Returns the newItemInProcess.
265 */
266 public CashieringItemInProcess getNewItemInProcess() {
267 return newItemInProcess;
268 }
269
270 /**
271 * Sets the newItemInProcess attribute value.
272 *
273 * @param newItemInProcess The newItemInProcess to set.
274 */
275 public void setNewItemInProcess(CashieringItemInProcess newItemInProcess) {
276 this.newItemInProcess = newItemInProcess;
277 }
278
279 /**
280 * Gets the openItemsInProcess attribute.
281 *
282 * @return Returns the openItemsInProcess.
283 */
284 public List<CashieringItemInProcess> getOpenItemsInProcess() {
285 return openItemsInProcess;
286 }
287
288 /**
289 * Sets the openItemsInProcess attribute value.
290 *
291 * @param openItemsInProcess The openItemsInProcess to set.
292 */
293 public void setOpenItemsInProcess(List<CashieringItemInProcess> openItemsInProcess) {
294 this.openItemsInProcess = openItemsInProcess;
295 }
296
297 /**
298 * This method returns a single open item in process
299 *
300 * @return a cashiering item in process
301 */
302 public CashieringItemInProcess getOpenItemInProcess(int index) {
303 extendOpenItemsList(index);
304 return this.openItemsInProcess.get(index);
305 }
306
307 /**
308 * make the open items in process list bigger, so it doesn't return a null value
309 *
310 * @param minSize the minsize to make the list
311 */
312 private void extendOpenItemsList(int minSize) {
313 while (this.openItemsInProcess.size() <= minSize) {
314 this.openItemsInProcess.add(new CashieringItemInProcess());
315 }
316 }
317
318 /**
319 * Gets the newCheck attribute.
320 *
321 * @return Returns the newCheck.
322 */
323 public Check getNewCheck() {
324 return newCheck;
325 }
326
327 /**
328 * Sets the newCheck attribute value.
329 *
330 * @param newCheck The newCheck to set.
331 */
332 public void setNewCheck(Check newCheck) {
333 this.newCheck = newCheck;
334 }
335
336 /**
337 * This method will make sure that all of the various currency, coin, check, and item in process detail records are populated
338 * with the correct info.
339 */
340 public void prepareForSave() {
341 moneyInCoin.setDocumentNumber(this.referenceFinancialDocumentNumber);
342 moneyInCoin.setFinancialDocumentTypeCode(DETAIL_DOCUMENT_TYPE);
343 moneyInCoin.setCashieringRecordSource(KFSConstants.CurrencyCoinSources.CASH_MANAGEMENT_IN);
344
345 moneyInCurrency.setDocumentNumber(this.referenceFinancialDocumentNumber);
346 moneyInCurrency.setFinancialDocumentTypeCode(DETAIL_DOCUMENT_TYPE);
347 moneyInCurrency.setCashieringRecordSource(KFSConstants.CurrencyCoinSources.CASH_MANAGEMENT_IN);
348
349 moneyOutCoin.setDocumentNumber(this.referenceFinancialDocumentNumber);
350 moneyOutCoin.setFinancialDocumentTypeCode(DETAIL_DOCUMENT_TYPE);
351 moneyOutCoin.setCashieringRecordSource(KFSConstants.CurrencyCoinSources.CASH_MANAGEMENT_OUT);
352
353 moneyOutCurrency.setDocumentNumber(this.referenceFinancialDocumentNumber);
354 moneyOutCurrency.setFinancialDocumentTypeCode(DETAIL_DOCUMENT_TYPE);
355 moneyOutCurrency.setCashieringRecordSource(KFSConstants.CurrencyCoinSources.CASH_MANAGEMENT_OUT);
356
357 newItemInProcess.setCampusCode(this.campusCode);
358 }
359
360 /**
361 * @see org.kuali.rice.kns.bo.BusinessObjectBase#toStringMapper()
362 */
363 @Override
364 protected LinkedHashMap toStringMapper() {
365 LinkedHashMap pkMap = new LinkedHashMap();
366 pkMap.put("campusCode", this.campusCode);
367 pkMap.put("referenceFinancialDocumentNumber", this.referenceFinancialDocumentNumber);
368 pkMap.put("transactionStarted", this.transactionStarted);
369 return pkMap;
370 }
371
372 /**
373 * Gets the checks attribute.
374 *
375 * @return Returns the checks.
376 */
377 public List getChecks() {
378 return getMoneyInChecks();
379 }
380
381 /**
382 * Sets the checks attribute value.
383 *
384 * @param checks The checks to set.
385 */
386 public void setChecks(List checks) {
387 moneyInChecks = new ArrayList<Check>();
388 for (Object o : checks) {
389 moneyInChecks.add((Check) o);
390 }
391 }
392
393 /**
394 * Gets the number of checks, since Sun doesn't have a direct getter for collection size
395 *
396 * @return the number of checks
397 */
398 public int getCheckCount() {
399 int count = 0;
400 if (moneyInChecks != null) {
401 count = moneyInChecks.size();
402 }
403 return count;
404 }
405
406
407 /**
408 * Adds a new check to the list.
409 *
410 * @param check
411 */
412 public void addCheck(Check check) {
413 check.setSequenceId(this.nextCheckSequenceId);
414
415 this.moneyInChecks.add(check);
416
417 this.nextCheckSequenceId = new Integer(this.nextCheckSequenceId.intValue() + 1);
418 }
419
420 /**
421 * Retrieve a particular check at a given index in the list of checks.
422 *
423 * @param index
424 * @return Check
425 */
426 public Check getCheck(int index) {
427 while (this.moneyInChecks.size() <= index) {
428 moneyInChecks.add(createNewCheck());
429 }
430 return (Check) moneyInChecks.get(index);
431 }
432
433 /**
434 * @param checks
435 * @return Map containing Checks from the given List, indexed by their sequenceId
436 */
437 private Map buildCheckMap(List checks) {
438 Map checkMap = new HashMap();
439
440 for (Iterator i = checks.iterator(); i.hasNext();) {
441 Check check = (Check) i.next();
442 Integer sequenceId = check.getSequenceId();
443
444 Object oldCheck = checkMap.put(sequenceId, check);
445
446 // verify that sequence numbers are unique...
447 if (oldCheck != null) {
448 throw new IllegalStateException("sequence id collision detected for sequence id " + sequenceId);
449 }
450 }
451
452 return checkMap;
453 }
454
455 /**
456 * This method removes a check from the list and updates the total appropriately.
457 *
458 * @param index
459 */
460 public void removeCheck(int index) {
461 Check check = (Check) moneyInChecks.remove(index);
462 KualiDecimal newTotalCheckAmount = getTotalCheckAmount().subtract(check.getAmount());
463 // if the totalCheckAmount goes negative, bring back to zero.
464 if (newTotalCheckAmount.isNegative()) {
465 newTotalCheckAmount = KualiDecimal.ZERO;
466 }
467 }
468
469 public KualiDecimal getTotalCheckAmount() {
470 KualiDecimal result = KualiDecimal.ZERO;
471 for (Check c : moneyInChecks) {
472 if (c != null && c.getAmount() != null) {
473 result = result.add(c.getAmount());
474 }
475 }
476 return result;
477 }
478
479 /**
480 * Gets the nextCheckSequenceId attribute.
481 *
482 * @return Returns the nextCheckSequenceId.
483 */
484 public Integer getNextCheckSequenceId() {
485 return nextCheckSequenceId;
486 }
487
488 /**
489 * Sets the nextCheckSequenceId attribute value.
490 *
491 * @param nextCheckSequenceId The nextCheckSequenceId to set.
492 */
493 public void setNextCheckSequenceId(Integer nextCheckSequenceId) {
494 this.nextCheckSequenceId = nextCheckSequenceId;
495 }
496
497 public Check createNewCheck() {
498 Check newCheck = new CheckBase();
499 newCheck.setFinancialDocumentTypeCode(DETAIL_DOCUMENT_TYPE);
500 newCheck.setCashieringRecordSource(KFSConstants.CheckSources.CASH_MANAGEMENT);
501 return newCheck;
502 }
503
504 /**
505 * This method calculates how much money has been paid back in all items in process
506 *
507 * @return the calculated amount
508 */
509 public KualiDecimal getPaidBackItemsInProcessAmount() {
510 KualiDecimal amount = KualiDecimal.ZERO;
511 if (this.openItemsInProcess != null) {
512 for (CashieringItemInProcess itemInProcess : this.openItemsInProcess) {
513 if (itemInProcess.getCurrentPayment() != null && itemInProcess.getCurrentPayment().isGreaterThan(KualiDecimal.ZERO)) {
514 amount = amount.add(itemInProcess.getCurrentPayment());
515 }
516 }
517 }
518 return amount;
519 }
520
521 /**
522 * @return current List of baseline checks for use in update detection
523 */
524 public List getBaselineChecks() {
525 return baselineChecks;
526 }
527
528 /**
529 * Sets the current List of baseline checks to the given List
530 *
531 * @param baselineChecks
532 */
533 public void setBaselineChecks(List baselineChecks) {
534 this.baselineChecks = baselineChecks;
535 }
536
537 /**
538 * @param index
539 * @return true if a baselineCheck with the given index exists
540 */
541 public boolean hasBaselineCheck(int index) {
542 boolean has = false;
543
544 if ((index >= 0) && (index <= baselineChecks.size())) {
545 has = true;
546 }
547
548 return has;
549 }
550
551 /**
552 * Implementation creates empty Checks as a side-effect, so that Struts' efforts to set fields of lines which haven't been
553 * created will succeed rather than causing a NullPointerException.
554 *
555 * @param index
556 * @return baseline Check at the given index
557 */
558 public Check getBaselineCheck(int index) {
559 while (baselineChecks.size() <= index) {
560 baselineChecks.add(this.createNewCheck());
561 }
562 return (Check) baselineChecks.get(index);
563 }
564
565 /**
566 * This method calcuates how much money has come in to the "Money In" side of the transaction
567 *
568 * @return the amount calculated
569 */
570 public KualiDecimal getMoneyInTotal() {
571 KualiDecimal result = KualiDecimal.ZERO;
572 result = result.add(this.moneyInCurrency.getTotalAmount());
573 result = result.add(this.moneyInCoin.getTotalAmount());
574 result = result.add(this.getTotalCheckAmount());
575 if (this.newItemInProcess.isPopulated()) {
576 result = result.add(this.newItemInProcess.getItemAmount());
577 }
578 return result;
579 }
580
581 /**
582 * This method calculates how much money has gone out through the "Money Out" side of the transaction
583 *
584 * @return the amount calculated
585 */
586 public KualiDecimal getMoneyOutTotal() {
587 KualiDecimal result = KualiDecimal.ZERO;
588 result = result.add(this.moneyOutCurrency.getTotalAmount());
589 result = result.add(this.moneyOutCoin.getTotalAmount());
590 result = result.add(this.getPaidBackItemsInProcessAmount());
591 return result;
592 }
593
594 /**
595 * @param checkTotal
596 * @deprecated
597 */
598 public void setCheckTotal(KualiDecimal checkTotal) {
599 this.checkTotal = checkTotal;
600 }
601
602 }