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