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.document.web.struts;
017
018 import java.util.ArrayList;
019 import java.util.HashMap;
020 import java.util.Iterator;
021 import java.util.List;
022 import java.util.Map;
023 import java.util.Properties;
024 import java.util.Set;
025
026 import java.sql.Date;
027 import java.sql.Timestamp;
028 import org.kuali.rice.kns.service.DateTimeService;
029
030 import javax.servlet.http.HttpServletRequest;
031 import javax.servlet.http.HttpServletResponse;
032
033 import org.apache.commons.lang.StringUtils;
034 import org.apache.struts.action.ActionForm;
035 import org.apache.struts.action.ActionForward;
036 import org.apache.struts.action.ActionMapping;
037 import org.kuali.kfs.fp.businessobject.CashDrawer;
038 import org.kuali.kfs.fp.businessobject.CashieringTransaction;
039 import org.kuali.kfs.fp.businessobject.Check;
040 import org.kuali.kfs.fp.businessobject.CoinDetail;
041 import org.kuali.kfs.fp.businessobject.CurrencyDetail;
042 import org.kuali.kfs.fp.businessobject.Deposit;
043 import org.kuali.kfs.fp.businessobject.DepositWizardCashieringCheckHelper;
044 import org.kuali.kfs.fp.businessobject.DepositWizardHelper;
045 import org.kuali.kfs.fp.businessobject.format.CashDrawerStatusCodeFormatter;
046 import org.kuali.kfs.fp.document.CashManagementDocument;
047 import org.kuali.kfs.fp.document.CashReceiptDocument;
048 import org.kuali.kfs.fp.document.service.CashManagementService;
049 import org.kuali.kfs.fp.document.service.CashReceiptService;
050 import org.kuali.kfs.fp.exception.CashDrawerStateException;
051 import org.kuali.kfs.fp.service.CashDrawerService;
052 import org.kuali.kfs.sys.KFSConstants;
053 import org.kuali.kfs.sys.KFSKeyConstants;
054 import org.kuali.kfs.sys.KFSPropertyConstants;
055 import org.kuali.kfs.sys.KFSConstants.CashDrawerConstants;
056 import org.kuali.kfs.sys.KFSConstants.DocumentStatusCodes.CashReceipt;
057 import org.kuali.kfs.sys.businessobject.Bank;
058 import org.kuali.kfs.sys.context.SpringContext;
059 import org.kuali.kfs.sys.document.datadictionary.FinancialSystemTransactionalDocumentEntry;
060 import org.kuali.rice.kew.exception.WorkflowException;
061 import org.kuali.rice.kim.bo.Person;
062 import org.kuali.rice.kns.document.authorization.DocumentAuthorizer;
063 import org.kuali.rice.kns.document.authorization.TransactionalDocumentAuthorizer;
064 import org.kuali.rice.kns.document.authorization.TransactionalDocumentPresentationController;
065 import org.kuali.rice.kns.exception.InfrastructureException;
066 import org.kuali.rice.kns.service.BusinessObjectService;
067 import org.kuali.rice.kns.service.DataDictionaryService;
068 import org.kuali.rice.kns.service.DocumentHelperService;
069 import org.kuali.rice.kns.service.DocumentService;
070 import org.kuali.rice.kns.util.GlobalVariables;
071 import org.kuali.rice.kns.util.KNSConstants;
072 import org.kuali.rice.kns.util.KualiDecimal;
073 import org.kuali.rice.kns.util.UrlFactory;
074 import org.kuali.rice.kns.web.format.CurrencyFormatter;
075 import org.kuali.rice.kns.web.struts.action.KualiAction;
076
077 /**
078 * This class handles actions for the deposit wizard, which is used to create deposits that bundle groupings of Cash Receipt
079 * documents.
080 */
081 public class DepositWizardAction extends KualiAction {
082 private static final org.apache.log4j.Logger LOG = org.apache.log4j.Logger.getLogger(DepositWizardAction.class);
083 private static final String CASH_MANAGEMENT_STATUS_PAGE = "/cashManagementStatus.do";
084
085 /**
086 * Overrides the parent to validate the document state of the cashManagementDocument which will be updated and redisplayed after
087 * the DepositWizard builds and attaches the new Deposit.
088 *
089 * @see org.apache.struts.action.Action#execute(org.apache.struts.action.ActionMapping, org.apache.struts.action.ActionForm,
090 * javax.servlet.http.HttpServletRequest, javax.servlet.http.HttpServletResponse)
091 */
092 @Override
093 public ActionForward execute(ActionMapping mapping, ActionForm form, HttpServletRequest request, HttpServletResponse response) throws Exception {
094 DepositWizardForm dwForm = (DepositWizardForm) form;
095
096 ActionForward dest = super.execute(mapping, form, request, response);
097
098 // check authorization manually, since the auth-check isn't inherited by this class
099 DocumentAuthorizer cmDocAuthorizer = SpringContext.getBean(DocumentHelperService.class).getDocumentAuthorizer(KFSConstants.FinancialDocumentTypeCodes.CASH_MANAGEMENT);
100 Person luser = GlobalVariables.getUserSession().getPerson();
101 cmDocAuthorizer.canInitiate(KFSConstants.FinancialDocumentTypeCodes.CASH_MANAGEMENT, luser);
102
103 // populate the outgoing form used by the JSP if it seems empty
104 String cmDocId = dwForm.getCashManagementDocId();
105 if (StringUtils.isBlank(cmDocId)) {
106 cmDocId = request.getParameter("cmDocId");
107 String depositTypeCode = request.getParameter("depositTypeCode");
108
109 CashManagementDocument cmDoc = (CashManagementDocument) SpringContext.getBean(DocumentService.class).getByDocumentHeaderId(cmDocId);
110
111 try {
112 initializeForm(dwForm, cmDoc, depositTypeCode);
113 }
114 catch (CashDrawerStateException cdse) {
115 dest = new ActionForward(UrlFactory.parameterizeUrl(CASH_MANAGEMENT_STATUS_PAGE, cdse.toProperties()), true);
116 }
117 }
118
119 return dest;
120 }
121
122 /**
123 * Initializes the given form using the given values
124 *
125 * @param dform
126 * @param cmDoc
127 * @param depositTypeCode
128 */
129 private void initializeForm(DepositWizardForm dform, CashManagementDocument cmDoc, String depositTypeCode) {
130 CashDrawer cd = SpringContext.getBean(CashDrawerService.class).getByCampusCode(cmDoc.getCampusCode());
131 if (cd == null) {
132 throw new RuntimeException("No cash drawer exists for campus code "+cmDoc.getCampusCode()+"; please create on via the Cash Drawer Maintenance Document before attemping to create a CashManagementDocument for campus "+cmDoc.getCampusCode());
133 }
134 if (!cd.isOpen()) {
135 CashDrawerStatusCodeFormatter f = new CashDrawerStatusCodeFormatter();
136
137 String cmDocId = cmDoc.getDocumentNumber();
138 String currentState = cd.getStatusCode();
139
140 throw new CashDrawerStateException(cmDoc.getCampusCode(), cmDocId, (String) f.format(CashDrawerConstants.STATUS_OPEN), (String) f.format(cd.getStatusCode()));
141 }
142
143 dform.setCashManagementDocId(cmDoc.getDocumentNumber());
144 dform.setCashDrawerCampusCode(cmDoc.getCampusCode());
145
146 dform.setDepositTypeCode(depositTypeCode);
147
148 if (depositTypeCode.equals(KFSConstants.DocumentStatusCodes.CashReceipt.FINAL)) {
149 // hey, we're the magical final deposit. We get currency and coin details!
150 CurrencyDetail currencyDetail = new CurrencyDetail();
151 currencyDetail.setDocumentNumber(cmDoc.getDocumentNumber());
152 currencyDetail.setCashieringRecordSource(KFSConstants.CurrencyCoinSources.DEPOSITS);
153 currencyDetail.setFinancialDocumentTypeCode(CashieringTransaction.DETAIL_DOCUMENT_TYPE);
154 dform.setCurrencyDetail(currencyDetail);
155
156 CoinDetail coinDetail = new CoinDetail();
157 coinDetail.setDocumentNumber(cmDoc.getDocumentNumber());
158 coinDetail.setCashieringRecordSource(KFSConstants.CurrencyCoinSources.DEPOSITS);
159 coinDetail.setFinancialDocumentTypeCode(CashieringTransaction.DETAIL_DOCUMENT_TYPE);
160 dform.setCoinDetail(coinDetail);
161 }
162
163 loadCashReceipts(dform);
164 loadUndepositedCashieringChecks(dform);
165 loadEditModesAndDocumentActions(dform);
166 }
167
168 /**
169 * Loads the CashReceipt information, re/setting the related form fields
170 *
171 * @param dform
172 */
173 private void loadCashReceipts(DepositWizardForm dform) {
174 List verifiedReceipts = SpringContext.getBean(CashReceiptService.class).getCashReceipts(dform.getCashDrawerCampusCode(), KFSConstants.DocumentStatusCodes.CashReceipt.VERIFIED);
175 dform.setDepositableCashReceipts(new ArrayList());
176 dform.setCheckFreeCashReceipts(new ArrayList<CashReceiptDocument>());
177
178 // prepopulate DepositWizardHelpers
179 int index = 0;
180 for (Iterator i = verifiedReceipts.iterator(); i.hasNext();) {
181 CashReceiptDocument receipt = (CashReceiptDocument) i.next();
182 if (receipt.getCheckCount() == 0 && receipt.getTotalCheckAmount().equals(KualiDecimal.ZERO)) {
183 dform.getCheckFreeCashReceipts().add(receipt);
184 }
185 else {
186 dform.getDepositableCashReceipts().add(receipt);
187 DepositWizardHelper d = dform.getDepositWizardHelper(index++);
188 //KFSMI-5232 Jira fix. Convert the time stamp to SQL date format
189 Timestamp ts = receipt.getDocumentHeader().getWorkflowDocument().getCreateDate();
190
191 try {
192 d.setCashReceiptCreateDate(SpringContext.getBean(DateTimeService.class).convertToSqlDate(ts));
193 } catch (Exception e) {
194
195 }
196 }
197 }
198 }
199
200 /**
201 * This loads any cashiering checks which have not yet been deposited into the DepositWizardForm
202 *
203 * @param dform a form to load undeposited checks into
204 */
205 private void loadUndepositedCashieringChecks(DepositWizardForm dform) {
206 List<Check> cashieringChecks = SpringContext.getBean(CashManagementService.class).selectUndepositedCashieringChecks(dform.getCashManagementDocId());
207 dform.setDepositableCashieringChecks(cashieringChecks);
208 }
209
210 private void loadEditModesAndDocumentActions(DepositWizardForm dform) {
211 final FinancialSystemTransactionalDocumentEntry ddEntry = getCashManagementDataDictionaryEntry();
212 final TransactionalDocumentPresentationController presentationController = getCashManagementPresentationController(ddEntry);
213 final TransactionalDocumentAuthorizer docAuthorizer = getCashManagementDocumentAuthorizer(ddEntry);
214
215 dform.setEditingMode(retrieveEditingModes(dform.getCashManagementDocId(), presentationController, docAuthorizer));
216 dform.setDocumentActions(retrieveDocumentActions(dform.getCashManagementDocId(), presentationController, docAuthorizer));
217 }
218
219 /**
220 * @return the class of the cash management document
221 */
222 protected String getCashManagementDocumentTypeName() {
223 return "CMD";
224 }
225
226 /**
227 * @return the data dictionary entry for the cash management class
228 */
229 private FinancialSystemTransactionalDocumentEntry getCashManagementDataDictionaryEntry() {
230 final DataDictionaryService ddService = SpringContext.getBean(DataDictionaryService.class);
231 return (FinancialSystemTransactionalDocumentEntry)ddService.getDataDictionary().getDocumentEntry(getCashManagementDocumentTypeName());
232 }
233
234 /**
235 * Returns an instance of the document presentation controller for the cash management class
236 * @param cashManagementEntry the data dictionary entry for the cash management document
237 * @return an instance of the proper document presentation controller
238 */
239 private TransactionalDocumentPresentationController getCashManagementPresentationController(FinancialSystemTransactionalDocumentEntry cashManagementEntry) {
240 final Class presentationControllerClass = cashManagementEntry.getDocumentPresentationControllerClass();
241 TransactionalDocumentPresentationController presentationController = null;
242 try {
243 presentationController = (TransactionalDocumentPresentationController)presentationControllerClass.newInstance();
244 }
245 catch (InstantiationException ie) {
246 throw new RuntimeException("Could not instantiate cash management presentation controller of class "+presentationControllerClass.getName(), ie);
247 }
248 catch (IllegalAccessException iae) {
249 throw new RuntimeException("Could not instantiate cash management presentation controller of class "+presentationControllerClass.getName(), iae);
250 }
251 return presentationController;
252 }
253
254 /**
255 * Returns an instance of the document authorizer for the cash management class
256 * @param cashManagementEntry the data dictionary entry for the cash management document
257 * @return an instance of the proper document authorizer
258 */
259 private TransactionalDocumentAuthorizer getCashManagementDocumentAuthorizer(FinancialSystemTransactionalDocumentEntry cashManagementEntry) {
260 final Class docAuthorizerClass = cashManagementEntry.getDocumentAuthorizerClass();
261 TransactionalDocumentAuthorizer docAuthorizer = null;
262 try {
263 docAuthorizer = (TransactionalDocumentAuthorizer)docAuthorizerClass.newInstance();
264 }
265 catch (InstantiationException ie) {
266 throw new RuntimeException("Could not instantiate cash management document authorizer of class "+docAuthorizerClass.getName(), ie);
267 }
268 catch (IllegalAccessException iae) {
269 throw new RuntimeException("Could not instantiate cash management document authorizer of class "+docAuthorizerClass.getName(), iae);
270 }
271 return docAuthorizer;
272 }
273
274 /**
275 * Retrieves the edit modes for the given cash management document
276 * @param cashManagementDocId the id of the cash management document to check
277 * @param presentationController the presentation controller of the cash management document
278 * @param docAuthorizer the cash management document authorizer
279 * @return a Map of edit modes
280 */
281 private Map retrieveEditingModes(String cashManagementDocId, TransactionalDocumentPresentationController presentationController, TransactionalDocumentAuthorizer docAuthorizer) {
282 Map editModeMap = null;
283 try {
284 final CashManagementDocument cmDoc = (CashManagementDocument)SpringContext.getBean(DocumentService.class).getByDocumentHeaderId(cashManagementDocId);
285 Set<String> editModes = presentationController.getEditModes(cmDoc);
286 editModes = docAuthorizer.getEditModes(cmDoc, GlobalVariables.getUserSession().getPerson(), editModes);
287 editModeMap = convertSetToMap(editModes);
288 }
289 catch (WorkflowException we) {
290 throw new RuntimeException("Workflow exception while retrieving document "+cashManagementDocId, we);
291 }
292 return editModeMap;
293 }
294
295 /**
296 * Retrieves the document actions for the given cash management document
297 * @param cashManagementDocId the id of the cash management document to check
298 * @param presentationController the presentation controller of the cash management document
299 * @param docAuthorizer the cash management document authorizer
300 * @return a Map of document actions
301 */
302 private Map retrieveDocumentActions(String cashManagementDocId, TransactionalDocumentPresentationController presentationController, TransactionalDocumentAuthorizer docAuthorizer) {
303 Map documentActionsMap = null;
304 try {
305 final CashManagementDocument cmDoc = (CashManagementDocument)SpringContext.getBean(DocumentService.class).getByDocumentHeaderId(cashManagementDocId);
306 Set<String> documentActions = presentationController.getDocumentActions(cmDoc);
307 documentActions = docAuthorizer.getEditModes(cmDoc, GlobalVariables.getUserSession().getPerson(), documentActions);
308 documentActionsMap = convertSetToMap(documentActions);
309 }
310 catch (WorkflowException we) {
311 throw new RuntimeException("Workflow exception while retrieving document "+cashManagementDocId, we);
312 }
313 return documentActionsMap;
314 }
315
316 /**
317 * Converts a set into a map, where each value in the set becomes a key and each value becomes KNSConstants.KUALI_DEFAULT_TRUE_VALUE
318 * @param s a set
319 * @return a map
320 */
321 protected Map convertSetToMap(Set s){
322 Map map = new HashMap();
323 Iterator i = s.iterator();
324 while(i.hasNext()) {
325 Object key = i.next();
326 map.put(key,KNSConstants.KUALI_DEFAULT_TRUE_VALUE);
327 }
328 return map;
329 }
330
331 /**
332 * Reloads the CashReceipts, leaving everything else unchanged
333 *
334 * @see org.kuali.rice.kns.web.struts.action.KualiAction#refresh(org.apache.struts.action.ActionMapping,
335 * org.apache.struts.action.ActionForm, javax.servlet.http.HttpServletRequest, javax.servlet.http.HttpServletResponse)
336 */
337 @Override
338 public ActionForward refresh(ActionMapping mapping, ActionForm form, HttpServletRequest request, HttpServletResponse response) throws Exception {
339 loadCashReceipts((DepositWizardForm) form);
340 loadUndepositedCashieringChecks((DepositWizardForm) form);
341 loadEditModesAndDocumentActions((DepositWizardForm) form);
342
343 return super.refresh(mapping, form, request, response);
344 }
345
346 /**
347 * This method is the starting point for the deposit document wizard.
348 *
349 * @param mapping
350 * @param form
351 * @param request
352 * @param response
353 * @return ActionForward
354 * @throws Exception
355 */
356 public ActionForward startWizard(ActionMapping mapping, ActionForm form, HttpServletRequest request, HttpServletResponse response) throws Exception {
357 return mapping.findForward(KFSConstants.MAPPING_BASIC);
358 }
359
360 /**
361 * This method is the action method for creating the new deposit document from the information chosen by the user in the UI.
362 *
363 * @param mapping
364 * @param form
365 * @param request
366 * @param response
367 * @return ActionForward
368 */
369 public ActionForward createDeposit(ActionMapping mapping, ActionForm form, HttpServletRequest request, HttpServletResponse response) {
370 ActionForward dest = mapping.findForward(KFSConstants.MAPPING_BASIC);
371
372 DepositWizardForm dform = (DepositWizardForm) form;
373 final BusinessObjectService boService = SpringContext.getBean(BusinessObjectService.class);
374 final CashReceiptService cashReceiptService = SpringContext.getBean(CashReceiptService.class);
375 final DocumentService documentService = SpringContext.getBean(DocumentService.class);
376 final CashManagementService cashManagementService = SpringContext.getBean(CashManagementService.class);
377
378 CurrencyFormatter formatter = new CurrencyFormatter();
379
380 // reload edit modes - just in case we have to return to the deposit wizard page
381 loadEditModesAndDocumentActions(dform);
382
383 // validate Bank
384 String bankCode = dform.getBankCode();
385 if (StringUtils.isBlank(bankCode)) {
386 GlobalVariables.getMessageMap().putError(KFSConstants.DepositConstants.DEPOSIT_WIZARD_DEPOSITHEADER_ERROR, KFSKeyConstants.Deposit.ERROR_MISSING_BANK);
387 }
388 else {
389 Map keyMap = new HashMap();
390 keyMap.put(KFSPropertyConstants.BANK_CODE, bankCode);
391
392 Bank bank = (Bank) boService.findByPrimaryKey(Bank.class, keyMap);
393 if (bank == null) {
394 GlobalVariables.getMessageMap().putError(KFSConstants.DepositConstants.DEPOSIT_WIZARD_DEPOSITHEADER_ERROR, KFSKeyConstants.Deposit.ERROR_UNKNOWN_BANK, bankCode);
395 }
396 else {
397 dform.setBank(bank);
398 }
399 }
400
401 boolean depositIsFinal = (StringUtils.equals(dform.getDepositTypeCode(), KFSConstants.DepositConstants.DEPOSIT_TYPE_FINAL));
402
403 // validate cashReceipt selection
404 List selectedIds = new ArrayList();
405 for (Iterator i = dform.getDepositWizardHelpers().iterator(); i.hasNext();) {
406 String checkValue = ((DepositWizardHelper) i.next()).getSelectedValue();
407
408 if (StringUtils.isNotBlank(checkValue) && !checkValue.equals(KFSConstants.ParameterValues.NO)) {
409 // removed apparently-unnecessary test for !checkValue.equals(KFSConstants.ParameterValues.YES)
410 selectedIds.add(checkValue);
411 }
412 }
413
414 if (depositIsFinal) {
415 // add check free cash receipts to the selected receipts so they are automatically deposited
416 dform.setCheckFreeCashReceipts(new ArrayList<CashReceiptDocument>());
417 for (Object crDocObj : cashReceiptService.getCashReceipts(dform.getCashDrawerCampusCode(), KFSConstants.DocumentStatusCodes.CashReceipt.VERIFIED)) {
418 CashReceiptDocument crDoc = (CashReceiptDocument) crDocObj;
419 if (crDoc.getCheckCount() == 0) {
420 // it's check free; it is automatically deposited as part of the final deposit
421 selectedIds.add(crDoc.getDocumentNumber());
422 dform.getCheckFreeCashReceipts().add(crDoc);
423 }
424 }
425 }
426
427 // make a list of cashiering checks to deposit
428 List<Integer> selectedCashieringChecks = new ArrayList<Integer>();
429 for (DepositWizardCashieringCheckHelper helper : dform.getDepositWizardCashieringCheckHelpers()) {
430 if (helper.getSequenceId() != null && !helper.getSequenceId().equals(new Integer(-1))) {
431 selectedCashieringChecks.add(helper.getSequenceId());
432 }
433 }
434
435 if (selectedIds.isEmpty() && selectedCashieringChecks.isEmpty()) {
436 GlobalVariables.getMessageMap().putError(KFSConstants.DepositConstants.DEPOSIT_WIZARD_CASHRECEIPT_ERROR, KFSKeyConstants.Deposit.ERROR_NO_CASH_RECEIPTS_SELECTED);
437 }
438
439 //
440 // proceed, if possible
441 if (GlobalVariables.getMessageMap().hasNoErrors()) {
442 try {
443 // retrieve selected receipts
444 List selectedReceipts = new ArrayList();
445 if (selectedIds != null && !selectedIds.isEmpty()) {
446 selectedReceipts = documentService.getDocumentsByListOfDocumentHeaderIds(CashReceiptDocument.class, selectedIds);
447 }
448
449 if (depositIsFinal) {
450 // have all verified CRs been deposited? If not, that's an error
451 List verifiedReceipts = cashReceiptService.getCashReceipts(dform.getCashDrawerCampusCode(), KFSConstants.DocumentStatusCodes.CashReceipt.VERIFIED);
452 for (Object o : verifiedReceipts) {
453 CashReceiptDocument crDoc = (CashReceiptDocument) o;
454 if (!selectedReceipts.contains(crDoc)) {
455 GlobalVariables.getMessageMap().putError(KFSConstants.DepositConstants.DEPOSIT_WIZARD_DEPOSITHEADER_ERROR, KFSKeyConstants.Deposit.ERROR_NON_DEPOSITED_VERIFIED_CASH_RECEIPT, new String[] { crDoc.getDocumentNumber() });
456 }
457 }
458 KualiDecimal toBeDepositedChecksTotal = KualiDecimal.ZERO;
459 // have we selected the rest of the undeposited checks?
460 for (Check check : cashManagementService.selectUndepositedCashieringChecks(dform.getCashManagementDocId())) {
461 if (!selectedCashieringChecks.contains(check.getSequenceId())) {
462 GlobalVariables.getMessageMap().putError(KFSConstants.DepositConstants.DEPOSIT_WIZARD_DEPOSITHEADER_ERROR, KFSKeyConstants.Deposit.ERROR_CASHIERING_CHECK_MUST_BE_DEPOSITED, new String[] { check.getCheckNumber() });
463 }
464 else {
465 toBeDepositedChecksTotal = toBeDepositedChecksTotal.add(check.getAmount());
466 }
467 }
468
469 // does the cash drawer have enough currency and coin to fulfill the requested deposit?
470 checkEnoughCurrencyForDeposit(dform);
471 checkEnoughCoinForDeposit(dform);
472
473 // does this deposit have currency and coin to match all currency and coin from CRs?
474 List<CashReceiptDocument> interestingReceipts = cashReceiptService.getCashReceipts(dform.getCashDrawerCampusCode(), new String[] { CashReceipt.VERIFIED, CashReceipt.INTERIM, CashReceipt.FINAL });
475 CurrencyDetail currencyTotal = new CurrencyDetail();
476 CoinDetail coinTotal = new CoinDetail();
477 for (CashReceiptDocument receipt : interestingReceipts) {
478 receipt.refreshCashDetails();
479 if (receipt.getCurrencyDetail() != null) {
480 currencyTotal.add(receipt.getCurrencyDetail());
481 }
482 if (receipt.getCoinDetail() != null) {
483 coinTotal.add(receipt.getCoinDetail());
484 }
485 }
486
487 KualiDecimal cashReceiptCashTotal = currencyTotal.getTotalAmount().add(coinTotal.getTotalAmount());
488 KualiDecimal depositedCashieringChecksTotal = cashManagementService.calculateDepositedCheckTotal(dform.getCashManagementDocId());
489 // remove the cashiering checks amounts from the cash receipts total; cashiering checks act as if they were CR
490 // currency/coin that gets deposited
491 cashReceiptCashTotal = cashReceiptCashTotal.subtract(depositedCashieringChecksTotal).subtract(toBeDepositedChecksTotal);
492 KualiDecimal depositedCashTotal = dform.getCurrencyDetail().getTotalAmount().add(dform.getCoinDetail().getTotalAmount());
493 if (!cashReceiptCashTotal.equals(depositedCashTotal)) {
494 GlobalVariables.getMessageMap().putError(KFSConstants.DepositConstants.DEPOSIT_WIZARD_DEPOSITHEADER_ERROR, KFSKeyConstants.Deposit.ERROR_CASH_DEPOSIT_DID_NOT_BALANCE, new String[] { formatter.format(depositedCashTotal).toString(), formatter.format(cashReceiptCashTotal).toString() });
495 }
496 }
497
498 // proceed again...if possible
499 if (GlobalVariables.getMessageMap().hasNoErrors()) {
500 // retrieve CashManagementDocument
501 String cashManagementDocId = dform.getCashManagementDocId();
502 CashManagementDocument cashManagementDoc = null;
503 try {
504 cashManagementDoc = (CashManagementDocument) documentService.getByDocumentHeaderId(cashManagementDocId);
505 if (cashManagementDoc == null) {
506 throw new IllegalStateException("unable to find cashManagementDocument with id " + cashManagementDocId);
507 }
508 }
509 catch (WorkflowException e) {
510 throw new IllegalStateException("unable to retrieve cashManagementDocument with id " + cashManagementDocId, e);
511 }
512
513 // create deposit
514 String cmDocId = dform.getCashManagementDocId();
515
516 cashManagementService.addDeposit(cashManagementDoc, dform.getDepositTicketNumber(), dform.getBank(), selectedReceipts, selectedCashieringChecks, depositIsFinal);
517
518 if (depositIsFinal) {
519 // find the final deposit
520 Deposit finalDeposit = findFinalDeposit(cashManagementDoc);
521 // if the currency and coin details aren't empty, save them and remove them from the cash drawer
522 if (dform.getCurrencyDetail() != null) {
523 // do we have enough currency to allow the deposit to leave the drawer?
524 boService.save(dform.getCurrencyDetail());
525 cashManagementDoc.getCashDrawer().removeCurrency(dform.getCurrencyDetail());
526 finalDeposit.setDepositAmount(finalDeposit.getDepositAmount().add(dform.getCurrencyDetail().getTotalAmount()));
527 }
528 if (dform.getCoinDetail() != null) {
529 // do we have enough coin to allow the deposit to leave the drawer?
530 boService.save(dform.getCoinDetail());
531 cashManagementDoc.getCashDrawer().removeCoin(dform.getCoinDetail());
532 finalDeposit.setDepositAmount(finalDeposit.getDepositAmount().add(dform.getCoinDetail().getTotalAmount()));
533 }
534 boService.save(cashManagementDoc.getCashDrawer());
535 boService.save(finalDeposit);
536 }
537
538 // redirect to controlling CashManagementDocument
539 dest = returnToSender(cashManagementDocId);
540 }
541 }
542 catch (WorkflowException e) {
543 throw new InfrastructureException("unable to retrieve cashReceipts by documentId", e);
544 }
545 }
546
547 return dest;
548 }
549
550 private Deposit findFinalDeposit(CashManagementDocument cmDoc) {
551 Deposit finalDeposit = null;
552 for (Deposit deposit : cmDoc.getDeposits()) {
553 if (deposit.getDepositTypeCode().equals(KFSConstants.DepositConstants.DEPOSIT_TYPE_FINAL)) {
554 finalDeposit = deposit;
555 break;
556 }
557 }
558 return finalDeposit;
559 }
560
561 /**
562 * Checks that the currency amount requested to be part of a deposit can be fulfilled by the amount of currency in the cash
563 * drawer
564 *
565 * @param depositForm the deposit form we are checking against
566 * @param detail the currency detail to check against the drawer
567 * @return true if enough currency, false if otherwise
568 */
569 private boolean checkEnoughCurrencyForDeposit(DepositWizardForm depositForm) {
570 boolean success = true;
571 CurrencyDetail detail = depositForm.getCurrencyDetail();
572 if (detail != null) {
573 // 1. get the cash drawer
574 CashDrawer drawer = SpringContext.getBean(CashDrawerService.class).getByCampusCode(depositForm.getCashDrawerCampusCode());
575 // assumptions at this point:
576 // 1. a cash drawer does exist for the unit
577 // 2. we can ignore negative amounts, because if we have negative amounts, we're actually gaining money (and that will
578 // happen with cashiering checks)
579 CurrencyFormatter formatter = new CurrencyFormatter();
580 if (detail.getFinancialDocumentHundredDollarAmount() != null && detail.getFinancialDocumentHundredDollarAmount().isGreaterThan(KualiDecimal.ZERO)) {
581 if (drawer.getFinancialDocumentHundredDollarAmount() == null || drawer.getFinancialDocumentHundredDollarAmount().isLessThan(detail.getFinancialDocumentHundredDollarAmount())) {
582 GlobalVariables.getMessageMap().putError(KFSConstants.DepositConstants.DEPOSIT_WIZARD_DEPOSITHEADER_ERROR, KFSKeyConstants.Deposit.ERROR_NOT_ENOUGH_CASH_TO_COMPLETE_DEPOSIT, new String[] { "hundred dollar amount", formatter.format(detail.getFinancialDocumentHundredDollarAmount()).toString(), formatter.format(drawer.getFinancialDocumentHundredDollarAmount()).toString() });
583 success = false;
584 }
585 }
586 if (detail.getFinancialDocumentFiftyDollarAmount() != null && detail.getFinancialDocumentFiftyDollarAmount().isGreaterThan(KualiDecimal.ZERO)) {
587 if (drawer.getFinancialDocumentFiftyDollarAmount() == null || drawer.getFinancialDocumentFiftyDollarAmount().isLessThan(detail.getFinancialDocumentFiftyDollarAmount())) {
588 GlobalVariables.getMessageMap().putError(KFSConstants.DepositConstants.DEPOSIT_WIZARD_DEPOSITHEADER_ERROR, KFSKeyConstants.Deposit.ERROR_NOT_ENOUGH_CASH_TO_COMPLETE_DEPOSIT, new String[] { "fifty dollar amount", formatter.format(detail.getFinancialDocumentFiftyDollarAmount()).toString(), formatter.format(drawer.getFinancialDocumentFiftyDollarAmount()).toString() });
589 success = false;
590 }
591 }
592 if (detail.getFinancialDocumentTwentyDollarAmount() != null && detail.getFinancialDocumentTwentyDollarAmount().isGreaterThan(KualiDecimal.ZERO)) {
593 if (drawer.getFinancialDocumentTwentyDollarAmount() == null || drawer.getFinancialDocumentTwentyDollarAmount().isLessThan(detail.getFinancialDocumentTwentyDollarAmount())) {
594 GlobalVariables.getMessageMap().putError(KFSConstants.DepositConstants.DEPOSIT_WIZARD_DEPOSITHEADER_ERROR, KFSKeyConstants.Deposit.ERROR_NOT_ENOUGH_CASH_TO_COMPLETE_DEPOSIT, new String[] { "twenty dollar amount", formatter.format(detail.getFinancialDocumentTwentyDollarAmount()).toString(), formatter.format(drawer.getFinancialDocumentTwentyDollarAmount()).toString() });
595 success = false;
596 }
597 }
598 if (detail.getFinancialDocumentTenDollarAmount() != null && detail.getFinancialDocumentTenDollarAmount().isGreaterThan(KualiDecimal.ZERO)) {
599 if (drawer.getFinancialDocumentTenDollarAmount() == null || drawer.getFinancialDocumentTenDollarAmount().isLessThan(detail.getFinancialDocumentTenDollarAmount())) {
600 GlobalVariables.getMessageMap().putError(KFSConstants.DepositConstants.DEPOSIT_WIZARD_DEPOSITHEADER_ERROR, KFSKeyConstants.Deposit.ERROR_NOT_ENOUGH_CASH_TO_COMPLETE_DEPOSIT, new String[] { "ten dollar amount", formatter.format(detail.getFinancialDocumentTenDollarAmount()).toString(), formatter.format(drawer.getFinancialDocumentTenDollarAmount()).toString() });
601 success = false;
602 }
603 }
604 if (detail.getFinancialDocumentFiveDollarAmount() != null && detail.getFinancialDocumentFiveDollarAmount().isGreaterThan(KualiDecimal.ZERO)) {
605 if (drawer.getFinancialDocumentFiveDollarAmount() == null || drawer.getFinancialDocumentFiveDollarAmount().isLessThan(detail.getFinancialDocumentFiveDollarAmount())) {
606 GlobalVariables.getMessageMap().putError(KFSConstants.DepositConstants.DEPOSIT_WIZARD_DEPOSITHEADER_ERROR, KFSKeyConstants.Deposit.ERROR_NOT_ENOUGH_CASH_TO_COMPLETE_DEPOSIT, new String[] { "five dollar amount", formatter.format(detail.getFinancialDocumentFiveDollarAmount()).toString(), formatter.format(drawer.getFinancialDocumentFiveDollarAmount()).toString() });
607 success = false;
608 }
609 }
610 if (detail.getFinancialDocumentTwoDollarAmount() != null && detail.getFinancialDocumentTwoDollarAmount().isGreaterThan(KualiDecimal.ZERO)) {
611 if (drawer.getFinancialDocumentTwoDollarAmount() == null || drawer.getFinancialDocumentTwoDollarAmount().isLessThan(detail.getFinancialDocumentTwoDollarAmount())) {
612 GlobalVariables.getMessageMap().putError(KFSConstants.DepositConstants.DEPOSIT_WIZARD_DEPOSITHEADER_ERROR, KFSKeyConstants.Deposit.ERROR_NOT_ENOUGH_CASH_TO_COMPLETE_DEPOSIT, new String[] { "two dollar amount", formatter.format(detail.getFinancialDocumentTwoDollarAmount()).toString(), formatter.format(drawer.getFinancialDocumentTwoDollarAmount()).toString() });
613 success = false;
614 }
615 }
616 if (detail.getFinancialDocumentOneDollarAmount() != null && detail.getFinancialDocumentOneDollarAmount().isGreaterThan(KualiDecimal.ZERO)) {
617 if (drawer.getFinancialDocumentOneDollarAmount() == null || drawer.getFinancialDocumentOneDollarAmount().isLessThan(detail.getFinancialDocumentOneDollarAmount())) {
618 GlobalVariables.getMessageMap().putError(KFSConstants.DepositConstants.DEPOSIT_WIZARD_DEPOSITHEADER_ERROR, KFSKeyConstants.Deposit.ERROR_NOT_ENOUGH_CASH_TO_COMPLETE_DEPOSIT, new String[] { "one dollar amount", formatter.format(detail.getFinancialDocumentOneDollarAmount()).toString(), formatter.format(drawer.getFinancialDocumentOneDollarAmount()).toString() });
619 success = false;
620 }
621 }
622 if (detail.getFinancialDocumentOtherDollarAmount() != null && detail.getFinancialDocumentOtherDollarAmount().isGreaterThan(KualiDecimal.ZERO)) {
623 if (drawer.getFinancialDocumentOtherDollarAmount() == null || drawer.getFinancialDocumentOtherDollarAmount().isLessThan(detail.getFinancialDocumentOtherDollarAmount())) {
624 GlobalVariables.getMessageMap().putError(KFSConstants.DepositConstants.DEPOSIT_WIZARD_DEPOSITHEADER_ERROR, KFSKeyConstants.Deposit.ERROR_NOT_ENOUGH_CASH_TO_COMPLETE_DEPOSIT, new String[] { "other dollar amount", formatter.format(detail.getFinancialDocumentOtherDollarAmount()).toString(), formatter.format(drawer.getFinancialDocumentOtherDollarAmount()).toString() });
625 success = false;
626 }
627 }
628 }
629 return success;
630 }
631
632 /**
633 * Checks that the coin amount requested by the deposit does not exceed the amount actually in the drawer
634 *
635 * @param depositForm the deposit form we are checking against
636 * @param detail the coin detail to check against the drawer
637 * @return true if there is enough coin, false if otherwise
638 */
639 public boolean checkEnoughCoinForDeposit(DepositWizardForm depositForm) {
640 boolean success = true;
641 CoinDetail detail = depositForm.getCoinDetail();
642 if (detail != null) {
643 // 1. get the cash drawer
644 CashDrawer drawer = SpringContext.getBean(CashDrawerService.class).getByCampusCode(depositForm.getCashDrawerCampusCode());
645 // assumptions at this point:
646 // 1. a cash drawer does exist for the unit
647 // 2. we can ignore negative amounts, because if we have negative amounts, we're actually gaining money (and that will
648 // happen with cashiering checks)
649 CurrencyFormatter formatter = new CurrencyFormatter();
650 if (detail.getFinancialDocumentHundredCentAmount() != null && detail.getFinancialDocumentHundredCentAmount().isGreaterThan(KualiDecimal.ZERO)) {
651 if (drawer.getFinancialDocumentHundredCentAmount() == null || drawer.getFinancialDocumentHundredCentAmount().isLessThan(detail.getFinancialDocumentHundredCentAmount())) {
652 GlobalVariables.getMessageMap().putError(KFSConstants.DepositConstants.DEPOSIT_WIZARD_DEPOSITHEADER_ERROR, KFSKeyConstants.Deposit.ERROR_NOT_ENOUGH_CASH_TO_COMPLETE_DEPOSIT, new String[] { "hundred cent amount", formatter.format(detail.getFinancialDocumentHundredCentAmount()).toString(), formatter.format(drawer.getFinancialDocumentHundredCentAmount()).toString() });
653 success = false;
654 }
655 }
656 if (detail.getFinancialDocumentFiftyCentAmount() != null && detail.getFinancialDocumentFiftyCentAmount().isGreaterThan(KualiDecimal.ZERO)) {
657 if (drawer.getFinancialDocumentFiftyCentAmount() == null || drawer.getFinancialDocumentFiftyCentAmount().isLessThan(detail.getFinancialDocumentFiftyCentAmount())) {
658 GlobalVariables.getMessageMap().putError(KFSConstants.DepositConstants.DEPOSIT_WIZARD_DEPOSITHEADER_ERROR, KFSKeyConstants.Deposit.ERROR_NOT_ENOUGH_CASH_TO_COMPLETE_DEPOSIT, new String[] { "fifty cent amount", formatter.format(detail.getFinancialDocumentFiftyCentAmount()).toString(), formatter.format(drawer.getFinancialDocumentFiftyCentAmount()).toString() });
659 success = false;
660 }
661 }
662 if (detail.getFinancialDocumentTwentyFiveCentAmount() != null && detail.getFinancialDocumentTwentyFiveCentAmount().isGreaterThan(KualiDecimal.ZERO)) {
663 if (drawer.getFinancialDocumentTwentyFiveCentAmount() == null || drawer.getFinancialDocumentTwentyFiveCentAmount().isLessThan(detail.getFinancialDocumentTwentyFiveCentAmount())) {
664 GlobalVariables.getMessageMap().putError(KFSConstants.DepositConstants.DEPOSIT_WIZARD_DEPOSITHEADER_ERROR, KFSKeyConstants.Deposit.ERROR_NOT_ENOUGH_CASH_TO_COMPLETE_DEPOSIT, new String[] { "twenty five cent amount", formatter.format(detail.getFinancialDocumentTwentyFiveCentAmount()).toString(), formatter.format(drawer.getFinancialDocumentTwentyFiveCentAmount()).toString() });
665 success = false;
666 }
667 }
668 if (detail.getFinancialDocumentTenCentAmount() != null && detail.getFinancialDocumentTenCentAmount().isGreaterThan(KualiDecimal.ZERO)) {
669 if (drawer.getFinancialDocumentTenCentAmount() == null || drawer.getFinancialDocumentTenCentAmount().isLessThan(detail.getFinancialDocumentTenCentAmount())) {
670 GlobalVariables.getMessageMap().putError(KFSConstants.DepositConstants.DEPOSIT_WIZARD_DEPOSITHEADER_ERROR, KFSKeyConstants.Deposit.ERROR_NOT_ENOUGH_CASH_TO_COMPLETE_DEPOSIT, new String[] { "ten cent amount", formatter.format(detail.getFinancialDocumentTenCentAmount()).toString(), formatter.format(drawer.getFinancialDocumentTenCentAmount()).toString() });
671 success = false;
672 }
673 }
674 if (detail.getFinancialDocumentFiveCentAmount() != null && detail.getFinancialDocumentFiveCentAmount().isGreaterThan(KualiDecimal.ZERO)) {
675 if (drawer.getFinancialDocumentFiveCentAmount() == null || drawer.getFinancialDocumentFiveCentAmount().isLessThan(detail.getFinancialDocumentFiveCentAmount())) {
676 GlobalVariables.getMessageMap().putError(KFSConstants.DepositConstants.DEPOSIT_WIZARD_DEPOSITHEADER_ERROR, KFSKeyConstants.Deposit.ERROR_NOT_ENOUGH_CASH_TO_COMPLETE_DEPOSIT, new String[] { "five cent amount", formatter.format(detail.getFinancialDocumentFiveCentAmount()).toString(), formatter.format(drawer.getFinancialDocumentFiveCentAmount()).toString() });
677 success = false;
678 }
679 }
680 if (detail.getFinancialDocumentOneCentAmount() != null && detail.getFinancialDocumentOneCentAmount().isGreaterThan(KualiDecimal.ZERO)) {
681 if (drawer.getFinancialDocumentOneCentAmount() == null || drawer.getFinancialDocumentOneCentAmount().isLessThan(detail.getFinancialDocumentOneCentAmount())) {
682 GlobalVariables.getMessageMap().putError(KFSConstants.DepositConstants.DEPOSIT_WIZARD_DEPOSITHEADER_ERROR, KFSKeyConstants.Deposit.ERROR_NOT_ENOUGH_CASH_TO_COMPLETE_DEPOSIT, new String[] { "one cent amount", formatter.format(detail.getFinancialDocumentOneCentAmount()).toString(), formatter.format(drawer.getFinancialDocumentOneCentAmount()).toString() });
683 success = false;
684 }
685 }
686 if (detail.getFinancialDocumentOtherCentAmount() != null && detail.getFinancialDocumentOtherCentAmount().isGreaterThan(KualiDecimal.ZERO)) {
687 if (drawer.getFinancialDocumentOtherCentAmount() == null || drawer.getFinancialDocumentOtherCentAmount().isLessThan(detail.getFinancialDocumentOtherCentAmount())) {
688 GlobalVariables.getMessageMap().putError(KFSConstants.DepositConstants.DEPOSIT_WIZARD_DEPOSITHEADER_ERROR, KFSKeyConstants.Deposit.ERROR_NOT_ENOUGH_CASH_TO_COMPLETE_DEPOSIT, new String[] { "other cent amount", formatter.format(detail.getFinancialDocumentOtherCentAmount()).toString(), formatter.format(drawer.getFinancialDocumentOtherCentAmount()).toString() });
689 success = false;
690 }
691 }
692 }
693 return success;
694 }
695
696
697 /**
698 * This method handles canceling (closing) the deposit wizard.
699 *
700 * @param mapping
701 * @param form
702 * @param request
703 * @param response
704 * @return ActionForward
705 * @throws Exception
706 */
707 public ActionForward cancel(ActionMapping mapping, ActionForm form, HttpServletRequest request, HttpServletResponse response) throws Exception {
708 DepositWizardForm dform = (DepositWizardForm) form;
709
710 ActionForward dest = returnToSender(dform.getCashManagementDocId());
711 return dest;
712 }
713
714
715 /**
716 * @param cmDocId
717 * @return ActionForward which will redirect the user to the docSearchDisplay for the CashManagementDocument with the given
718 * documentId
719 */
720 private ActionForward returnToSender(String cmDocId) {
721 Properties params = new Properties();
722 params.setProperty("methodToCall", "docHandler");
723 params.setProperty("command", "displayDocSearchView");
724 params.setProperty("docId", cmDocId);
725
726 String cmActionUrl = UrlFactory.parameterizeUrl(KFSConstants.CASH_MANAGEMENT_DOCUMENT_ACTION, params);
727
728 return new ActionForward(cmActionUrl, true);
729 }
730 }
731