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.io.FileNotFoundException; 019 import java.io.IOException; 020 import java.util.ArrayList; 021 022 import javax.servlet.http.HttpServletRequest; 023 import javax.servlet.http.HttpServletResponse; 024 025 import org.apache.commons.lang.StringUtils; 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.coa.businessobject.BalanceType; 030 import org.kuali.kfs.coa.service.BalanceTypeService; 031 import org.kuali.kfs.fp.businessobject.VoucherAccountingLineHelper; 032 import org.kuali.kfs.fp.businessobject.VoucherAccountingLineHelperBase; 033 import org.kuali.kfs.fp.businessobject.VoucherSourceAccountingLine; 034 import org.kuali.kfs.fp.document.JournalVoucherDocument; 035 import org.kuali.kfs.fp.document.VoucherDocument; 036 import org.kuali.kfs.sys.KFSConstants; 037 import org.kuali.kfs.sys.KFSKeyConstants; 038 import org.kuali.kfs.sys.KFSPropertyConstants; 039 import org.kuali.kfs.sys.businessobject.SourceAccountingLine; 040 import org.kuali.kfs.sys.context.SpringContext; 041 import org.kuali.rice.kew.exception.WorkflowException; 042 import org.kuali.rice.kns.question.ConfirmationQuestion; 043 import org.kuali.rice.kns.service.KualiConfigurationService; 044 import org.kuali.rice.kns.util.GlobalVariables; 045 import org.kuali.rice.kns.util.KualiDecimal; 046 import org.kuali.rice.kns.web.format.CurrencyFormatter; 047 import org.kuali.rice.kns.web.struts.form.KualiDocumentFormBase; 048 049 /** 050 * This class piggy backs on all of the functionality in the FinancialSystemTransactionalDocumentActionBase but is necessary for 051 * this document type. The Journal Voucher is unique in that it defines several fields that aren't typically used by the other 052 * financial transaction processing eDocs (i.e. external system fields, object type override, credit and debit amounts). 053 */ 054 public class JournalVoucherAction extends VoucherAction { 055 056 // used to determine which way the change balance type action is switching these are local constants only used within this 057 // action class these should not be used outside of this class 058 protected static final int CREDIT_DEBIT_TO_SINGLE_AMT_MODE = 0; 059 protected static final int SINGLE_AMT_TO_CREDIT_DEBIT_MODE = 1; 060 protected static final int EXT_ENCUMB_TO_NON_EXT_ENCUMB = 0; 061 protected static final int NON_EXT_ENCUMB_TO_EXT_ENCUMB = 1; 062 protected static final int NO_MODE_CHANGE = -1; 063 064 /** 065 * Overrides the parent and then calls the super method after building the array lists for valid accounting periods and balance 066 * types. 067 * 068 * @see org.kuali.rice.kns.web.struts.action.KualiAction#execute(ActionMapping mapping, ActionForm form, HttpServletRequest 069 * request, HttpServletResponse response) 070 */ 071 @Override 072 public ActionForward execute(ActionMapping mapping, ActionForm form, HttpServletRequest request, HttpServletResponse response) throws Exception { 073 JournalVoucherForm journalVoucherForm = (JournalVoucherForm) form; 074 075 populateBalanceTypeOneDocument(journalVoucherForm); 076 077 // now check to see if the balance type was changed and if so, we want to 078 // set the method to call so that the appropriate action can be invoked 079 // had to do it this way b/c the changing of the drop down causes the page to re-submit 080 // and couldn't use a hidden field called "methodToCall" b/c it screwed everything up 081 ActionForward returnForward; 082 if (StringUtils.isNotBlank(journalVoucherForm.getOriginalBalanceType()) && !journalVoucherForm.getSelectedBalanceType().getCode().equals(journalVoucherForm.getOriginalBalanceType())) { 083 returnForward = super.dispatchMethod(mapping, form, request, response, KFSConstants.CHANGE_JOURNAL_VOUCHER_BALANCE_TYPE_METHOD); 084 // must call this here, because execute in the super method will never have control for this particular action 085 // this is called in the parent by super.execute() 086 this.populateAuthorizationFields(journalVoucherForm); 087 } 088 else { // otherwise call the super 089 returnForward = super.execute(mapping, journalVoucherForm, request, response); 090 } 091 return returnForward; 092 } 093 094 /** 095 * Overrides the parent to first prompt the user appropriately to make sure that they want to submit and out of balance 096 * document, then calls super's route method. 097 * 098 * @see org.kuali.rice.kns.web.struts.action.KualiDocumentActionBase#route(org.apache.struts.action.ActionMapping, 099 * org.apache.struts.action.ActionForm, javax.servlet.http.HttpServletRequest, javax.servlet.http.HttpServletResponse) 100 */ 101 @Override 102 public ActionForward route(ActionMapping mapping, ActionForm form, HttpServletRequest request, HttpServletResponse response) throws Exception { 103 // process the question but we need to make sure there are lines and then check to see if it's not balanced 104 VoucherDocument vDoc = ((VoucherForm) form).getVoucherDocument(); 105 106 KualiDecimal balance = vDoc.getCreditTotal().subtract(vDoc.getDebitTotal()); 107 if (vDoc.getSourceAccountingLines().size() > 0 && balance.compareTo(KualiDecimal.ZERO) != 0) { 108 // it's not in "balance" 109 ActionForward returnForward = processRouteOutOfBalanceDocumentConfirmationQuestion(mapping, form, request, response); 110 111 // if not null, then the question component either has control of the flow and needs to ask its questions 112 // or the person chose the "cancel" or "no" button 113 // otherwise we have control 114 if (returnForward != null) { 115 return returnForward; 116 } 117 } 118 // now call the route method 119 return super.route(mapping, form, request, response); 120 } 121 122 /** 123 * This method handles grabbing the values from the form and pushing them into the document appropriately. 124 * 125 * @param journalVoucherForm 126 */ 127 protected void populateBalanceTypeOneDocument(JournalVoucherForm journalVoucherForm) { 128 String selectedBalanceTypeCode = journalVoucherForm.getSelectedBalanceType().getCode(); 129 BalanceType selectedBalanceType = getPopulatedBalanceTypeInstance(selectedBalanceTypeCode); 130 journalVoucherForm.getJournalVoucherDocument().setBalanceTypeCode(selectedBalanceTypeCode); 131 journalVoucherForm.getJournalVoucherDocument().setBalanceType(selectedBalanceType); // set the fully populated balance type 132 // object into the form's selected 133 // balance type 134 journalVoucherForm.setSelectedBalanceType(selectedBalanceType); 135 } 136 137 138 /** 139 * Overrides to call super, and then to repopulate the credit/debit amounts b/c the credit/debit code might change during a JV 140 * error correction. 141 * 142 * @see org.kuali.kfs.fp.document.web.struts.VoucherAction#correct(org.apache.struts.action.ActionMapping, 143 * org.apache.struts.action.ActionForm, javax.servlet.http.HttpServletRequest, javax.servlet.http.HttpServletResponse) 144 */ 145 @Override 146 public ActionForward correct(ActionMapping mapping, ActionForm form, HttpServletRequest request, HttpServletResponse response) throws Exception { 147 ActionForward actionForward = super.correct(mapping, form, request, response); 148 149 JournalVoucherDocument jvDoc = (JournalVoucherDocument) ((JournalVoucherForm) form).getDocument(); 150 151 jvDoc.refreshReferenceObject(KFSPropertyConstants.BALANCE_TYPE); 152 // only repopulate if this is a JV that was entered in debit/credit mode 153 if (jvDoc.getBalanceType().isFinancialOffsetGenerationIndicator()) { 154 // now make sure to repopulate credit/debit amounts 155 populateAllVoucherAccountingLineHelpers((JournalVoucherForm) form); 156 } 157 158 return actionForward; 159 } 160 161 /** 162 * This method processes a change in the balance type for a Journal Voucher document - from either a offset generation balance 163 * type to a non-offset generation balance type or visa-versa. 164 * 165 * @param mapping 166 * @param form 167 * @param request 168 * @param response 169 * @return ActionForward 170 * @throws Exception 171 */ 172 public ActionForward changeBalanceType(ActionMapping mapping, ActionForm form, HttpServletRequest request, HttpServletResponse response) throws Exception { 173 JournalVoucherForm journalVoucherForm = (JournalVoucherForm) form; 174 175 // figure out which way the balance type is changing 176 int balanceTypeAmountChangeMode = determineBalanceTypeAmountChangeMode(journalVoucherForm); 177 int balanceTypeExternalEncumbranceChangeMode = determineBalanceTypeEncumbranceChangeMode(journalVoucherForm); 178 179 // process the question 180 if (balanceTypeAmountChangeMode != NO_MODE_CHANGE || balanceTypeExternalEncumbranceChangeMode != NO_MODE_CHANGE) { 181 ActionForward returnForward = processChangeBalanceTypeConfirmationQuestion(mapping, form, request, response); 182 183 // if not null, then the question component either has control of the flow and needs to ask its questions 184 // or the person choose the "cancel" or "no" button otherwise we have control 185 if (returnForward != null) { 186 return returnForward; 187 } 188 else { 189 // deal with balance type changes first amount change 190 if (balanceTypeAmountChangeMode == CREDIT_DEBIT_TO_SINGLE_AMT_MODE) { 191 switchFromCreditDebitModeToSingleAmountMode(journalVoucherForm); 192 } 193 else if (balanceTypeAmountChangeMode == SINGLE_AMT_TO_CREDIT_DEBIT_MODE) { 194 switchFromSingleAmountModeToCreditDebitMode(journalVoucherForm); 195 } 196 197 // then look to see if the external encumbrance was involved 198 if (balanceTypeExternalEncumbranceChangeMode == EXT_ENCUMB_TO_NON_EXT_ENCUMB) { 199 switchFromExternalEncumbranceModeToNonExternalEncumbrance(journalVoucherForm); 200 } 201 } 202 } 203 204 return mapping.findForward(KFSConstants.MAPPING_BASIC); 205 } 206 207 /** 208 * This method will determine which balance type amount mode to switch to. A change in the balance type selection will 209 * eventually invoke this mechanism, which looks at the old balance type value, and the new balance type value to determine what 210 * the next mode is. 211 * 212 * @param journalVoucherForm 213 * @throws Exception 214 */ 215 protected int determineBalanceTypeAmountChangeMode(JournalVoucherForm journalVoucherForm) throws Exception { 216 int balanceTypeAmountChangeMode = NO_MODE_CHANGE; 217 218 // retrieve fully populated balance type instances 219 BalanceType origBalType = getPopulatedBalanceTypeInstance(journalVoucherForm.getOriginalBalanceType()); 220 BalanceType newBalType = getPopulatedBalanceTypeInstance(journalVoucherForm.getSelectedBalanceType().getCode()); 221 222 // figure out which ways we are switching the modes first deal with amount changes 223 if (origBalType.isFinancialOffsetGenerationIndicator() && !newBalType.isFinancialOffsetGenerationIndicator()) { // credit/debit 224 balanceTypeAmountChangeMode = CREDIT_DEBIT_TO_SINGLE_AMT_MODE; 225 } 226 else if (!origBalType.isFinancialOffsetGenerationIndicator() && newBalType.isFinancialOffsetGenerationIndicator()) { // single 227 balanceTypeAmountChangeMode = SINGLE_AMT_TO_CREDIT_DEBIT_MODE; 228 } 229 230 return balanceTypeAmountChangeMode; 231 } 232 233 /** 234 * This method will determine which balance type encumbrance mode to switch to. A change in the balance type selection will 235 * eventually invoke this mechanism, which looks at the old balance type value, and the new balance type value to determine what 236 * the next mode is. 237 * 238 * @param journalVoucherForm 239 * @throws Exception 240 */ 241 protected int determineBalanceTypeEncumbranceChangeMode(JournalVoucherForm journalVoucherForm) throws Exception { 242 int balanceTypeExternalEncumbranceChangeMode = NO_MODE_CHANGE; 243 244 // retrieve fully populated balance type instances 245 BalanceType origBalType = getPopulatedBalanceTypeInstance(journalVoucherForm.getOriginalBalanceType()); 246 BalanceType newBalType = getPopulatedBalanceTypeInstance(journalVoucherForm.getSelectedBalanceType().getCode()); 247 248 // then deal with external encumbrance changes 249 if (origBalType.getCode().equals(KFSConstants.BALANCE_TYPE_EXTERNAL_ENCUMBRANCE) && !newBalType.getCode().equals(KFSConstants.BALANCE_TYPE_EXTERNAL_ENCUMBRANCE)) { 250 balanceTypeExternalEncumbranceChangeMode = EXT_ENCUMB_TO_NON_EXT_ENCUMB; 251 } 252 else if (!origBalType.getCode().equals(KFSConstants.BALANCE_TYPE_EXTERNAL_ENCUMBRANCE) && newBalType.getCode().equals(KFSConstants.BALANCE_TYPE_EXTERNAL_ENCUMBRANCE)) { 253 balanceTypeExternalEncumbranceChangeMode = NON_EXT_ENCUMB_TO_EXT_ENCUMB; 254 } 255 256 return balanceTypeExternalEncumbranceChangeMode; 257 } 258 259 /** 260 * This method takes control from the changeBalanceType action method in order to present a question prompt to the user so that 261 * they can confirm the change in balance type. 262 * 263 * @param mapping 264 * @param form 265 * @param request 266 * @param response 267 * @return ActionForward 268 * @throws Exception 269 */ 270 protected ActionForward processChangeBalanceTypeConfirmationQuestion(ActionMapping mapping, ActionForm form, HttpServletRequest request, HttpServletResponse response) throws Exception { 271 JournalVoucherForm jvForm = (JournalVoucherForm) form; 272 JournalVoucherDocument jvDoc = jvForm.getJournalVoucherDocument(); 273 274 // only want to present the confirmation question to the user if there are any 275 // accouting lines, because that is the only impact 276 if (jvDoc.getSourceAccountingLines().size() != 0) { 277 String question = request.getParameter(KFSConstants.QUESTION_INST_ATTRIBUTE_NAME); 278 KualiConfigurationService kualiConfiguration = SpringContext.getBean(KualiConfigurationService.class); 279 280 if (question == null) { // question hasn't been asked 281 String message = buildBalanceTypeChangeConfirmationMessage(jvForm, kualiConfiguration); 282 283 // now transfer control over to the question component 284 return this.performQuestionWithoutInput(mapping, form, request, response, KFSConstants.JOURNAL_VOUCHER_CHANGE_BALANCE_TYPE_QUESTION, message, KFSConstants.CONFIRMATION_QUESTION, KFSConstants.CHANGE_JOURNAL_VOUCHER_BALANCE_TYPE_METHOD, ""); 285 } 286 else { 287 String buttonClicked = request.getParameter(KFSConstants.QUESTION_CLICKED_BUTTON); 288 if ((KFSConstants.JOURNAL_VOUCHER_CHANGE_BALANCE_TYPE_QUESTION.equals(question)) && ConfirmationQuestion.NO.equals(buttonClicked)) { 289 // if no button clicked keep the old value and reload doc 290 BalanceType origBalType = getPopulatedBalanceTypeInstance(jvForm.getOriginalBalanceType()); 291 jvForm.setSelectedBalanceType(origBalType); 292 jvDoc.setBalanceType(origBalType); 293 jvDoc.setBalanceTypeCode(origBalType.getCode()); 294 return mapping.findForward(KFSConstants.MAPPING_BASIC); 295 } 296 } 297 } 298 return null; 299 } 300 301 /** 302 * This method will setup the message that will get displayed to the user when they are asked to confirm the balance type 303 * change. The message is tuned to the particular context, the value chosen, and also the previous value. It also combines with 304 * the core part of the message which is part of the ApplicationResources.properties file. 305 * 306 * @param jvForm 307 * @param kualiConfiguration 308 * @return The message to display to the user in the question prompt window. 309 * @throws Exception 310 */ 311 protected String buildBalanceTypeChangeConfirmationMessage(JournalVoucherForm jvForm, KualiConfigurationService kualiConfiguration) throws Exception { 312 String message = new String(""); 313 314 // figure out which way the balance type is changing 315 int balanceTypeAmountChangeMode = determineBalanceTypeAmountChangeMode(jvForm); 316 int balanceTypeExternalEncumbranceChangeMode = determineBalanceTypeEncumbranceChangeMode(jvForm); 317 318 // grab the right message from the ApplicationResources.properties file depending upon the balance type switching mode 319 if (balanceTypeAmountChangeMode == SINGLE_AMT_TO_CREDIT_DEBIT_MODE) { 320 message = kualiConfiguration.getPropertyString(KFSKeyConstants.QUESTION_CHANGE_JV_BAL_TYPE_FROM_SINGLE_AMT_TO_CREDIT_DEBIT_MODE); 321 // see if we need the extra bit about the external encumbrance 322 String newMessage = new String(""); 323 if (balanceTypeExternalEncumbranceChangeMode == NON_EXT_ENCUMB_TO_EXT_ENCUMB) { 324 newMessage = StringUtils.replace(message, "{3}", kualiConfiguration.getPropertyString(KFSKeyConstants.QUESTION_CHANGE_JV_BAL_TYPE_FROM_SINGLE_AMT_TO_EXT_ENCUMB_CREDIT_DEBIT_MODE)); 325 } 326 else { 327 newMessage = StringUtils.replace(message, "{3}", ""); 328 } 329 message = new String(newMessage); 330 } 331 else if (balanceTypeAmountChangeMode == CREDIT_DEBIT_TO_SINGLE_AMT_MODE) { 332 message = kualiConfiguration.getPropertyString(KFSKeyConstants.QUESTION_CHANGE_JV_BAL_TYPE_FROM_CREDIT_DEBIT_TO_SINGLE_AMT_MODE); 333 // see if we need the extra bit about the external encumbrance 334 String newMessage = new String(""); 335 if (balanceTypeExternalEncumbranceChangeMode == EXT_ENCUMB_TO_NON_EXT_ENCUMB) { 336 newMessage = StringUtils.replace(message, "{3}", kualiConfiguration.getPropertyString(KFSKeyConstants.QUESTION_CHANGE_JV_BAL_TYPE_FROM_EXT_ENCUMB_CREDIT_DEBIT_TO_SINGLE_AMT_MODE)); 337 } 338 else { 339 newMessage = StringUtils.replace(message, "{3}", ""); 340 } 341 message = new String(newMessage); 342 } 343 else if (balanceTypeExternalEncumbranceChangeMode == EXT_ENCUMB_TO_NON_EXT_ENCUMB) { 344 message = kualiConfiguration.getPropertyString(KFSKeyConstants.QUESTION_CHANGE_JV_BAL_TYPE_FROM_EXT_ENCUMB_TO_NON_EXT_ENCUMB); 345 } 346 else if (balanceTypeExternalEncumbranceChangeMode == NON_EXT_ENCUMB_TO_EXT_ENCUMB) { 347 message = kualiConfiguration.getPropertyString(KFSKeyConstants.QUESTION_CHANGE_JV_BAL_TYPE_FROM_NON_EXT_ENCUMB_TO_EXT_ENCUMB); 348 } 349 350 // retrieve fully populated balance type instances 351 BalanceType origBalType = getPopulatedBalanceTypeInstance(jvForm.getOriginalBalanceType()); 352 BalanceType newBalType = getPopulatedBalanceTypeInstance(jvForm.getSelectedBalanceType().getCode()); 353 354 // now complete building of the message 355 String replacement = "\"" + origBalType.getCode() + "-" + origBalType.getName() + "\""; 356 String newMessage = StringUtils.replace(message, "{0}", replacement); 357 358 replacement = "\"" + newBalType.getCode() + "-" + newBalType.getName() + "\""; 359 String finalMessage = StringUtils.replace(newMessage, "{1}", replacement); 360 361 return finalMessage; 362 } 363 364 /** 365 * This method will fully populate a balance type given the passed in code, by calling the business object service that 366 * retrieves the rest of the instances' information. 367 * 368 * @param balanceTypeCode 369 * @return BalanceTyp 370 */ 371 protected BalanceType getPopulatedBalanceTypeInstance(String balanceTypeCode) { 372 // now we have to get the code and the name of the original and new balance types 373 return SpringContext.getBean(BalanceTypeService.class).getBalanceTypeByCode(balanceTypeCode); 374 } 375 376 /** 377 * This method will clear out the source line values that aren't needed for the "Single Amount" mode. 378 * 379 * @param journalVoucherForm 380 */ 381 protected void switchFromSingleAmountModeToCreditDebitMode(JournalVoucherForm journalVoucherForm) { 382 // going from single amount to credit/debit view so we want to blank out the amount and the extra "reference" fields 383 // that the single amount view uses 384 JournalVoucherDocument jvDoc = (JournalVoucherDocument) journalVoucherForm.getTransactionalDocument(); 385 ArrayList sourceLines = (ArrayList) jvDoc.getSourceAccountingLines(); 386 ArrayList helperLines = (ArrayList) journalVoucherForm.getVoucherLineHelpers(); 387 helperLines.clear(); // reset so we can add in fresh empty ones 388 389 // make sure that there is enough space in the list 390 helperLines.ensureCapacity(sourceLines.size()); 391 392 for (int i = 0; i < sourceLines.size(); i++) { 393 VoucherSourceAccountingLine sourceLine = (VoucherSourceAccountingLine) sourceLines.get(i); 394 sourceLine.setAmount(KualiDecimal.ZERO); 395 sourceLine.setDebitCreditCode(KFSConstants.GL_DEBIT_CODE); // default to debit 396 397 helperLines.add(new VoucherAccountingLineHelperBase()); // populate with a fresh new empty object 398 } 399 } 400 401 /** 402 * This method will clear out the extra "reference" fields that the external encumbrance balance type uses, but will leave the 403 * amounts since we aren't changing the offset generation code stuff. 404 * 405 * @param journalVoucherForm 406 */ 407 protected void switchFromExternalEncumbranceModeToNonExternalEncumbrance(JournalVoucherForm journalVoucherForm) { 408 // going from external encumbrance view to non external encumbrance view, so we want to blank out the extra "reference" 409 // fields 410 JournalVoucherDocument jvDoc = (JournalVoucherDocument) journalVoucherForm.getTransactionalDocument(); 411 ArrayList sourceLines = (ArrayList) jvDoc.getSourceAccountingLines(); 412 413 for (int i = 0; i < sourceLines.size(); i++) { 414 VoucherSourceAccountingLine sourceLine = (VoucherSourceAccountingLine) sourceLines.get(i); 415 sourceLine.setReferenceOriginCode(null); // won't be needed in this mode 416 sourceLine.setReferenceNumber(null); // won't be needed in this mode 417 sourceLine.setReferenceTypeCode(null); // won't be needed in this mode 418 } 419 } 420 421 /** 422 * This method will clear out the source line values that aren't needed for the "Credit/Debit" mode. 423 * 424 * @param journalVoucherForm 425 */ 426 protected void switchFromCreditDebitModeToSingleAmountMode(JournalVoucherForm journalVoucherForm) { 427 // going from credit/debit view to single amount view so we don't need the debit and credit 428 // indicator set any more and we need to blank out the amount values to zero 429 JournalVoucherDocument jvDoc = journalVoucherForm.getJournalVoucherDocument(); 430 ArrayList sourceLines = (ArrayList) jvDoc.getSourceAccountingLines(); 431 ArrayList helperLines = (ArrayList) journalVoucherForm.getVoucherLineHelpers(); 432 433 KualiDecimal ZERO = new KualiDecimal("0.00"); 434 for (int i = 0; i < sourceLines.size(); i++) { 435 VoucherAccountingLineHelper helperLine = (VoucherAccountingLineHelper) helperLines.get(i); 436 SourceAccountingLine sourceLine = (SourceAccountingLine) sourceLines.get(i); 437 sourceLine.setAmount(ZERO); 438 sourceLine.setDebitCreditCode(KFSConstants.GL_DEBIT_CODE); // single sided is always debit 439 440 helperLine.setCredit(null); // won't be needed in this mode 441 helperLine.setDebit(null); // won't be needed in this mode 442 } 443 } 444 445 /** 446 * Overrides the parent to make sure that the JV specific accounting line helper forms are properly populated when the document 447 * is first loaded. This first calls super, then populates the helper objects. 448 * 449 * @see org.kuali.rice.kns.web.struts.action.KualiDocumentActionBase#loadDocument(org.kuali.rice.kns.web.struts.form.KualiDocumentFormBase) 450 */ 451 @Override 452 protected void loadDocument(KualiDocumentFormBase kualiDocumentFormBase) throws WorkflowException { 453 super.loadDocument(kualiDocumentFormBase); 454 JournalVoucherForm journalVoucherForm = (JournalVoucherForm) kualiDocumentFormBase; 455 456 // if the balance type is an offset generation balance type, then the user is able to enter the amount 457 // as either a debit or a credit, otherwise, they only need to deal with the amount field 458 JournalVoucherDocument journalVoucherDocument = (JournalVoucherDocument) journalVoucherForm.getTransactionalDocument(); 459 if (journalVoucherDocument.getBalanceType().isFinancialOffsetGenerationIndicator()) { 460 populateAllVoucherAccountingLineHelpers(journalVoucherForm); 461 KualiDecimal ZERO = new KualiDecimal("0.00"); 462 journalVoucherForm.setNewSourceLineCredit(ZERO); 463 journalVoucherForm.setNewSourceLineDebit(ZERO); 464 } 465 466 // always wipe out the new source line 467 journalVoucherForm.setNewSourceLine(null); 468 469 // reload the balance type and accounting period selections since now we have data in the document bo 470 populateSelectedJournalBalanceType(journalVoucherDocument, journalVoucherForm); 471 populateSelectedAccountingPeriod(journalVoucherDocument, journalVoucherForm); 472 } 473 474 /** 475 * This method grabs the value from the document bo and sets the selected balance type appropriately. 476 * 477 * @param journalVoucherDocument 478 * @param journalVoucherForm 479 */ 480 protected void populateSelectedJournalBalanceType(JournalVoucherDocument journalVoucherDocument, JournalVoucherForm journalVoucherForm) { 481 journalVoucherForm.setSelectedBalanceType(journalVoucherDocument.getBalanceType()); 482 if (StringUtils.isNotBlank(journalVoucherDocument.getBalanceTypeCode())) { 483 journalVoucherForm.setOriginalBalanceType(journalVoucherDocument.getBalanceTypeCode()); 484 } 485 } 486 487 /** 488 * This helper method determines from the request object instance whether or not the user has been prompted about the journal 489 * being out of balance. If they haven't, then the method will build the appropriate message given the state of the document and 490 * return control to the question component so that the user receives the "yes"/"no" prompt. If the question has been asked, the 491 * we evaluate the user's answer and direct the flow appropriately. If they answer with a "No", then we build out a message 492 * stating that they chose that value and return an ActionForward of a MAPPING_BASIC which keeps them at the same page that they 493 * were on. If they choose "Yes", then we return a null ActionForward, which the calling action method recognizes as a "Yes" and 494 * continues on processing the "Route." 495 * 496 * @param mapping 497 * @param form 498 * @param request 499 * @param response 500 * @return ActionForward 501 * @throws Exception 502 */ 503 @Override 504 protected ActionForward processRouteOutOfBalanceDocumentConfirmationQuestion(ActionMapping mapping, ActionForm form, HttpServletRequest request, HttpServletResponse response) throws Exception { 505 JournalVoucherForm jvForm = (JournalVoucherForm) form; 506 JournalVoucherDocument jvDoc = jvForm.getJournalVoucherDocument(); 507 508 String question = request.getParameter(KFSConstants.QUESTION_INST_ATTRIBUTE_NAME); 509 KualiConfigurationService kualiConfiguration = SpringContext.getBean(KualiConfigurationService.class); 510 511 if (question == null) { // question hasn't been asked 512 String currencyFormattedDebitTotal = (String) new CurrencyFormatter().format(jvDoc.getDebitTotal()); 513 String currencyFormattedCreditTotal = (String) new CurrencyFormatter().format(jvDoc.getCreditTotal()); 514 String currencyFormattedTotal = (String) new CurrencyFormatter().format(jvDoc.getTotalDollarAmount()); 515 String message = ""; 516 jvDoc.refreshReferenceObject(KFSPropertyConstants.BALANCE_TYPE); 517 if (jvDoc.getBalanceType().isFinancialOffsetGenerationIndicator()) { 518 message = StringUtils.replace(kualiConfiguration.getPropertyString(KFSKeyConstants.QUESTION_ROUTE_OUT_OF_BALANCE_JV_DOC), "{0}", currencyFormattedDebitTotal); 519 message = StringUtils.replace(message, "{1}", currencyFormattedCreditTotal); 520 } 521 else { 522 message = StringUtils.replace(kualiConfiguration.getPropertyString(KFSKeyConstants.QUESTION_ROUTE_OUT_OF_BALANCE_JV_DOC_SINGLE_AMT_MODE), "{0}", currencyFormattedTotal); 523 } 524 525 // now transfer control over to the question component 526 return this.performQuestionWithoutInput(mapping, form, request, response, KFSConstants.JOURNAL_VOUCHER_ROUTE_OUT_OF_BALANCE_DOCUMENT_QUESTION, message, KFSConstants.CONFIRMATION_QUESTION, KFSConstants.ROUTE_METHOD, ""); 527 } 528 else { 529 String buttonClicked = request.getParameter(KFSConstants.QUESTION_CLICKED_BUTTON); 530 if ((KFSConstants.JOURNAL_VOUCHER_ROUTE_OUT_OF_BALANCE_DOCUMENT_QUESTION.equals(question)) && ConfirmationQuestion.NO.equals(buttonClicked)) { 531 GlobalVariables.getMessageList().add(KFSKeyConstants.MESSAGE_JV_CANCELLED_ROUTE); 532 return mapping.findForward(KFSConstants.MAPPING_BASIC); 533 } 534 } 535 return null; 536 } 537 538 /** 539 * This action executes a call to upload CSV accounting line values as SourceAccountingLines for a given transactional document. 540 * The "uploadAccountingLines()" method handles the multi-part request. 541 * 542 * @param mapping 543 * @param form 544 * @param request 545 * @param response 546 * @return ActionForward 547 * @throws FileNotFoundException 548 * @throws IOException 549 */ 550 @Override 551 public ActionForward uploadSourceLines(ActionMapping mapping, ActionForm form, HttpServletRequest request, HttpServletResponse response) throws FileNotFoundException, IOException { 552 // call method that sourceform and destination list 553 uploadAccountingLines(true, form); 554 555 return mapping.findForward(KFSConstants.MAPPING_BASIC); 556 } 557 558 /** 559 * This method determines whether we are uploading source or target lines, and then calls uploadAccountingLines directly on the 560 * document object. This method handles retrieving the actual upload file as an input stream into the document. 561 * 562 * @param isSource 563 * @param form 564 * @throws FileNotFoundException 565 * @throws IOException 566 */ 567 @Override 568 protected void uploadAccountingLines(boolean isSource, ActionForm form) throws FileNotFoundException, IOException { 569 JournalVoucherForm jvForm = (JournalVoucherForm) form; 570 // JournalVoucherAccountingLineParser needs a fresh BalanceType BO in the JournalVoucherDocument. 571 jvForm.getJournalVoucherDocument().refreshReferenceObject(KFSPropertyConstants.BALANCE_TYPE); 572 super.uploadAccountingLines(isSource, jvForm); 573 } 574 575 }