View Javadoc
1   /*
2    * Copyright 2006 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.fp.businessobject.VoucherAccountingLineHelper;
30  import org.kuali.ole.fp.businessobject.VoucherAccountingLineHelperBase;
31  import org.kuali.ole.fp.document.VoucherDocument;
32  import org.kuali.ole.sys.OLEConstants;
33  import org.kuali.ole.sys.OLEKeyConstants;
34  import org.kuali.ole.sys.businessobject.SourceAccountingLine;
35  import org.kuali.ole.sys.context.SpringContext;
36  import org.kuali.ole.sys.document.AmountTotaling;
37  import org.kuali.ole.sys.service.UniversityDateService;
38  import org.kuali.ole.sys.web.struts.KualiAccountingDocumentActionBase;
39  import org.kuali.rice.core.api.config.property.ConfigurationService;
40  import org.kuali.rice.core.api.util.type.KualiDecimal;
41  import org.kuali.rice.core.web.format.CurrencyFormatter;
42  import org.kuali.rice.kew.api.exception.WorkflowException;
43  import org.kuali.rice.kns.question.ConfirmationQuestion;
44  import org.kuali.rice.kns.util.KNSGlobalVariables;
45  import org.kuali.rice.kns.web.struts.form.KualiDocumentFormBase;
46  import org.kuali.rice.krad.util.GlobalVariables;
47  
48  /**
49   * This class piggy backs on all of the functionality in the FinancialSystemTransactionalDocumentActionBase but is necessary for this document
50   * type. Vouchers are unique in that they define several fields that aren't typically used by the other financial transaction
51   * processing eDocs (i.e. external system fields, object type override, credit and debit amounts).
52   */
53  public class VoucherAction extends KualiAccountingDocumentActionBase {
54      // used to determine which way the change balance type action is switching
55      // these are local constants only used within this action class
56      // these should not be used outside of this class
57  
58      /**
59       * Overrides to call super, and then to repopulate the credit/debit amounts b/c the credit/debit code might change during a
60       * voucher error correction.
61       * 
62       * @see org.kuali.ole.sys.document.web.struts.FinancialSystemTransactionalDocumentActionBase#correct(org.apache.struts.action.ActionMapping, org.apache.struts.action.ActionForm, javax.servlet.http.HttpServletRequest, javax.servlet.http.HttpServletResponse)
63       */
64      @Override
65      public ActionForward correct(ActionMapping mapping, ActionForm form, HttpServletRequest request, HttpServletResponse response) throws Exception {
66          ActionForward actionForward = super.correct(mapping, form, request, response);
67  
68          VoucherForm vForm = (VoucherForm) form;
69  
70          // now make sure to repopulate credit/debit amounts
71          populateAllVoucherAccountingLineHelpers(vForm);
72  
73          return actionForward;
74      }
75  
76      /**
77       * Overrides parent to first populate the new source line with the correct debit or credit value, then it calls the parent's
78       * implementation.
79       * 
80       * @see org.kuali.module.financial.web.struts.action.KualiFinancialDocumentActionBase#insertSourceLine(org.apache.struts.action.ActionMapping,
81       *      org.apache.struts.action.ActionForm, javax.servlet.http.HttpServletRequest, javax.servlet.http.HttpServletResponse)
82       */
83      @Override
84      public ActionForward insertSourceLine(ActionMapping mapping, ActionForm form, HttpServletRequest request, HttpServletResponse response) throws Exception {
85          // cast the form to the right pojo
86          VoucherForm voucherForm = (VoucherForm) form;
87  
88          // call the super's method
89          ActionForward actionForward = super.insertSourceLine(mapping, form, request, response);
90  
91          if (GlobalVariables.getMessageMap().getErrorCount() == 0) {
92              // since no exceptions were thrown, the add succeeded, so we have to re-init the new credit and debit
93              // attributes, and add a new instance of a helperLine to the helperLines list
94              VoucherAccountingLineHelper helperLine = populateNewVoucherAccountingLineHelper(voucherForm);
95              voucherForm.getVoucherLineHelpers().add(helperLine);
96  
97              // now reset the debit and credit fields for adds
98              voucherForm.setNewSourceLineDebit(KualiDecimal.ZERO);
99              voucherForm.setNewSourceLineCredit(KualiDecimal.ZERO);
100         }
101 
102         return actionForward;
103     }
104 
105     /**
106      * Overrides parent to remove the associated helper line also, and then it call the parent's implementation.
107      * 
108      * @see org.kuali.module.financial.web.struts.action.KualiFinancialDocumentActionBase#deleteSourceLine(org.apache.struts.action.ActionMapping,
109      *      org.apache.struts.action.ActionForm, javax.servlet.http.HttpServletRequest, javax.servlet.http.HttpServletResponse)
110      */
111     @Override
112     public ActionForward deleteSourceLine(ActionMapping mapping, ActionForm form, HttpServletRequest request, HttpServletResponse response) throws Exception {
113         // cast the form to the right pojo
114         VoucherForm voucherForm = (VoucherForm) form;
115 
116         // call the super's method
117         ActionForward actionForward = super.deleteSourceLine(mapping, voucherForm, request, response);
118 
119         // now remove the associated helper line
120         int index = getLineToDelete(request);
121         if (voucherForm.getVoucherLineHelpers() != null && voucherForm.getVoucherLineHelpers().size() > index) {
122             voucherForm.getVoucherLineHelpers().remove(getLineToDelete(request));
123         }
124 
125         return actionForward;
126     }
127 
128     /**
129      * Overrides the parent to make sure that the AV specific accounting line helper forms are properly populated when the document
130      * is first loaded. This first calls super, then populates the helper objects.
131      * 
132      * @see org.kuali.rice.kns.web.struts.action.KualiDocumentActionBase#loadDocument(org.kuali.rice.kns.web.struts.form.KualiDocumentFormBase)
133      */
134     @Override
135     protected void loadDocument(KualiDocumentFormBase kualiDocumentFormBase) throws WorkflowException {
136         super.loadDocument(kualiDocumentFormBase);
137         VoucherForm voucherForm = (VoucherForm) kualiDocumentFormBase;
138 
139         populateAllVoucherAccountingLineHelpers(voucherForm);
140         voucherForm.setNewSourceLineCredit(KualiDecimal.ZERO);
141         voucherForm.setNewSourceLineDebit(KualiDecimal.ZERO);
142 
143         // always wipe out the new source line
144         voucherForm.setNewSourceLine(null);
145 
146         // reload the accounting period selections since now we have data in the document bo
147         populateSelectedAccountingPeriod(voucherForm.getVoucherDocument(), voucherForm);
148     }
149 
150     /**
151      * This method parses the accounting period value from the bo and builds the right string to pass to the form object as the
152      * selected value.
153      * 
154      * @param voucherDocument
155      * @param voucherForm
156      */
157     protected void populateSelectedAccountingPeriod(VoucherDocument voucherDocument, VoucherForm voucherForm) {
158         if (StringUtils.isNotBlank(voucherDocument.getPostingPeriodCode())) {
159             String selectedAccountingPeriod = voucherDocument.getPostingPeriodCode();
160             if (null != voucherDocument.getPostingYear()) {
161                 selectedAccountingPeriod += voucherDocument.getPostingYear().toString();
162             }
163             else {
164                 selectedAccountingPeriod += SpringContext.getBean(UniversityDateService.class).getCurrentFiscalYear().toString();
165             }
166             voucherForm.setSelectedAccountingPeriod(selectedAccountingPeriod);
167         }
168     }
169 
170     /**
171      * This populates a new helperLine instance with the one that was just added so that the new instance can be added to the
172      * helperLines list.
173      * 
174      * @param voucherForm
175      * @return VoucherAccountingLineHelper
176      */
177     protected VoucherAccountingLineHelper populateVoucherAccountingLineHelper(VoucherForm voucherForm) {
178         VoucherAccountingLineHelper helperLine = new VoucherAccountingLineHelperBase();
179 
180         KualiDecimal debitAmount = voucherForm.getNewSourceLineDebit();
181         if (debitAmount != null && StringUtils.isNotBlank(debitAmount.toString())) {
182             helperLine.setDebit(debitAmount);
183         }
184 
185         KualiDecimal creditAmount = voucherForm.getNewSourceLineCredit();
186         if (creditAmount != null && StringUtils.isNotBlank(creditAmount.toString())) {
187             helperLine.setCredit(creditAmount);
188         }
189 
190         return helperLine;
191     }
192 
193     /**
194      * This method builds the corresponding list of voucher acounting line helper objects so that a user can differentiate between
195      * credit and debit fields. It does this by iterating over each source accounting line (what the voucher uses) looking at the
196      * debit/credit code and then populateingLineHelpers a corresponding helper form instance with the amount in the appropriate
197      * amount field - credit or debit.
198      * 
199      * @param voucherForm
200      */
201     protected void populateAllVoucherAccountingLineHelpers(VoucherForm voucherForm) {
202         // make sure the journal voucher accounting line helper form list is populated properly
203         ArrayList voucherLineHelpers = (ArrayList) voucherForm.getVoucherLineHelpers();
204 
205         // make sure the helper list is the right size
206         VoucherDocument vDoc = (VoucherDocument) voucherForm.getTransactionalDocument();
207         int size = vDoc.getSourceAccountingLines().size();
208         voucherLineHelpers.ensureCapacity(size);
209 
210         // iterate through each source accounting line and initialize the helper form lines appropriately
211         for (int i = 0; i < size; i++) {
212             // get the bo's accounting line at the right index
213             SourceAccountingLine sourceAccountingLine = vDoc.getSourceAccountingLine(i);
214 
215             // instantiate a new helper form to use for populating the helper form list
216             VoucherAccountingLineHelper avAcctLineHelperForm = voucherForm.getVoucherLineHelper(i);
217 
218             // figure whether we need to set the credit amount or the debit amount
219             if (StringUtils.isNotBlank(sourceAccountingLine.getDebitCreditCode())) {
220                 if (sourceAccountingLine.getDebitCreditCode().equals(OLEConstants.GL_DEBIT_CODE)) {
221                     avAcctLineHelperForm.setDebit(sourceAccountingLine.getAmount());
222                     avAcctLineHelperForm.setCredit(KualiDecimal.ZERO);
223                 }
224                 else if (sourceAccountingLine.getDebitCreditCode().equals(OLEConstants.GL_CREDIT_CODE)) {
225                     avAcctLineHelperForm.setCredit(sourceAccountingLine.getAmount());
226                     avAcctLineHelperForm.setDebit(KualiDecimal.ZERO);
227                 }
228             }
229         }
230     }
231 
232 
233     /**
234      * This helper method determines from the request object instance whether or not the user has been prompted about the journal
235      * being out of balance. If they haven't, then the method will build the appropriate message given the state of the document and
236      * return control to the question component so that the user receives the "yes"/"no" prompt. If the question has been asked, the
237      * we evaluate the user's answer and direct the flow appropriately. If they answer with a "No", then we build out a message
238      * stating that they chose that value and return an ActionForward of a MAPPING_BASIC which keeps them at the same page that they
239      * were on. If they choose "Yes", then we return a null ActionForward, which the calling action method recognizes as a "Yes" and
240      * continues on processing the "Route."
241      * 
242      * @param mapping
243      * @param form
244      * @param request
245      * @param response
246      * @return ActionForward
247      * @throws Exception
248      */
249     protected ActionForward processRouteOutOfBalanceDocumentConfirmationQuestion(ActionMapping mapping, ActionForm form, HttpServletRequest request, HttpServletResponse response) throws Exception {
250         VoucherForm vForm = (VoucherForm) form;
251         VoucherDocument avDoc = vForm.getVoucherDocument();
252 
253         String question = request.getParameter(OLEConstants.QUESTION_INST_ATTRIBUTE_NAME);
254         ConfigurationService kualiConfiguration = SpringContext.getBean(ConfigurationService.class);
255 
256         if (question == null) { // question hasn't been asked
257             String currencyFormattedDebitTotal = (String) new CurrencyFormatter().format(avDoc.getDebitTotal());
258             String currencyFormattedCreditTotal = (String) new CurrencyFormatter().format(avDoc.getCreditTotal());
259             String currencyFormattedTotal = (String) new CurrencyFormatter().format(((AmountTotaling) avDoc).getTotalDollarAmount());
260             String message = "";
261             message = StringUtils.replace(kualiConfiguration.getPropertyValueAsString(OLEKeyConstants.QUESTION_ROUTE_OUT_OF_BALANCE_JV_DOC), "{0}", currencyFormattedDebitTotal);
262             message = StringUtils.replace(message, "{1}", currencyFormattedCreditTotal);
263 
264             // now transfer control over to the question component
265             return this.performQuestionWithoutInput(mapping, form, request, response, OLEConstants.JOURNAL_VOUCHER_ROUTE_OUT_OF_BALANCE_DOCUMENT_QUESTION, message, OLEConstants.CONFIRMATION_QUESTION, OLEConstants.ROUTE_METHOD, "");
266         }
267         else {
268             String buttonClicked = request.getParameter(OLEConstants.QUESTION_CLICKED_BUTTON);
269             if ((OLEConstants.JOURNAL_VOUCHER_ROUTE_OUT_OF_BALANCE_DOCUMENT_QUESTION.equals(question)) && ConfirmationQuestion.NO.equals(buttonClicked)) {
270                 KNSGlobalVariables.getMessageList().add(OLEKeyConstants.MESSAGE_JV_CANCELLED_ROUTE);
271                 return mapping.findForward(OLEConstants.MAPPING_BASIC);
272             }
273         }
274         return null;
275     }
276 
277     /**
278      * This populates a new helperLine instance with the one that was just added so that the new instance can be added to the
279      * helperLines list.
280      * 
281      * @param voucherForm
282      * @return voucherAccountingLineHelper
283      */
284     protected VoucherAccountingLineHelper populateNewVoucherAccountingLineHelper(VoucherForm voucherForm) {
285         VoucherAccountingLineHelper helperLine = new VoucherAccountingLineHelperBase();
286 
287         KualiDecimal debitAmount = voucherForm.getNewSourceLineDebit();
288         if (debitAmount != null && StringUtils.isNotBlank(debitAmount.toString())) {
289             helperLine.setDebit(debitAmount);
290         }
291 
292         KualiDecimal creditAmount = voucherForm.getNewSourceLineCredit();
293         if (creditAmount != null && StringUtils.isNotBlank(creditAmount.toString())) {
294             helperLine.setCredit(creditAmount);
295         }
296 
297         return helperLine;
298     }
299 
300     /**
301      * This action executes a call to upload CSV accounting line values as SourceAccountingLines for a given transactional document.
302      * The "uploadAccountingLines()" method handles the multi-part request.
303      * 
304      * @param mapping
305      * @param form
306      * @param request
307      * @param response
308      * @return ActionForward
309      * @throws FileNotFoundException
310      * @throws IOException
311      */
312     @Override
313     public ActionForward uploadSourceLines(ActionMapping mapping, ActionForm form, HttpServletRequest request, HttpServletResponse response) throws FileNotFoundException, IOException {
314         // call method that sourceform and destination list
315         uploadAccountingLines(true, form);
316 
317         return mapping.findForward(OLEConstants.MAPPING_BASIC);
318     }
319 
320     /**
321      * This method determines whether we are uploading source or target lines, and then calls uploadAccountingLines directly on the
322      * document object. This method handles retrieving the actual upload file as an input stream into the document.
323      * 
324      * @param isSource
325      * @param form
326      * @throws FileNotFoundException
327      * @throws IOException
328      */
329     @Override
330     protected void uploadAccountingLines(boolean isSource, ActionForm form) throws FileNotFoundException, IOException {
331         super.uploadAccountingLines(isSource, form);
332 
333         populateAllVoucherAccountingLineHelpers((VoucherForm) form);
334     }
335 
336     /**
337      * Overridden to reset the available and selected accounting periods on the form, so that copies are moved forward to the current accounting period correctly
338      * @see org.kuali.ole.sys.web.struts.KualiAccountingDocumentActionBase#copy(org.apache.struts.action.ActionMapping, org.apache.struts.action.ActionForm, javax.servlet.http.HttpServletRequest, javax.servlet.http.HttpServletResponse)
339      */
340     @Override
341     public ActionForward copy(ActionMapping mapping, ActionForm form, HttpServletRequest request, HttpServletResponse response) throws Exception {
342         ActionForward forward = super.copy(mapping, form, request, response);
343         VoucherForm voucherForm = (VoucherForm)form;
344         voucherForm.populateAccountingPeriodListForRendering();
345         voucherForm.populateDefaultSelectedAccountingPeriod();
346         return forward;
347     }
348 }