/* * The Kuali Financial System, a comprehensive financial management system for higher education. * * Copyright 2005-2014 The Kuali Foundation * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU Affero General Public License as * published by the Free Software Foundation, either version 3 of the * License, or (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU Affero General Public License for more details. * * You should have received a copy of the GNU Affero General Public License * along with this program. If not, see <http://www.gnu.org/licenses/>. */ package org.kuali.kfs.fp.document.web.struts; import java.util.Map; import java.util.Properties; import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletResponse; import org.apache.commons.lang.StringUtils; import org.apache.log4j.Logger; import org.apache.struts.action.ActionForm; import org.apache.struts.action.ActionForward; import org.apache.struts.action.ActionMapping; import org.kuali.kfs.fp.businessobject.Check; import org.kuali.kfs.fp.businessobject.Deposit; import org.kuali.kfs.fp.document.CashManagementDocument; import org.kuali.kfs.fp.document.service.CashManagementService; import org.kuali.kfs.fp.document.service.CashReceiptService; import org.kuali.kfs.fp.document.validation.event.AddCheckEvent; import org.kuali.kfs.fp.document.validation.event.CashieringTransactionApplicationEventBase; import org.kuali.kfs.fp.document.validation.event.DeleteCheckEvent; import org.kuali.kfs.fp.document.web.struts.CashManagementForm.CashDrawerSummary; import org.kuali.kfs.fp.exception.CashDrawerStateException; import org.kuali.kfs.fp.service.CashDrawerService; import org.kuali.kfs.sys.KFSConstants; import org.kuali.kfs.sys.KFSConstants.CashDrawerConstants; import org.kuali.kfs.sys.KFSConstants.DepositConstants; import org.kuali.kfs.sys.KFSKeyConstants; import org.kuali.kfs.sys.KFSKeyConstants.CashManagement; import org.kuali.kfs.sys.KfsAuthorizationConstants; import org.kuali.kfs.sys.context.SpringContext; import org.kuali.rice.core.api.config.property.ConfigurationService; import org.kuali.rice.kew.api.WorkflowDocument; import org.kuali.rice.kew.api.exception.WorkflowException; import org.kuali.rice.kim.api.identity.Person; import org.kuali.rice.kns.util.KNSGlobalVariables; import org.kuali.rice.kns.web.struts.action.KualiTransactionalDocumentActionBase; import org.kuali.rice.kns.web.struts.form.KualiDocumentFormBase; import org.kuali.rice.krad.service.DocumentService; import org.kuali.rice.krad.service.KualiRuleService; import org.kuali.rice.krad.util.GlobalVariables; import org.kuali.rice.krad.util.UrlFactory; /** * Action class for CashManagementForm */ public class CashManagementAction extends KualiTransactionalDocumentActionBase { protected static Logger LOG = Logger.getLogger(CashManagementAction.class); protected static final String CASH_MANAGEMENT_STATUS_PAGE = "/cashManagementStatus.do"; /** * Default constructor */ public CashManagementAction() { } /** * Overrides to call super, but also make sure the helpers are populated. * * @see org.kuali.rice.kns.web.struts.action.KualiDocumentActionBase#execute(org.apache.struts.action.ActionMapping, * org.apache.struts.action.ActionForm, javax.servlet.http.HttpServletRequest, javax.servlet.http.HttpServletResponse) */ @Override public ActionForward execute(ActionMapping mapping, ActionForm form, HttpServletRequest request, HttpServletResponse response) throws Exception { ActionForward dest = null; try { dest = super.execute(mapping, form, request, response); CashManagementForm cmf = (CashManagementForm) form; cmf.populateDepositHelpers(); WorkflowDocument kwd = cmf.getDocument().getDocumentHeader().getWorkflowDocument(); if (kwd.isEnroute() || kwd.isFinal()) { cmf.setCashDrawerSummary(null); } else { if (cmf.getCashDrawerSummary() == null) { cmf.populateCashDrawerSummary(); } } // put any recently closed items in process in the form cmf.setRecentlyClosedItemsInProcess(SpringContext.getBean(CashManagementService.class).getRecentlyClosedItemsInProcess(cmf.getCashManagementDocument())); } catch (CashDrawerStateException cdse) { dest = new ActionForward(UrlFactory.parameterizeUrl(CASH_MANAGEMENT_STATUS_PAGE, cdse.toProperties()), true); } return dest; } /** * Overrides the default document-creation code to auto-save new documents upon creation: since creating a CMDoc changes the * CashDrawer's state as a side-effect, we need all CMDocs to be docsearchable so that someone can relocate and use or cancel * whatever the current CMDoc is. * * @param kualiDocumentFormBase * @throws WorkflowException */ @Override protected void createDocument(KualiDocumentFormBase kualiDocumentFormBase) throws WorkflowException { Person user = GlobalVariables.getUserSession().getPerson(); String campusCode = SpringContext.getBean(CashReceiptService.class).getCashReceiptVerificationUnitForUser(user); String defaultDescription = SpringContext.getBean(ConfigurationService.class).getPropertyValueAsString(CashManagement.DEFAULT_DOCUMENT_DESCRIPTION); defaultDescription = StringUtils.replace(defaultDescription, "{0}", campusCode); defaultDescription = StringUtils.substring(defaultDescription, 0, 39); // create doc CashManagementDocument cmDoc = SpringContext.getBean(CashManagementService.class).createCashManagementDocument(campusCode, defaultDescription, null); // update form kualiDocumentFormBase.setDocument(cmDoc); kualiDocumentFormBase.setDocTypeName(cmDoc.getDocumentHeader().getWorkflowDocument().getDocumentTypeName()); } /** * @param mapping * @param form * @param request * @param response * @return ActionForward * @throws Exception */ public ActionForward addInterimDeposit(ActionMapping mapping, ActionForm form, HttpServletRequest request, HttpServletResponse response) throws Exception { CashManagementForm cmForm = (CashManagementForm) form; CashManagementDocument cmDoc = cmForm.getCashManagementDocument(); checkDepositAuthorization(cmForm, cmDoc); String wizardUrl = buildDepositWizardUrl(cmDoc, DepositConstants.DEPOSIT_TYPE_INTERIM); return new ActionForward(wizardUrl, true); } /** * @param mapping * @param form * @param request * @param response * @return ActionForward * @throws Exception */ public ActionForward addFinalDeposit(ActionMapping mapping, ActionForm form, HttpServletRequest request, HttpServletResponse response) throws Exception { CashManagementForm cmForm = (CashManagementForm) form; CashManagementDocument cmDoc = cmForm.getCashManagementDocument(); checkDepositAuthorization(cmForm, cmDoc); String wizardUrl = buildDepositWizardUrl(cmDoc, DepositConstants.DEPOSIT_TYPE_FINAL); return new ActionForward(wizardUrl, true); } /** * Throws a DocumentAuthorizationException if the current user is not authorized to add a deposit of the given type to the given * document. * * @param cmDoc * @param cmForm */ protected void checkDepositAuthorization(CashManagementForm cmForm, CashManagementDocument cmDoc) { //deposits can only be added if the CashDrawer is open if (!cmDoc.getCashDrawerStatus().equals(CashDrawerConstants.STATUS_OPEN)) { throw new IllegalStateException("CashDrawer '" + cmDoc.getCampusCode() + "' must be open for deposits to be made"); } //verify user's ability to add a deposit Map<String, String> documentActions = cmForm.getEditingMode(); if (!documentActions.containsKey(KfsAuthorizationConstants.CashManagementEditMode.ALLOW_ADDITIONAL_DEPOSITS)) { throw buildAuthorizationException("add a deposit", cmDoc); } } /** * @param cmDoc * @param depositTypeCode * @return URL for passing control to the DepositWizard */ protected String buildDepositWizardUrl(CashManagementDocument cmDoc, String depositTypeCode) { Properties params = new Properties(); params.setProperty("methodToCall", "startWizard"); params.setProperty("cmDocId", cmDoc.getDocumentNumber()); params.setProperty("depositTypeCode", depositTypeCode); String wizardActionUrl = UrlFactory.parameterizeUrl("depositWizard.do", params); return wizardActionUrl; } /** * @param mapping * @param form * @param request * @param response * @return ActionForward * @throws Exception */ public ActionForward cancelDeposit(ActionMapping mapping, ActionForm form, HttpServletRequest request, HttpServletResponse response) throws Exception { CashManagementForm cmForm = (CashManagementForm) form; CashManagementDocument cmDoc = cmForm.getCashManagementDocument(); // validate cancelability int depositIndex = getSelectedLine(request); Deposit deposit = cmDoc.getDeposit(depositIndex); if (StringUtils.equals(deposit.getDepositTypeCode(), DepositConstants.DEPOSIT_TYPE_INTERIM) && cmDoc.hasFinalDeposit()) { throw new IllegalStateException("interim deposits cannot be canceled if the document already has a final deposit"); } // cancel the deposit deposit = cmDoc.removeDeposit(depositIndex); SpringContext.getBean(CashManagementService.class).cancelDeposit(deposit); // update the form cmForm.removeDepositHelper(depositIndex); // open the CashDrawer so that user can add new deposits cmDoc.getCashDrawer().setStatusCode(KFSConstants.CashDrawerConstants.STATUS_OPEN); // display status message KNSGlobalVariables.getMessageList().add(CashManagement.STATUS_DEPOSIT_CANCELED); ((CashManagementForm) form).getCashDrawerSummary().resummarize(cmDoc); return mapping.findForward(KFSConstants.MAPPING_BASIC); } /** * @see org.kuali.rice.kns.web.struts.action.KualiDocumentActionBase#reload(org.apache.struts.action.ActionMapping, * org.apache.struts.action.ActionForm, javax.servlet.http.HttpServletRequest, javax.servlet.http.HttpServletResponse) */ @Override public ActionForward reload(ActionMapping mapping, ActionForm form, HttpServletRequest request, HttpServletResponse response) throws Exception { ActionForward dest = super.reload(mapping, form, request, response); // refresh the CashDrawerSummary, just in case CashManagementForm cmForm = (CashManagementForm) form; CashManagementDocument cmDoc = cmForm.getCashManagementDocument(); CashDrawerSummary cms = cmForm.getCashDrawerSummary(); if (cms != null) { cms.resummarize(cmDoc); } return dest; } /** * @param mapping * @param form * @param request * @param response * @return ActionForward * @throws Exception */ public ActionForward refreshSummary(ActionMapping mapping, ActionForm form, HttpServletRequest request, HttpServletResponse response) throws Exception { CashManagementForm cmForm = (CashManagementForm) form; CashManagementDocument cmDoc = cmForm.getCashManagementDocument(); if (cmForm.getCashDrawerSummary() != null) { cmForm.getCashDrawerSummary().resummarize(cmDoc); } return mapping.findForward(KFSConstants.MAPPING_BASIC); } /** * Saves the document, then opens the cash drawer * * @param mapping * @param form * @param request * @param response * @return * @throws Exception */ public ActionForward openCashDrawer(ActionMapping mapping, ActionForm form, HttpServletRequest request, HttpServletResponse response) throws Exception { CashManagementForm cmForm = (CashManagementForm) form; CashManagementDocument cmDoc = cmForm.getCashManagementDocument(); if (!cmDoc.getDocumentHeader().getWorkflowDocument().isInitiated()) { throw new IllegalStateException("openCashDrawer should only be called on documents which haven't yet been saved"); } // open the CashDrawer CashDrawerService cds = SpringContext.getBean(CashDrawerService.class); cds.openCashDrawer(cmDoc.getCashDrawer(), cmDoc.getDocumentNumber()); // now that the cash drawer is open, let's create currency/coin detail records for this document // create and save the cumulative cash receipt, deposit, money in and money out curr/coin details SpringContext.getBean(CashManagementService.class).createNewCashDetails(cmDoc, KFSConstants.CurrencyCoinSources.CASH_RECEIPTS); SpringContext.getBean(CashManagementService.class).createNewCashDetails(cmDoc, KFSConstants.CurrencyCoinSources.CASH_MANAGEMENT_IN); SpringContext.getBean(CashManagementService.class).createNewCashDetails(cmDoc, KFSConstants.CurrencyCoinSources.CASH_MANAGEMENT_OUT); try { SpringContext.getBean(DocumentService.class).saveDocument(cmDoc); } catch (WorkflowException e) { // force it closed if workflow proves recalcitrant cds.closeCashDrawer(cmDoc.getCashDrawer()); throw e; } // update the CashDrawerSummary to reflect the change cmForm.populateCashDrawerSummary(); return mapping.findForward(KFSConstants.MAPPING_BASIC); } /** * This action makes the last interim deposit a final deposit * * @param mapping the mapping of the actions * @param form the Struts form populated on the post * @param request the servlet request * @param response the servlet response * @return a forward to the same page we were on * @throws Exception because you never know when something just might go wrong */ public ActionForward finalizeLastInterimDeposit(ActionMapping mapping, ActionForm form, HttpServletRequest request, HttpServletResponse response) throws Exception { CashManagementDocument cmDoc = ((CashManagementForm) form).getCashManagementDocument(); CashManagementService cms = SpringContext.getBean(CashManagementService.class); if (cmDoc.hasFinalDeposit()) { GlobalVariables.getMessageMap().putError(KFSConstants.CASH_MANAGEMENT_DEPOSIT_ERRORS, CashManagement.ERROR_DOCUMENT_ALREADY_HAS_FINAL_DEPOSIT, new String[] {}); } else if (cmDoc.getDeposits().size() == 0) { GlobalVariables.getMessageMap().putError(KFSConstants.CASH_MANAGEMENT_DEPOSIT_ERRORS, CashManagement.ERROR_DOCUMENT_NO_DEPOSITS_TO_MAKE_FINAL, new String[] {}); } else if (!cms.allVerifiedCashReceiptsAreDeposited(cmDoc)) { GlobalVariables.getMessageMap().putError(KFSConstants.CASH_MANAGEMENT_DEPOSIT_ERRORS, CashManagement.ERROR_NON_DEPOSITED_VERIFIED_CASH_RECEIPTS, new String[] {}); } cms.finalizeLastInterimDeposit(cmDoc); ((CashManagementForm) form).getCashDrawerSummary().resummarize(cmDoc); return mapping.findForward(KFSConstants.MAPPING_BASIC); } /** * This action applies the current cashiering transaction to the cash drawer * * @param mapping * @param form * @param request * @param response * @return * @throws Exception */ public ActionForward applyCashieringTransaction(ActionMapping mapping, ActionForm form, HttpServletRequest request, HttpServletResponse response) throws Exception { CashManagementDocument cmDoc = ((CashManagementForm) form).getCashManagementDocument(); CashManagementService cmService = SpringContext.getBean(CashManagementService.class); final boolean valid = SpringContext.getBean(KualiRuleService.class).applyRules(new CashieringTransactionApplicationEventBase("Cashiering Transaction Application Event", "", cmDoc, SpringContext.getBean(CashDrawerService.class).getByCampusCode(cmDoc.getCampusCode()), cmDoc.getCurrentTransaction())); if (valid) { cmService.applyCashieringTransaction(cmDoc); ((CashManagementForm) form).getCashDrawerSummary().resummarize(cmDoc); } return mapping.findForward(KFSConstants.MAPPING_BASIC); } /** * This action allows the user to go to the cash drawer correction screen * * @param mapping * @param form * @param request * @param response * @return * @throws Exception */ public ActionForward correctCashDrawer(ActionMapping mapping, ActionForm form, HttpServletRequest request, HttpServletResponse response) throws Exception { return new ActionForward("CashDrawerCorrectionForm", buildCashDrawerCorrectionUrl(((CashManagementForm) form).getCashManagementDocument()), true); } /** * @param cmDoc * @param depositTypeCode * @return URL for passing control to the DepositWizard */ protected String buildCashDrawerCorrectionUrl(CashManagementDocument cmDoc) { Properties params = new Properties(); params.setProperty("methodToCall", "startCorrections"); params.setProperty("campusCode", cmDoc.getCampusCode()); return UrlFactory.parameterizeUrl("cashDrawerCorrection.do", params); } /** * Adds Check instance created from the current "new check" line to the document * * @param mapping * @param form * @param request * @param response * @return ActionForward * @throws Exception */ public ActionForward addCheck(ActionMapping mapping, ActionForm form, HttpServletRequest request, HttpServletResponse response) throws Exception { CashManagementDocument cmDoc = ((CashManagementForm) form).getCashManagementDocument(); Check newCheck = cmDoc.getCurrentTransaction().getNewCheck(); newCheck.setDocumentNumber(cmDoc.getDocumentNumber()); // check business rules boolean rulePassed = SpringContext.getBean(KualiRuleService.class).applyRules(new AddCheckEvent(KFSConstants.NEW_CHECK_PROPERTY_NAME, cmDoc, newCheck)); if (rulePassed) { // add check cmDoc.getCurrentTransaction().addCheck(newCheck); // clear the used newCheck cmDoc.getCurrentTransaction().setNewCheck(cmDoc.getCurrentTransaction().createNewCheck()); } return mapping.findForward(KFSConstants.MAPPING_BASIC); } /** * Deletes the selected check (line) from the document * * @param mapping * @param form * @param request * @param response * @return ActionForward * @throws Exception */ public ActionForward deleteCheck(ActionMapping mapping, ActionForm form, HttpServletRequest request, HttpServletResponse response) throws Exception { CashManagementDocument cmDoc = ((CashManagementForm) form).getCashManagementDocument(); int deleteIndex = getLineToDelete(request); Check oldCheck = cmDoc.getCurrentTransaction().getCheck(deleteIndex); boolean rulePassed = SpringContext.getBean(KualiRuleService.class).applyRules(new DeleteCheckEvent(KFSConstants.EXISTING_CHECK_PROPERTY_NAME, cmDoc, oldCheck)); if (rulePassed) { // delete check cmDoc.getCurrentTransaction().removeCheck(deleteIndex); // delete baseline check, if any if (cmDoc.getCurrentTransaction().hasBaselineCheck(deleteIndex)) { cmDoc.getCurrentTransaction().getBaselineChecks().remove(deleteIndex); } } else { GlobalVariables.getMessageMap().putError("document.currentTransaction.check[" + deleteIndex + "]", KFSKeyConstants.Check.ERROR_CHECK_DELETERULE, Integer.toString(deleteIndex)); } return mapping.findForward(KFSConstants.MAPPING_BASIC); } /** * Overridden to clear the CashDrawerSummary info * * @see org.kuali.rice.kns.web.struts.action.KualiDocumentActionBase#route(org.apache.struts.action.ActionMapping, * org.apache.struts.action.ActionForm, javax.servlet.http.HttpServletRequest, javax.servlet.http.HttpServletResponse) */ @Override public ActionForward route(ActionMapping mapping, ActionForm form, HttpServletRequest request, HttpServletResponse response) throws Exception { CashManagementForm cmForm = (CashManagementForm) form; CashManagementDocument cmDoc = cmForm.getCashManagementDocument(); ActionForward dest = super.route(mapping, form, request, response); // clear the CashDrawerSummary cmForm.setCashDrawerSummary(null); return dest; } }