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.module.purap.document.web.struts; 017 018 import java.util.Iterator; 019 import java.util.TreeMap; 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.struts.action.ActionForm; 026 import org.apache.struts.action.ActionForward; 027 import org.apache.struts.action.ActionMapping; 028 import org.kuali.kfs.module.purap.PurapKeyConstants; 029 import org.kuali.kfs.module.purap.document.ReceivingDocument; 030 import org.kuali.kfs.module.purap.util.ReceivingQuestionCallback; 031 import org.kuali.kfs.sys.KFSConstants; 032 import org.kuali.kfs.sys.context.SpringContext; 033 import org.kuali.kfs.sys.document.web.struts.FinancialSystemTransactionalDocumentActionBase; 034 import org.kuali.rice.kns.bo.Note; 035 import org.kuali.rice.kns.question.ConfirmationQuestion; 036 import org.kuali.rice.kns.service.DataDictionaryService; 037 import org.kuali.rice.kns.service.KualiConfigurationService; 038 import org.kuali.rice.kns.util.ObjectUtils; 039 import org.kuali.rice.kns.web.struts.form.KualiDocumentFormBase; 040 041 public class ReceivingBaseAction extends FinancialSystemTransactionalDocumentActionBase { 042 043 /** 044 * A wrapper method which prompts for a reason to hold a payment request or credit memo. 045 * 046 * @param mapping An ActionMapping 047 * @param form An ActionForm 048 * @param request The HttpServletRequest 049 * @param response The HttpServletResponse 050 * @param questionType A String used to distinguish which question is being asked 051 * @param notePrefix A String explaining what action was taken, to be prepended to the note containing the reason, which gets 052 * written to the document 053 * @param operation A one-word String description of the action to be taken, to be substituted into the message. (Can be an 054 * empty String for some messages.) 055 * @param messageKey A key to the message which will appear on the question screen 056 * @param callback A PurQuestionCallback 057 * @return An ActionForward 058 * @throws Exception 059 */ 060 protected ActionForward askQuestionWithInput(ActionMapping mapping, ActionForm form, HttpServletRequest request, HttpServletResponse response, String questionType, String notePrefix, String operation, String messageKey, ReceivingQuestionCallback callback) throws Exception { 061 TreeMap<String, ReceivingQuestionCallback> questionsAndCallbacks = new TreeMap<String, ReceivingQuestionCallback>(); 062 questionsAndCallbacks.put(questionType, callback); 063 064 return askQuestionWithInput(mapping, form, request, response, questionType, notePrefix, operation, messageKey, questionsAndCallbacks, "", mapping.findForward(KFSConstants.MAPPING_BASIC)); 065 } 066 067 /** 068 * Builds and asks questions which require text input by the user for a payment request or a credit memo. 069 * 070 * @param mapping An ActionMapping 071 * @param form An ActionForm 072 * @param request The HttpServletRequest 073 * @param response The HttpServletResponse 074 * @param questionType A String used to distinguish which question is being asked 075 * @param notePrefix A String explaining what action was taken, to be prepended to the note containing the reason, which gets 076 * written to the document 077 * @param operation A one-word String description of the action to be taken, to be substituted into the message. (Can be an 078 * empty String for some messages.) 079 * @param messageKey A (whole) key to the message which will appear on the question screen 080 * @param questionsAndCallbacks A TreeMap associating the type of question to be asked and the type of callback which should 081 * happen in that case 082 * @param messagePrefix The most general part of a key to a message text to be retrieved from KualiConfigurationService, 083 * Describes a collection of questions. 084 * @param redirect An ActionForward to return to if done with questions 085 * @return An ActionForward 086 * @throws Exception 087 */ 088 protected ActionForward askQuestionWithInput(ActionMapping mapping, ActionForm form, HttpServletRequest request, HttpServletResponse response, String questionType, String notePrefix, String operation, String messageKey, TreeMap<String, ReceivingQuestionCallback> questionsAndCallbacks, String messagePrefix, ActionForward redirect) throws Exception { 089 KualiDocumentFormBase kualiDocumentFormBase = (KualiDocumentFormBase) form; 090 ReceivingDocument receivingDocument = (ReceivingDocument) kualiDocumentFormBase.getDocument(); 091 092 String question = (String) request.getParameter(KFSConstants.QUESTION_INST_ATTRIBUTE_NAME); 093 String reason = request.getParameter(KFSConstants.QUESTION_REASON_ATTRIBUTE_NAME); 094 String noteText = ""; 095 096 KualiConfigurationService kualiConfiguration = SpringContext.getBean(KualiConfigurationService.class); 097 String firstQuestion = questionsAndCallbacks.firstKey(); 098 ReceivingQuestionCallback callback = null; 099 Iterator questions = questionsAndCallbacks.keySet().iterator(); 100 String mapQuestion = null; 101 String key = null; 102 103 // Start in logic for confirming the close. 104 if (question == null) { 105 key = getQuestionProperty(messageKey, messagePrefix, kualiConfiguration, firstQuestion); 106 String message = StringUtils.replace(key, "{0}", operation); 107 108 // Ask question if not already asked. 109 return this.performQuestionWithInput(mapping, form, request, response, firstQuestion, message, KFSConstants.CONFIRMATION_QUESTION, questionType, ""); 110 } 111 else { 112 // find callback for this question 113 while (questions.hasNext()) { 114 mapQuestion = (String) questions.next(); 115 116 if (StringUtils.equals(mapQuestion, question)) { 117 callback = questionsAndCallbacks.get(mapQuestion); 118 break; 119 } 120 } 121 key = getQuestionProperty(messageKey, messagePrefix, kualiConfiguration, mapQuestion); 122 123 Object buttonClicked = request.getParameter(KFSConstants.QUESTION_CLICKED_BUTTON); 124 if (question.equals(mapQuestion) && buttonClicked.equals(ConfirmationQuestion.NO)) { 125 // If 'No' is the button clicked, just reload the doc 126 127 String nextQuestion = null; 128 // ask another question if more left 129 if (questions.hasNext()) { 130 nextQuestion = (String) questions.next(); 131 key = getQuestionProperty(messageKey, messagePrefix, kualiConfiguration, nextQuestion); 132 133 return this.performQuestionWithInput(mapping, form, request, response, nextQuestion, key, KFSConstants.CONFIRMATION_QUESTION, questionType, ""); 134 } 135 else { 136 137 return mapping.findForward(KFSConstants.MAPPING_BASIC); 138 } 139 } 140 // Have to check length on value entered. 141 String introNoteMessage = notePrefix + KFSConstants.BLANK_SPACE; 142 143 // Build out full message. 144 noteText = introNoteMessage + reason; 145 int noteTextLength = noteText.length(); 146 147 // Get note text max length from DD. 148 int noteTextMaxLength = SpringContext.getBean(DataDictionaryService.class).getAttributeMaxLength(Note.class, KFSConstants.NOTE_TEXT_PROPERTY_NAME).intValue(); 149 if (StringUtils.isBlank(reason) || (noteTextLength > noteTextMaxLength)) { 150 // Figure out exact number of characters that the user can enter. 151 int reasonLimit = noteTextMaxLength - noteTextLength; 152 if (reason == null) { 153 // Prevent a NPE by setting the reason to a blank string. 154 reason = ""; 155 } 156 157 return this.performQuestionWithInputAgainBecauseOfErrors(mapping, form, request, response, mapQuestion, key, KFSConstants.CONFIRMATION_QUESTION, questionType, "", reason, PurapKeyConstants.ERROR_PAYMENT_REQUEST_REASON_REQUIRED, KFSConstants.QUESTION_REASON_ATTRIBUTE_NAME, new Integer(reasonLimit).toString()); 158 } 159 } 160 161 // make callback 162 if (ObjectUtils.isNotNull(callback)) { 163 ReceivingDocument refreshedReceivingDocument = callback.doPostQuestion(receivingDocument, noteText); 164 kualiDocumentFormBase.setDocument(refreshedReceivingDocument); 165 } 166 String nextQuestion = null; 167 // ask another question if more left 168 if (questions.hasNext()) { 169 nextQuestion = (String) questions.next(); 170 key = getQuestionProperty(messageKey, messagePrefix, kualiConfiguration, nextQuestion); 171 172 return this.performQuestionWithInput(mapping, form, request, response, nextQuestion, key, KFSConstants.CONFIRMATION_QUESTION, questionType, ""); 173 } 174 175 return redirect; 176 } 177 178 /** 179 * Used to look up messages to be displayed, from the KualiConfigurationService, given either a whole key or two parts of a key 180 * that may be concatenated together. 181 * 182 * @param messageKey String. One of the message keys in PurapKeyConstants. 183 * @param messagePrefix String. A prefix to the question key, such as "ap.question." that, concatenated with the question, 184 * comprises the whole key of the message. 185 * @param kualiConfiguration An instance of KualiConfigurationService 186 * @param question String. The most specific part of the message key in PurapKeyConstants. 187 * @return The message to be displayed given the key 188 */ 189 protected String getQuestionProperty(String messageKey, String messagePrefix, KualiConfigurationService kualiConfiguration, String question) { 190 191 return kualiConfiguration.getPropertyString((StringUtils.isEmpty(messagePrefix)) ? messageKey : messagePrefix + question); 192 } 193 194 }