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