View Javadoc
1   /*
2    * Copyright 2005 The Kuali Foundation
3    * 
4    * Licensed under the Educational Community License, Version 2.0 (the "License");
5    * you may not use this file except in compliance with the License.
6    * You may obtain a copy of the License at
7    * 
8    * http://www.opensource.org/licenses/ecl2.php
9    * 
10   * Unless required by applicable law or agreed to in writing, software
11   * distributed under the License is distributed on an "AS IS" BASIS,
12   * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13   * See the License for the specific language governing permissions and
14   * limitations under the License.
15   */
16  package org.kuali.ole.fp.document.web.struts;
17  
18  import java.io.FileNotFoundException;
19  import java.io.IOException;
20  import java.util.ArrayList;
21  
22  import javax.servlet.http.HttpServletRequest;
23  import javax.servlet.http.HttpServletResponse;
24  
25  import org.apache.commons.lang.StringUtils;
26  import org.apache.struts.action.ActionForm;
27  import org.apache.struts.action.ActionForward;
28  import org.apache.struts.action.ActionMapping;
29  import org.kuali.ole.coa.businessobject.BalanceType;
30  import org.kuali.ole.coa.service.BalanceTypeService;
31  import org.kuali.ole.fp.businessobject.VoucherAccountingLineHelper;
32  import org.kuali.ole.fp.businessobject.VoucherAccountingLineHelperBase;
33  import org.kuali.ole.fp.businessobject.VoucherSourceAccountingLine;
34  import org.kuali.ole.fp.document.JournalVoucherDocument;
35  import org.kuali.ole.fp.document.VoucherDocument;
36  import org.kuali.ole.sys.OLEConstants;
37  import org.kuali.ole.sys.OLEKeyConstants;
38  import org.kuali.ole.sys.OLEPropertyConstants;
39  import org.kuali.ole.sys.businessobject.SourceAccountingLine;
40  import org.kuali.ole.sys.context.SpringContext;
41  import org.kuali.rice.core.api.config.property.ConfigurationService;
42  import org.kuali.rice.core.api.util.type.KualiDecimal;
43  import org.kuali.rice.core.web.format.CurrencyFormatter;
44  import org.kuali.rice.kew.api.exception.WorkflowException;
45  import org.kuali.rice.kns.question.ConfirmationQuestion;
46  import org.kuali.rice.kns.util.KNSGlobalVariables;
47  import org.kuali.rice.kns.web.struts.form.KualiDocumentFormBase;
48  
49  /**
50   * This class piggy backs on all of the functionality in the FinancialSystemTransactionalDocumentActionBase but is necessary for
51   * this document type. The Journal Voucher is unique in that it defines several fields that aren't typically used by the other
52   * financial transaction processing eDocs (i.e. external system fields, object type override, credit and debit amounts).
53   */
54  public class JournalVoucherAction extends VoucherAction {
55  
56      // used to determine which way the change balance type action is switching these are local constants only used within this
57      // action class these should not be used outside of this class
58      protected static final int CREDIT_DEBIT_TO_SINGLE_AMT_MODE = 0;
59      protected static final int SINGLE_AMT_TO_CREDIT_DEBIT_MODE = 1;
60      protected static final int EXT_ENCUMB_TO_NON_EXT_ENCUMB = 0;
61      protected static final int NON_EXT_ENCUMB_TO_EXT_ENCUMB = 1;
62      protected static final int NO_MODE_CHANGE = -1;
63  
64      /**
65       * Overrides the parent and then calls the super method after building the array lists for valid accounting periods and balance
66       * types.
67       * 
68       * @see org.kuali.rice.kns.web.struts.action.KualiAction#execute(ActionMapping mapping, ActionForm form, HttpServletRequest
69       *      request, HttpServletResponse response)
70       */
71      @Override
72      public ActionForward execute(ActionMapping mapping, ActionForm form, HttpServletRequest request, HttpServletResponse response) throws Exception {
73          JournalVoucherForm journalVoucherForm = (JournalVoucherForm) form;
74  
75          populateBalanceTypeOneDocument(journalVoucherForm);
76  
77          // now check to see if the balance type was changed and if so, we want to
78          // set the method to call so that the appropriate action can be invoked
79          // had to do it this way b/c the changing of the drop down causes the page to re-submit
80          // and couldn't use a hidden field called "methodToCall" b/c it screwed everything up
81          ActionForward returnForward;
82          if (StringUtils.isNotBlank(journalVoucherForm.getOriginalBalanceType()) && !journalVoucherForm.getSelectedBalanceType().getCode().equals(journalVoucherForm.getOriginalBalanceType())) {
83              returnForward = super.dispatchMethod(mapping, form, request, response, OLEConstants.CHANGE_JOURNAL_VOUCHER_BALANCE_TYPE_METHOD);
84              // must call this here, because execute in the super method will never have control for this particular action
85              // this is called in the parent by super.execute()
86              this.populateAuthorizationFields(journalVoucherForm);
87          }
88          else { // otherwise call the super
89              returnForward = super.execute(mapping, journalVoucherForm, request, response);
90          }
91          return returnForward;
92      }
93  
94      /**
95       * Overrides the parent to first prompt the user appropriately to make sure that they want to submit and out of balance
96       * document, then calls super's route method.
97       * 
98       * @see org.kuali.rice.kns.web.struts.action.KualiDocumentActionBase#route(org.apache.struts.action.ActionMapping,
99       *      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.ole.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(OLEPropertyConstants.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(OLEConstants.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(OLEConstants.BALANCE_TYPE_EXTERNAL_ENCUMBRANCE) && !newBalType.getCode().equals(OLEConstants.BALANCE_TYPE_EXTERNAL_ENCUMBRANCE)) {
250             balanceTypeExternalEncumbranceChangeMode = EXT_ENCUMB_TO_NON_EXT_ENCUMB;
251         }
252         else if (!origBalType.getCode().equals(OLEConstants.BALANCE_TYPE_EXTERNAL_ENCUMBRANCE) && newBalType.getCode().equals(OLEConstants.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(OLEConstants.QUESTION_INST_ATTRIBUTE_NAME);
278             ConfigurationService kualiConfiguration = SpringContext.getBean(ConfigurationService.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, OLEConstants.JOURNAL_VOUCHER_CHANGE_BALANCE_TYPE_QUESTION, message, OLEConstants.CONFIRMATION_QUESTION, OLEConstants.CHANGE_JOURNAL_VOUCHER_BALANCE_TYPE_METHOD, "");
285             }
286             else {
287                 String buttonClicked = request.getParameter(OLEConstants.QUESTION_CLICKED_BUTTON);
288                 if ((OLEConstants.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(OLEConstants.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, ConfigurationService 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.getPropertyValueAsString(OLEKeyConstants.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.getPropertyValueAsString(OLEKeyConstants.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.getPropertyValueAsString(OLEKeyConstants.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.getPropertyValueAsString(OLEKeyConstants.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.getPropertyValueAsString(OLEKeyConstants.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.getPropertyValueAsString(OLEKeyConstants.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(OLEConstants.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(OLEConstants.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(OLEConstants.QUESTION_INST_ATTRIBUTE_NAME);
509         ConfigurationService kualiConfiguration = SpringContext.getBean(ConfigurationService.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(OLEPropertyConstants.BALANCE_TYPE);
517             if (jvDoc.getBalanceType().isFinancialOffsetGenerationIndicator()) {
518                 message = StringUtils.replace(kualiConfiguration.getPropertyValueAsString(OLEKeyConstants.QUESTION_ROUTE_OUT_OF_BALANCE_JV_DOC), "{0}", currencyFormattedDebitTotal);
519                 message = StringUtils.replace(message, "{1}", currencyFormattedCreditTotal);
520             }
521             else {
522                 message = StringUtils.replace(kualiConfiguration.getPropertyValueAsString(OLEKeyConstants.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, OLEConstants.JOURNAL_VOUCHER_ROUTE_OUT_OF_BALANCE_DOCUMENT_QUESTION, message, OLEConstants.CONFIRMATION_QUESTION, OLEConstants.ROUTE_METHOD, "");
527         }
528         else {
529             String buttonClicked = request.getParameter(OLEConstants.QUESTION_CLICKED_BUTTON);
530             if ((OLEConstants.JOURNAL_VOUCHER_ROUTE_OUT_OF_BALANCE_DOCUMENT_QUESTION.equals(question)) && ConfirmationQuestion.NO.equals(buttonClicked)) {
531                 KNSGlobalVariables.getMessageList().add(OLEKeyConstants.MESSAGE_JV_CANCELLED_ROUTE);
532                 return mapping.findForward(OLEConstants.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(OLEConstants.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(OLEPropertyConstants.BALANCE_TYPE);
572         super.uploadAccountingLines(isSource, jvForm);
573     }
574 
575 }