View Javadoc
1   /*
2    * Copyright 2007 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.module.purap.document.web.struts;
17  
18  import org.apache.commons.lang.StringUtils;
19  import org.apache.struts.action.ActionForm;
20  import org.apache.struts.action.ActionForward;
21  import org.apache.struts.action.ActionMapping;
22  import org.apache.struts.upload.FormFile;
23  import org.kuali.ole.module.purap.PurapConstants;
24  import org.kuali.ole.module.purap.PurapPropertyConstants;
25  import org.kuali.ole.module.purap.businessobject.PurApAccountingLine;
26  import org.kuali.ole.module.purap.businessobject.PurApAccountingLineParser;
27  import org.kuali.ole.module.purap.businessobject.PurApItem;
28  import org.kuali.ole.module.purap.document.PurchasingAccountsPayableDocument;
29  import org.kuali.ole.module.purap.document.PurchasingAccountsPayableDocumentBase;
30  import org.kuali.ole.module.purap.document.service.PurapService;
31  import org.kuali.ole.module.purap.service.PurapAccountingService;
32  import org.kuali.ole.sys.OLEConstants;
33  import org.kuali.ole.sys.OLEPropertyConstants;
34  import org.kuali.ole.sys.businessobject.AccountingLine;
35  import org.kuali.ole.sys.businessobject.SourceAccountingLine;
36  import org.kuali.ole.sys.context.SpringContext;
37  import org.kuali.ole.sys.document.validation.event.AddAccountingLineEvent;
38  import org.kuali.ole.sys.exception.AccountingLineParserException;
39  import org.kuali.ole.sys.web.struts.KualiAccountingDocumentActionBase;
40  import org.kuali.ole.sys.web.struts.KualiAccountingDocumentFormBase;
41  import org.kuali.rice.core.api.util.RiceConstants;
42  import org.kuali.rice.kew.api.WorkflowDocument;
43  import org.kuali.rice.kew.api.exception.WorkflowException;
44  import org.kuali.rice.kns.web.struts.form.KualiDocumentFormBase;
45  import org.kuali.rice.kns.web.struts.form.KualiForm;
46  import org.kuali.rice.krad.service.DocumentService;
47  import org.kuali.rice.krad.service.KualiRuleService;
48  import org.kuali.rice.krad.service.PersistenceService;
49  import org.kuali.rice.krad.util.GlobalVariables;
50  import org.kuali.rice.krad.util.ObjectUtils;
51  
52  import javax.servlet.http.HttpServletRequest;
53  import javax.servlet.http.HttpServletResponse;
54  import java.io.FileNotFoundException;
55  import java.io.IOException;
56  import java.math.BigDecimal;
57  import java.util.HashMap;
58  import java.util.Iterator;
59  import java.util.List;
60  import java.util.Map;
61  import java.util.Map.Entry;
62  
63  /**
64   * Struts Action for Purchasing and Accounts Payable documents
65   */
66  public class PurchasingAccountsPayableActionBase extends KualiAccountingDocumentActionBase {
67  
68      /**
69       * @see org.kuali.rice.kns.web.struts.action.KualiTransactionalDocumentActionBase#copy(org.apache.struts.action.ActionMapping, org.apache.struts.action.ActionForm, javax.servlet.http.HttpServletRequest, javax.servlet.http.HttpServletResponse)
70       */
71      @Override
72      public ActionForward copy(ActionMapping mapping, ActionForm form, HttpServletRequest request, HttpServletResponse response) throws Exception {
73          ActionForward actionForward = super.copy(mapping, form, request, response);
74  
75  
76          KualiDocumentFormBase kualiDocumentFormBase = (KualiDocumentFormBase) form;
77          PurchasingAccountsPayableDocument purapDocument = (PurchasingAccountsPayableDocument) kualiDocumentFormBase.getDocument();
78  
79          //refresh accounts in each item....
80          List<PurApItem> items = purapDocument.getItems();
81  
82          for (PurApItem item : items) {
83              item.getNewSourceLine().setAccountLinePercent(new BigDecimal(0));
84              //set default sequence number.
85              for (PurApAccountingLine account : item.getSourceAccountingLines()) {
86                  account.setSequenceNumber(0);
87              }
88          }
89  
90          return actionForward;
91      }
92  
93      /**
94       * @see org.kuali.rice.kns.web.struts.action.KualiDocumentActionBase#loadDocument(org.kuali.rice.kns.web.struts.form.KualiDocumentFormBase)
95       */
96      @Override
97      protected void loadDocument(KualiDocumentFormBase kualiDocumentFormBase) throws WorkflowException {
98          super.loadDocument(kualiDocumentFormBase);
99          PurchasingAccountsPayableFormBase purapForm = (PurchasingAccountsPayableFormBase) kualiDocumentFormBase;
100         PurchasingAccountsPayableDocument document = (PurchasingAccountsPayableDocument) purapForm.getDocument();
101 
102         // refresh the account summary (note this also updates the account amounts)
103         purapForm.refreshAccountSummmary();
104 
105         for (org.kuali.rice.krad.bo.Note note : (java.util.List<org.kuali.rice.krad.bo.Note>) document.getNotes()) {
106             note.refreshReferenceObject("attachment");
107         }
108 
109         // sort the below the line
110         SpringContext.getBean(PurapService.class).sortBelowTheLine(document);
111 
112         updateBaseline(document, (PurchasingAccountsPayableFormBase) kualiDocumentFormBase);
113     }
114 
115     /**
116      * Updates the baseline accounts on form and doc.
117      *
118      * @param document A descendant of PurchasingAccountsPayableDocument
119      */
120     protected <T extends PurchasingAccountsPayableDocument, V extends KualiAccountingDocumentFormBase> void updateBaseline(T document, V form) {
121         // clear out the old lines first
122         for (PurApItem item : document.getItems()) {
123             // clear out the old lines first
124             item.getBaselineSourceAccountingLines().clear();
125 
126             for (PurApAccountingLine sourceAccount : item.getSourceAccountingLines()) {
127                 // JHK: KFSMI-287 - removed deep copy since this object will be thrown away after the page renders, we just need a
128                 // different path to have them stored on the form
129                 // ESPECIALLY since PURAP does not allow lines to be reverted (see calls to setRevertible)
130                 item.getBaselineSourceAccountingLines().add(sourceAccount);
131             }
132         }
133     }
134 
135     /**
136      * Invokes a service method to refresh the account summary.
137      *
138      * @param mapping  An ActionMapping
139      * @param form     An ActionForm
140      * @param request  The HttpServletRequest
141      * @param response The HttpServletResponse
142      * @return An ActionForward
143      * @throws Exception
144      */
145     public ActionForward refreshAccountSummary(ActionMapping mapping, ActionForm form, HttpServletRequest request, HttpServletResponse response) throws Exception {
146         PurchasingAccountsPayableFormBase purapForm = (PurchasingAccountsPayableFormBase) form;
147         PurchasingAccountsPayableDocument document = (PurchasingAccountsPayableDocument) purapForm.getDocument();
148         SpringContext.getBean(PurapAccountingService.class).updateAccountAmounts(document);
149         purapForm.refreshAccountSummmary();
150         return mapping.findForward(OLEConstants.MAPPING_BASIC);
151     }
152 
153     /**
154      * @see org.kuali.ole.sys.web.struts.KualiAccountingDocumentActionBase#uploadAccountingLines(boolean, org.apache.struts.action.ActionForm)
155      */
156     @Override
157     protected void uploadAccountingLines(boolean isSource, ActionForm form) throws FileNotFoundException, IOException {
158         PurchasingAccountsPayableFormBase purapForm = (PurchasingAccountsPayableFormBase) form;
159         PurchasingAccountsPayableDocumentBase purapDocument = (PurchasingAccountsPayableDocumentBase) purapForm.getFinancialDocument();
160         PurApAccountingLineParser accountingLineParser = (PurApAccountingLineParser) purapDocument.getAccountingLineParser();
161         List importedLines = null;
162         String errorPathPrefix = PurapConstants.ACCOUNT_DISTRIBUTION_ERROR_KEY;
163         //String errorPathPrefix = "accountDistributionnewSourceLine";
164 
165         // import the lines
166         try {
167             FormFile sourceFile = purapForm.getSourceFile();
168             checkUploadFile(sourceFile);
169             GlobalVariables.getMessageMap().clearErrorPath();
170             GlobalVariables.getMessageMap().addToErrorPath(errorPathPrefix);
171             importedLines = accountingLineParser.importSourceAccountingLines(sourceFile.getFileName(), sourceFile.getInputStream(), purapDocument);
172             GlobalVariables.getMessageMap().removeFromErrorPath(errorPathPrefix);
173         } catch (AccountingLineParserException e) {
174             GlobalVariables.getMessageMap().putError(errorPathPrefix, e.getErrorKey(), e.getErrorParameters());
175         }
176 
177         // add to list those lines successfully imported
178         if (importedLines != null) {
179             for (Iterator iter = importedLines.iterator(); iter.hasNext(); ) {
180                 PurApAccountingLine importedLine = (PurApAccountingLine) iter.next();
181                 //boolean rulePassed = SpringContext.getBean(KualiRuleService.class).applyRules(new AddAccountingLineEvent(errorPathPrefix, purapForm.getDocument(), (AccountingLine) importedLine));
182                 //if (rulePassed) {
183                 // add accountingLine
184                 SpringContext.getBean(PersistenceService.class).retrieveNonKeyFields(importedLine);
185                 ((PurchasingFormBase) purapForm).addAccountDistributionsourceAccountingLine(importedLine);
186                 //}
187             }
188         }
189     }
190 
191     /**
192      * @see org.kuali.ole.sys.web.struts.KualiAccountingDocumentActionBase#insertSourceLine(org.apache.struts.action.ActionMapping,
193      *      org.apache.struts.action.ActionForm, javax.servlet.http.HttpServletRequest, javax.servlet.http.HttpServletResponse)
194      */
195     @Override
196     public ActionForward insertSourceLine(ActionMapping mapping, ActionForm form, HttpServletRequest request, HttpServletResponse response) throws Exception {
197         // It would be preferable to find a way to genericize the KualiAccountingDocument methods but this will work for now
198         PurchasingAccountsPayableFormBase purapForm = (PurchasingAccountsPayableFormBase) form;
199 
200         // index of item selected
201         int itemIndex = getSelectedLine(request);
202         PurApItem item = null;
203 
204         // if custom processing of an accounting line is not done then insert a line generically.
205         if (processCustomInsertAccountingLine(purapForm, request) == false) {
206             String errorPrefix = null;
207             PurApAccountingLine line = null;
208             boolean rulePassed = false;
209             if (itemIndex >= 0) {
210                 item = (PurApItem) ((PurchasingAccountsPayableDocument) purapForm.getDocument()).getItem((itemIndex));
211                 line = (PurApAccountingLine) ObjectUtils.deepCopy(item.getNewSourceLine());
212                 //SpringContext.getBean(AccountService.class).populateAccountingLineChartIfNeeded(line);
213                 errorPrefix = OLEPropertyConstants.DOCUMENT + "." + PurapPropertyConstants.ITEM + "[" + Integer.toString(itemIndex) + "]." + OLEConstants.NEW_SOURCE_ACCT_LINE_PROPERTY_NAME;
214                 rulePassed = SpringContext.getBean(KualiRuleService.class).applyRules(new AddAccountingLineEvent(errorPrefix, purapForm.getDocument(), (AccountingLine) line));
215             } else if (itemIndex == -2) {
216                 //corrected: itemIndex == -2 is the only case for distribute account
217                 //This is the case when we're inserting an accounting line for distribute account.
218                 line = ((PurchasingFormBase) purapForm).getAccountDistributionnewSourceLine();
219                 //SpringContext.getBean(AccountService.class).populateAccountingLineChartIfNeeded(line);
220                 errorPrefix = PurapPropertyConstants.ACCOUNT_DISTRIBUTION_NEW_SRC_LINE;
221                 rulePassed = SpringContext.getBean(KualiRuleService.class).applyRules(new AddAccountingLineEvent(errorPrefix, purapForm.getDocument(), (AccountingLine) line));
222             }
223 
224             if (rulePassed) {
225                 // add accountingLine
226                 SpringContext.getBean(PersistenceService.class).retrieveNonKeyFields(line);
227                 if (itemIndex >= 0) {
228                     insertAccountingLine(purapForm, item, line);
229                     // clear the temp account
230                     item.resetAccount();
231                 } else if (itemIndex == -2) {
232                     //this is the case for distribute account
233                     ((PurchasingFormBase) purapForm).addAccountDistributionsourceAccountingLine(line);
234                 }
235             }
236         }
237 
238         return mapping.findForward(OLEConstants.MAPPING_BASIC);
239     }
240 
241     /**
242      * Insert the given Accounting Line in several appropriate places in the given item and given form.
243      *
244      * @param financialDocumentForm A form that inherits from PurchasingAccountsPaybleFormBase
245      * @param item                  A PurApItem
246      * @param line                  A PurApAccountingLine
247      */
248     protected void insertAccountingLine(PurchasingAccountsPayableFormBase financialDocumentForm, PurApItem item, PurApAccountingLine line) {
249         PurchasingAccountsPayableDocument preq = (PurchasingAccountsPayableDocument) financialDocumentForm.getDocument();
250 
251         Integer index = item.getSourceAccountingLines().size() + 1;
252         line.setSequenceNumber(index);
253         // add it to the item
254         item.getSourceAccountingLines().add(line);
255     }
256 
257     /**
258      * Allows the custom processing of an accounting line during a call to insert source line. If a custom method for inserting an
259      * accounting line was performed, then a value of true must be returned.
260      *
261      * @param purapForm
262      * @param request
263      * @return boolean indicating if validation succeeded
264      */
265     public boolean processCustomInsertAccountingLine(PurchasingAccountsPayableFormBase purapForm, HttpServletRequest request) {
266         return false;
267     }
268 
269     /**
270      * Insert the given Accounting Line in several appropriate places in the given item and given form.
271      *
272      * @param financialDocumentForm A form that inherits from KualiAccountingDocumentFormBase
273      * @param item                  A PurApItem
274      * @param line                  A PurApAccountingLine
275      */
276     protected void insertAccountingLine(KualiAccountingDocumentFormBase financialDocumentForm, PurApItem item, PurApAccountingLine line) {
277         // add it to the item
278         item.getSourceAccountingLines().add(line);
279     }
280 
281     /**
282      * @see org.kuali.ole.sys.web.struts.KualiAccountingDocumentActionBase#deleteSourceLine(org.apache.struts.action.ActionMapping,
283      *      org.apache.struts.action.ActionForm, javax.servlet.http.HttpServletRequest, javax.servlet.http.HttpServletResponse)
284      */
285     @Override
286     public ActionForward deleteSourceLine(ActionMapping mapping, ActionForm form, HttpServletRequest request, HttpServletResponse response) throws Exception {
287         PurchasingAccountsPayableFormBase purapForm = (PurchasingAccountsPayableFormBase) form;
288 
289         String[] indexes = getSelectedLineForAccounts(request);
290         int itemIndex = Integer.parseInt(indexes[0]);
291         int accountIndex = Integer.parseInt(indexes[1]);
292 
293         PurApItem item = (PurApItem) ((PurchasingAccountsPayableDocument) purapForm.getDocument()).getItem((itemIndex));
294         if (itemIndex == -2) {
295             item.getSourceAccountingLines().remove(accountIndex);
296         } else {
297             item.getSourceAccountingLines().remove(accountIndex);
298             List<PurApAccountingLine> purApAccountingLineList = item.getSourceAccountingLines();
299             BigDecimal initialPercent = new BigDecimal(0);
300             for (PurApAccountingLine purApAccountingLine : purApAccountingLineList) {
301                 initialPercent = initialPercent.add(purApAccountingLine.getAccountLinePercent());
302             }
303             initialPercent = new BigDecimal(100).subtract(initialPercent);
304             if(initialPercent.intValue()>0){
305                 item.resetAccount(initialPercent);
306             }
307             else{
308                 item.resetAccount(new BigDecimal(0));
309             }
310         }
311         return mapping.findForward(OLEConstants.MAPPING_BASIC);
312     }
313 
314     /**
315      * @see org.kuali.ole.sys.web.struts.KualiAccountingDocumentActionBase#getSourceAccountingLine(org.apache.struts.action.ActionForm,
316      *      javax.servlet.http.HttpServletRequest)
317      */
318     @Override
319     public SourceAccountingLine getSourceAccountingLine(ActionForm form, HttpServletRequest request) {
320         String[] indexes = getSelectedLineForAccounts(request);
321         int itemIndex = Integer.parseInt(indexes[0]);
322         int accountIndex = Integer.parseInt(indexes[1]);
323         PurchasingAccountsPayableFormBase purchasingAccountsPayableForm = (PurchasingAccountsPayableFormBase) form;
324         SourceAccountingLine line;
325         if (itemIndex == -2) {
326             line = customAccountRetrieval(accountIndex, purchasingAccountsPayableForm);
327         } else {
328             PurApItem item = (PurApItem) ((PurchasingAccountsPayableDocument) purchasingAccountsPayableForm.getDocument()).getItem((itemIndex));
329             line = (SourceAccountingLine) ObjectUtils.deepCopy(item.getSourceAccountingLines().get(accountIndex));
330         }
331         return line;
332     }
333 
334     /**
335      * Perform custom processing on accounting lines. See <code>getSelectedLineForAccounts</code>.
336      *
337      * @param accountIndex                  The index of the account into the request parameter
338      * @param purchasingAccountsPayableForm A form which inherits from PurchasingAccountsPayableFormBase
339      * @return A SourceAccountingLine
340      */
341     protected SourceAccountingLine customAccountRetrieval(int accountIndex, PurchasingAccountsPayableFormBase purchasingAccountsPayableForm) {
342         // default impl returns null
343         return null;
344     }
345 
346     /**
347      * Will return an array of Strings containing 2 indexes, the first String is the item index and the second String is the account
348      * index. These are obtained by parsing the method to call parameter from the request, between the word ".line" and "." The
349      * indexes are separated by a semicolon (:)
350      *
351      * @param request The HttpServletRequest
352      * @return An array of Strings containing pairs of two indices, an item index and a account index
353      */
354     protected String[] getSelectedLineForAccounts(HttpServletRequest request) {
355         String accountString = new String();
356         String parameterName = (String) request.getAttribute(OLEConstants.METHOD_TO_CALL_ATTRIBUTE);
357         if (StringUtils.isNotBlank(parameterName)) {
358             accountString = StringUtils.substringBetween(parameterName, ".line", ".");
359         }
360         String[] result = StringUtils.split(accountString, ":");
361 
362         return result;
363     }
364 
365     /**
366      * @see org.kuali.rice.kns.web.struts.action.KualiDocumentActionBase#downloadBOAttachment(org.apache.struts.action.ActionMapping,
367      *      org.apache.struts.action.ActionForm, javax.servlet.http.HttpServletRequest, javax.servlet.http.HttpServletResponse)
368      */
369     @Override
370     public ActionForward downloadBOAttachment(ActionMapping mapping, ActionForm form, HttpServletRequest request, HttpServletResponse response) throws Exception {
371         PurchasingAccountsPayableDocument document = (PurchasingAccountsPayableDocument) ((PurchasingAccountsPayableFormBase) form).getDocument();
372 
373         for (org.kuali.rice.krad.bo.Note note : (java.util.List<org.kuali.rice.krad.bo.Note>) document.getNotes()) {
374             note.refreshReferenceObject("attachment");
375         }
376 
377         return super.downloadBOAttachment(mapping, form, request, response);
378     }
379 
380     @Override
381     protected void processAccountingLineOverrides(List accountingLines) {
382         //do nothing purap handles these differently
383     }
384 
385     /**
386      * Perform calculation on item line.
387      *
388      * @param mapping  An ActionMapping
389      * @param form     An ActionForm
390      * @param request  The HttpServletRequest
391      * @param response The HttpServletResponse
392      * @return An ActionForward
393      */
394     public ActionForward calculate(ActionMapping mapping, ActionForm form, HttpServletRequest request, HttpServletResponse response) throws Exception {
395         return mapping.findForward(OLEConstants.MAPPING_BASIC);
396     }
397 
398     public ActionForward clearAllTaxes(ActionMapping mapping, ActionForm form, HttpServletRequest request, HttpServletResponse response) throws Exception {
399         return mapping.findForward(OLEConstants.MAPPING_BASIC);
400     }
401 
402     protected void customCalculate(PurchasingAccountsPayableDocument purapDoc) {
403         // do nothing by default
404     }
405 
406     /**
407      * Toggles all specific tabs to open
408      *
409      * @param mapping
410      * @param form
411      * @param request
412      * @param response
413      * @return
414      * @throws Exception
415      */
416     public ActionForward showAllAccounts(ActionMapping mapping, ActionForm form, HttpServletRequest request, HttpServletResponse response) throws Exception {
417         KualiForm kualiForm = (KualiForm) form;
418         String accountingLineTab = "AccountingLines";
419         String value = null;
420 
421         Map<String, String> tabStates = kualiForm.getTabStates();
422         Map<String, String> newTabStates = new HashMap<String, String>();
423         for (Entry<String, String> tabEntry : tabStates.entrySet()) {
424             if (tabEntry.getKey().startsWith(accountingLineTab)) {
425                 newTabStates.put(tabEntry.getKey(), "OPEN");
426             } else {
427                 if (tabEntry.getValue() instanceof String) {
428                     value = tabEntry.getValue();
429                 } else {
430                     //This is the case where the value is an Array of String,
431                     //so we'll have to get the first element
432                     Object result = tabEntry.getValue();
433                     result.getClass();
434                     value = ((String[]) result)[0];
435                 }
436                 newTabStates.put(tabEntry.getKey(), value);
437             }
438         }
439         kualiForm.setTabStates(newTabStates);
440         return mapping.findForward(RiceConstants.MAPPING_BASIC);
441     }
442 
443     /**
444      * Toggles all specific tabs to closed
445      *
446      * @param mapping
447      * @param form
448      * @param request
449      * @param response
450      * @return
451      * @throws Exception
452      */
453     public ActionForward hideAllAccounts(ActionMapping mapping, ActionForm form, HttpServletRequest request, HttpServletResponse response) throws Exception {
454         KualiForm kualiForm = (KualiForm) form;
455         String accountingLineTab = "AccountingLines";
456         String value = null;
457 
458         Map<String, String> tabStates = kualiForm.getTabStates();
459         Map<String, String> newTabStates = new HashMap<String, String>();
460         for (Entry<String, String> tabEntry : tabStates.entrySet()) {
461             if (tabEntry.getKey().startsWith(accountingLineTab)) {
462                 newTabStates.put(tabEntry.getKey(), "CLOSE");
463             } else {
464                 if (tabEntry.getValue() instanceof String) {
465                     value = tabEntry.getValue();
466                 } else {
467                     //This is the case where the value is an Array of String,
468                     //so we'll have to get the first element
469                     Object result = tabEntry.getValue();
470                     result.getClass();
471                     value = ((String[]) result)[0];
472                 }
473                 newTabStates.put(tabEntry.getKey(), value);
474             }
475         }
476         kualiForm.setTabStates(newTabStates);
477         return mapping.findForward(RiceConstants.MAPPING_BASIC);
478     }
479 
480     /**
481      * Override to verify the document has been saved before the note is inserted. This will assure the correct parent object id is
482      * associated with the note.
483      *
484      * @see org.kuali.rice.kns.web.struts.action.KualiDocumentActionBase#insertBONote(org.apache.struts.action.ActionMapping,
485      *      org.apache.struts.action.ActionForm, javax.servlet.http.HttpServletRequest, javax.servlet.http.HttpServletResponse)
486      */
487     @Override
488     public ActionForward insertBONote(ActionMapping mapping, ActionForm form, HttpServletRequest request, HttpServletResponse response) throws Exception {
489         PurchasingAccountsPayableDocument document = (PurchasingAccountsPayableDocument) ((PurchasingAccountsPayableFormBase) form).getDocument();
490         WorkflowDocument workflowDocument = document.getDocumentHeader().getWorkflowDocument();
491 
492         if (workflowDocument.isInitiated()) {
493             SpringContext.getBean(DocumentService.class).saveDocument(document);
494         }
495 
496         return super.insertBONote(mapping, form, request, response);
497     }
498 
499 }