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