001/* 002 * Copyright 2006 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 */ 016package org.kuali.ole.fp.document.web.struts; 017 018import java.util.Map; 019import java.util.Properties; 020 021import javax.servlet.http.HttpServletRequest; 022import javax.servlet.http.HttpServletResponse; 023 024import org.apache.commons.lang.StringUtils; 025import org.apache.log4j.Logger; 026import org.apache.struts.action.ActionForm; 027import org.apache.struts.action.ActionForward; 028import org.apache.struts.action.ActionMapping; 029import org.kuali.ole.fp.businessobject.Check; 030import org.kuali.ole.fp.businessobject.Deposit; 031import org.kuali.ole.fp.document.CashManagementDocument; 032import org.kuali.ole.fp.document.service.CashManagementService; 033import org.kuali.ole.fp.document.service.CashReceiptService; 034import org.kuali.ole.fp.document.validation.event.AddCheckEvent; 035import org.kuali.ole.fp.document.validation.event.CashieringTransactionApplicationEventBase; 036import org.kuali.ole.fp.document.validation.event.DeleteCheckEvent; 037import org.kuali.ole.fp.document.web.struts.CashManagementForm.CashDrawerSummary; 038import org.kuali.ole.fp.exception.CashDrawerStateException; 039import org.kuali.ole.fp.service.CashDrawerService; 040import org.kuali.ole.sys.OLEConstants; 041import org.kuali.ole.sys.OLEConstants.CashDrawerConstants; 042import org.kuali.ole.sys.OLEConstants.DepositConstants; 043import org.kuali.ole.sys.OLEKeyConstants; 044import org.kuali.ole.sys.OLEKeyConstants.CashManagement; 045import org.kuali.ole.sys.OleAuthorizationConstants; 046import org.kuali.ole.sys.context.SpringContext; 047import org.kuali.rice.core.api.config.property.ConfigurationService; 048import org.kuali.rice.kew.api.WorkflowDocument; 049import org.kuali.rice.kew.api.exception.WorkflowException; 050import org.kuali.rice.kim.api.identity.Person; 051import org.kuali.rice.kns.util.KNSGlobalVariables; 052import org.kuali.rice.kns.web.struts.action.KualiTransactionalDocumentActionBase; 053import org.kuali.rice.kns.web.struts.form.KualiDocumentFormBase; 054import org.kuali.rice.krad.service.DocumentService; 055import org.kuali.rice.krad.service.KualiRuleService; 056import org.kuali.rice.krad.util.GlobalVariables; 057import org.kuali.rice.krad.util.UrlFactory; 058 059/** 060 * Action class for CashManagementForm 061 */ 062public class CashManagementAction extends KualiTransactionalDocumentActionBase { 063 protected static Logger LOG = Logger.getLogger(CashManagementAction.class); 064 protected static final String CASH_MANAGEMENT_STATUS_PAGE = "/cashManagementStatus.do"; 065 066 /** 067 * Default constructor 068 */ 069 public CashManagementAction() { 070 } 071 072 073 /** 074 * Overrides to call super, but also make sure the helpers are populated. 075 * 076 * @see org.kuali.rice.kns.web.struts.action.KualiDocumentActionBase#execute(org.apache.struts.action.ActionMapping, 077 * org.apache.struts.action.ActionForm, javax.servlet.http.HttpServletRequest, javax.servlet.http.HttpServletResponse) 078 */ 079 @Override 080 public ActionForward execute(ActionMapping mapping, ActionForm form, HttpServletRequest request, HttpServletResponse response) throws Exception { 081 ActionForward dest = null; 082 083 try { 084 dest = super.execute(mapping, form, request, response); 085 086 CashManagementForm cmf = (CashManagementForm) form; 087 cmf.populateDepositHelpers(); 088 WorkflowDocument kwd = cmf.getDocument().getDocumentHeader().getWorkflowDocument(); 089 if (kwd.isEnroute() || kwd.isFinal()) { 090 cmf.setCashDrawerSummary(null); 091 } 092 else { 093 if (cmf.getCashDrawerSummary() == null) { 094 cmf.populateCashDrawerSummary(); 095 } 096 } 097 // put any recently closed items in process in the form 098 cmf.setRecentlyClosedItemsInProcess(SpringContext.getBean(CashManagementService.class).getRecentlyClosedItemsInProcess(cmf.getCashManagementDocument())); 099 } catch (CashDrawerStateException cdse) { 100 dest = new ActionForward(UrlFactory.parameterizeUrl(CASH_MANAGEMENT_STATUS_PAGE, cdse.toProperties()), true); 101 } 102 103 return dest; 104 } 105 106 /** 107 * Overrides the default document-creation code to auto-save new documents upon creation: since creating a CMDoc changes the 108 * CashDrawer's state as a side-effect, we need all CMDocs to be docsearchable so that someone can relocate and use or cancel 109 * whatever the current CMDoc is. 110 * 111 * @param kualiDocumentFormBase 112 * @throws WorkflowException 113 */ 114 @Override 115 protected void createDocument(KualiDocumentFormBase kualiDocumentFormBase) throws WorkflowException { 116 Person user = GlobalVariables.getUserSession().getPerson(); 117 String campusCode = SpringContext.getBean(CashReceiptService.class).getCashReceiptVerificationUnitForUser(user); 118 119 String defaultDescription = SpringContext.getBean(ConfigurationService.class).getPropertyValueAsString(CashManagement.DEFAULT_DOCUMENT_DESCRIPTION); 120 defaultDescription = StringUtils.replace(defaultDescription, "{0}", campusCode); 121 defaultDescription = StringUtils.substring(defaultDescription, 0, 39); 122 123 // create doc 124 CashManagementDocument cmDoc = SpringContext.getBean(CashManagementService.class).createCashManagementDocument(campusCode, defaultDescription, null); 125 126 // update form 127 kualiDocumentFormBase.setDocument(cmDoc); 128 kualiDocumentFormBase.setDocTypeName(cmDoc.getDocumentHeader().getWorkflowDocument().getDocumentTypeName()); 129 } 130 131 /** 132 * @param mapping 133 * @param form 134 * @param request 135 * @param response 136 * @return ActionForward 137 * @throws Exception 138 */ 139 public ActionForward addInterimDeposit(ActionMapping mapping, ActionForm form, HttpServletRequest request, HttpServletResponse response) throws Exception { 140 CashManagementForm cmForm = (CashManagementForm) form; 141 CashManagementDocument cmDoc = cmForm.getCashManagementDocument(); 142 143 checkDepositAuthorization(cmForm, cmDoc); 144 145 String wizardUrl = buildDepositWizardUrl(cmDoc, DepositConstants.DEPOSIT_TYPE_INTERIM); 146 return new ActionForward(wizardUrl, true); 147 } 148 149 /** 150 * @param mapping 151 * @param form 152 * @param request 153 * @param response 154 * @return ActionForward 155 * @throws Exception 156 */ 157 public ActionForward addFinalDeposit(ActionMapping mapping, ActionForm form, HttpServletRequest request, HttpServletResponse response) throws Exception { 158 CashManagementForm cmForm = (CashManagementForm) form; 159 CashManagementDocument cmDoc = cmForm.getCashManagementDocument(); 160 161 checkDepositAuthorization(cmForm, cmDoc); 162 163 String wizardUrl = buildDepositWizardUrl(cmDoc, DepositConstants.DEPOSIT_TYPE_FINAL); 164 return new ActionForward(wizardUrl, true); 165 } 166 167 /** 168 * Throws a DocumentAuthorizationException if the current user is not authorized to add a deposit of the given type to the given 169 * document. 170 * 171 * @param cmDoc 172 * @param cmForm 173 */ 174 protected void checkDepositAuthorization(CashManagementForm cmForm, CashManagementDocument cmDoc) { 175 //deposits can only be added if the CashDrawer is open 176 if (!cmDoc.getCashDrawerStatus().equals(CashDrawerConstants.STATUS_OPEN)) { 177 throw new IllegalStateException("CashDrawer '" + cmDoc.getCampusCode() + "' must be open for deposits to be made"); 178 } 179 180 //verify user's ability to add a deposit 181 Map<String, String> documentActions = cmForm.getEditingMode(); 182 if (!documentActions.containsKey(OleAuthorizationConstants.CashManagementEditMode.ALLOW_ADDITIONAL_DEPOSITS)) { 183 throw buildAuthorizationException("add a deposit", cmDoc); 184 } 185 } 186 187 /** 188 * @param cmDoc 189 * @param depositTypeCode 190 * @return URL for passing control to the DepositWizard 191 */ 192 protected String buildDepositWizardUrl(CashManagementDocument cmDoc, String depositTypeCode) { 193 Properties params = new Properties(); 194 params.setProperty("methodToCall", "startWizard"); 195 params.setProperty("cmDocId", cmDoc.getDocumentNumber()); 196 params.setProperty("depositTypeCode", depositTypeCode); 197 198 String wizardActionUrl = UrlFactory.parameterizeUrl("depositWizard.do", params); 199 return wizardActionUrl; 200 } 201 202 203 /** 204 * @param mapping 205 * @param form 206 * @param request 207 * @param response 208 * @return ActionForward 209 * @throws Exception 210 */ 211 public ActionForward cancelDeposit(ActionMapping mapping, ActionForm form, HttpServletRequest request, HttpServletResponse response) throws Exception { 212 CashManagementForm cmForm = (CashManagementForm) form; 213 CashManagementDocument cmDoc = cmForm.getCashManagementDocument(); 214 215 // validate cancelability 216 int depositIndex = getSelectedLine(request); 217 Deposit deposit = cmDoc.getDeposit(depositIndex); 218 if (StringUtils.equals(deposit.getDepositTypeCode(), DepositConstants.DEPOSIT_TYPE_INTERIM) && cmDoc.hasFinalDeposit()) { 219 throw new IllegalStateException("interim deposits cannot be canceled if the document already has a final deposit"); 220 } 221 222 // cancel the deposit 223 deposit = cmDoc.removeDeposit(depositIndex); 224 SpringContext.getBean(CashManagementService.class).cancelDeposit(deposit); 225 226 // update the form 227 cmForm.removeDepositHelper(depositIndex); 228 229 // open the CashDrawer so that user can add new deposits 230 cmDoc.getCashDrawer().setStatusCode(OLEConstants.CashDrawerConstants.STATUS_OPEN); 231 232 // display status message 233 KNSGlobalVariables.getMessageList().add(CashManagement.STATUS_DEPOSIT_CANCELED); 234 235 ((CashManagementForm) form).getCashDrawerSummary().resummarize(cmDoc); 236 237 return mapping.findForward(OLEConstants.MAPPING_BASIC); 238 } 239 240 241 /** 242 * @see org.kuali.rice.kns.web.struts.action.KualiDocumentActionBase#reload(org.apache.struts.action.ActionMapping, 243 * org.apache.struts.action.ActionForm, javax.servlet.http.HttpServletRequest, javax.servlet.http.HttpServletResponse) 244 */ 245 @Override 246 public ActionForward reload(ActionMapping mapping, ActionForm form, HttpServletRequest request, HttpServletResponse response) throws Exception { 247 ActionForward dest = super.reload(mapping, form, request, response); 248 249 // refresh the CashDrawerSummary, just in case 250 CashManagementForm cmForm = (CashManagementForm) form; 251 CashManagementDocument cmDoc = cmForm.getCashManagementDocument(); 252 253 CashDrawerSummary cms = cmForm.getCashDrawerSummary(); 254 if (cms != null) { 255 cms.resummarize(cmDoc); 256 } 257 258 return dest; 259 } 260 261 262 /** 263 * @param mapping 264 * @param form 265 * @param request 266 * @param response 267 * @return ActionForward 268 * @throws Exception 269 */ 270 public ActionForward refreshSummary(ActionMapping mapping, ActionForm form, HttpServletRequest request, HttpServletResponse response) throws Exception { 271 CashManagementForm cmForm = (CashManagementForm) form; 272 CashManagementDocument cmDoc = cmForm.getCashManagementDocument(); 273 274 if (cmForm.getCashDrawerSummary() != null) { 275 cmForm.getCashDrawerSummary().resummarize(cmDoc); 276 } 277 278 return mapping.findForward(OLEConstants.MAPPING_BASIC); 279 } 280 281 282 /** 283 * Saves the document, then opens the cash drawer 284 * 285 * @param mapping 286 * @param form 287 * @param request 288 * @param response 289 * @return 290 * @throws Exception 291 */ 292 public ActionForward openCashDrawer(ActionMapping mapping, ActionForm form, HttpServletRequest request, HttpServletResponse response) throws Exception { 293 CashManagementForm cmForm = (CashManagementForm) form; 294 CashManagementDocument cmDoc = cmForm.getCashManagementDocument(); 295 296 if (!cmDoc.getDocumentHeader().getWorkflowDocument().isInitiated()) { 297 throw new IllegalStateException("openCashDrawer should only be called on documents which haven't yet been saved"); 298 } 299 300 // open the CashDrawer 301 CashDrawerService cds = SpringContext.getBean(CashDrawerService.class); 302 cds.openCashDrawer(cmDoc.getCashDrawer(), cmDoc.getDocumentNumber()); 303 // now that the cash drawer is open, let's create currency/coin detail records for this document 304 // create and save the cumulative cash receipt, deposit, money in and money out curr/coin details 305 SpringContext.getBean(CashManagementService.class).createNewCashDetails(cmDoc, OLEConstants.CurrencyCoinSources.CASH_RECEIPTS); 306 SpringContext.getBean(CashManagementService.class).createNewCashDetails(cmDoc, OLEConstants.CurrencyCoinSources.CASH_MANAGEMENT_IN); 307 SpringContext.getBean(CashManagementService.class).createNewCashDetails(cmDoc, OLEConstants.CurrencyCoinSources.CASH_MANAGEMENT_OUT); 308 try { 309 SpringContext.getBean(DocumentService.class).saveDocument(cmDoc); 310 } 311 catch (WorkflowException e) { 312 // force it closed if workflow proves recalcitrant 313 cds.closeCashDrawer(cmDoc.getCashDrawer()); 314 throw e; 315 } 316 317 // update the CashDrawerSummary to reflect the change 318 cmForm.populateCashDrawerSummary(); 319 320 return mapping.findForward(OLEConstants.MAPPING_BASIC); 321 } 322 323 /** 324 * This action makes the last interim deposit a final deposit 325 * 326 * @param mapping the mapping of the actions 327 * @param form the Struts form populated on the post 328 * @param request the servlet request 329 * @param response the servlet response 330 * @return a forward to the same page we were on 331 * @throws Exception because you never know when something just might go wrong 332 */ 333 public ActionForward finalizeLastInterimDeposit(ActionMapping mapping, ActionForm form, HttpServletRequest request, HttpServletResponse response) throws Exception { 334 CashManagementDocument cmDoc = ((CashManagementForm) form).getCashManagementDocument(); 335 CashManagementService cms = SpringContext.getBean(CashManagementService.class); 336 337 if (cmDoc.hasFinalDeposit()) { 338 GlobalVariables.getMessageMap().putError(OLEConstants.CASH_MANAGEMENT_DEPOSIT_ERRORS, CashManagement.ERROR_DOCUMENT_ALREADY_HAS_FINAL_DEPOSIT, new String[] {}); 339 } 340 else if (cmDoc.getDeposits().size() == 0) { 341 GlobalVariables.getMessageMap().putError(OLEConstants.CASH_MANAGEMENT_DEPOSIT_ERRORS, CashManagement.ERROR_DOCUMENT_NO_DEPOSITS_TO_MAKE_FINAL, new String[] {}); 342 } 343 else if (!cms.allVerifiedCashReceiptsAreDeposited(cmDoc)) { 344 GlobalVariables.getMessageMap().putError(OLEConstants.CASH_MANAGEMENT_DEPOSIT_ERRORS, CashManagement.ERROR_NON_DEPOSITED_VERIFIED_CASH_RECEIPTS, new String[] {}); 345 } 346 347 cms.finalizeLastInterimDeposit(cmDoc); 348 349 ((CashManagementForm) form).getCashDrawerSummary().resummarize(cmDoc); 350 351 return mapping.findForward(OLEConstants.MAPPING_BASIC); 352 } 353 354 /** 355 * This action applies the current cashiering transaction to the cash drawer 356 * 357 * @param mapping 358 * @param form 359 * @param request 360 * @param response 361 * @return 362 * @throws Exception 363 */ 364 public ActionForward applyCashieringTransaction(ActionMapping mapping, ActionForm form, HttpServletRequest request, HttpServletResponse response) throws Exception { 365 CashManagementDocument cmDoc = ((CashManagementForm) form).getCashManagementDocument(); 366 CashManagementService cmService = SpringContext.getBean(CashManagementService.class); 367 368 final boolean valid = SpringContext.getBean(KualiRuleService.class).applyRules(new CashieringTransactionApplicationEventBase("Cashiering Transaction Application Event", "", cmDoc, SpringContext.getBean(CashDrawerService.class).getByCampusCode(cmDoc.getCampusCode()), cmDoc.getCurrentTransaction())); 369 370 if (valid) { 371 cmService.applyCashieringTransaction(cmDoc); 372 373 ((CashManagementForm) form).getCashDrawerSummary().resummarize(cmDoc); 374 } 375 376 return mapping.findForward(OLEConstants.MAPPING_BASIC); 377 } 378 379 /** 380 * This action allows the user to go to the cash drawer correction screen 381 * 382 * @param mapping 383 * @param form 384 * @param request 385 * @param response 386 * @return 387 * @throws Exception 388 */ 389 public ActionForward correctCashDrawer(ActionMapping mapping, ActionForm form, HttpServletRequest request, HttpServletResponse response) throws Exception { 390 return new ActionForward("CashDrawerCorrectionForm", buildCashDrawerCorrectionUrl(((CashManagementForm) form).getCashManagementDocument()), true); 391 } 392 393 /** 394 * @param cmDoc 395 * @param depositTypeCode 396 * @return URL for passing control to the DepositWizard 397 */ 398 protected String buildCashDrawerCorrectionUrl(CashManagementDocument cmDoc) { 399 Properties params = new Properties(); 400 params.setProperty("methodToCall", "startCorrections"); 401 params.setProperty("campusCode", cmDoc.getCampusCode()); 402 403 return UrlFactory.parameterizeUrl("cashDrawerCorrection.do", params); 404 } 405 406 /** 407 * Adds Check instance created from the current "new check" line to the document 408 * 409 * @param mapping 410 * @param form 411 * @param request 412 * @param response 413 * @return ActionForward 414 * @throws Exception 415 */ 416 public ActionForward addCheck(ActionMapping mapping, ActionForm form, HttpServletRequest request, HttpServletResponse response) throws Exception { 417 CashManagementDocument cmDoc = ((CashManagementForm) form).getCashManagementDocument(); 418 419 Check newCheck = cmDoc.getCurrentTransaction().getNewCheck(); 420 newCheck.setDocumentNumber(cmDoc.getDocumentNumber()); 421 422 // check business rules 423 boolean rulePassed = SpringContext.getBean(KualiRuleService.class).applyRules(new AddCheckEvent(OLEConstants.NEW_CHECK_PROPERTY_NAME, cmDoc, newCheck)); 424 if (rulePassed) { 425 // add check 426 cmDoc.getCurrentTransaction().addCheck(newCheck); 427 428 // clear the used newCheck 429 cmDoc.getCurrentTransaction().setNewCheck(cmDoc.getCurrentTransaction().createNewCheck()); 430 431 } 432 433 return mapping.findForward(OLEConstants.MAPPING_BASIC); 434 } 435 436 /** 437 * Deletes the selected check (line) from the document 438 * 439 * @param mapping 440 * @param form 441 * @param request 442 * @param response 443 * @return ActionForward 444 * @throws Exception 445 */ 446 public ActionForward deleteCheck(ActionMapping mapping, ActionForm form, HttpServletRequest request, HttpServletResponse response) throws Exception { 447 CashManagementDocument cmDoc = ((CashManagementForm) form).getCashManagementDocument(); 448 449 int deleteIndex = getLineToDelete(request); 450 Check oldCheck = cmDoc.getCurrentTransaction().getCheck(deleteIndex); 451 452 453 boolean rulePassed = SpringContext.getBean(KualiRuleService.class).applyRules(new DeleteCheckEvent(OLEConstants.EXISTING_CHECK_PROPERTY_NAME, cmDoc, oldCheck)); 454 455 if (rulePassed) { 456 // delete check 457 cmDoc.getCurrentTransaction().removeCheck(deleteIndex); 458 459 // delete baseline check, if any 460 if (cmDoc.getCurrentTransaction().hasBaselineCheck(deleteIndex)) { 461 cmDoc.getCurrentTransaction().getBaselineChecks().remove(deleteIndex); 462 } 463 464 } 465 else { 466 GlobalVariables.getMessageMap().putError("document.currentTransaction.check[" + deleteIndex + "]", OLEKeyConstants.Check.ERROR_CHECK_DELETERULE, Integer.toString(deleteIndex)); 467 } 468 469 return mapping.findForward(OLEConstants.MAPPING_BASIC); 470 } 471 472 /** 473 * Overridden to clear the CashDrawerSummary info 474 * 475 * @see org.kuali.rice.kns.web.struts.action.KualiDocumentActionBase#route(org.apache.struts.action.ActionMapping, 476 * org.apache.struts.action.ActionForm, javax.servlet.http.HttpServletRequest, javax.servlet.http.HttpServletResponse) 477 */ 478 @Override 479 public ActionForward route(ActionMapping mapping, ActionForm form, HttpServletRequest request, HttpServletResponse response) throws Exception { 480 CashManagementForm cmForm = (CashManagementForm) form; 481 CashManagementDocument cmDoc = cmForm.getCashManagementDocument(); 482 483 ActionForward dest = super.route(mapping, form, request, response); 484 485 // clear the CashDrawerSummary 486 cmForm.setCashDrawerSummary(null); 487 488 return dest; 489 } 490} 491