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 }