View Javadoc
1   /*
2    * The Kuali Financial System, a comprehensive financial management system for higher education.
3    * 
4    * Copyright 2005-2014 The Kuali Foundation
5    * 
6    * This program is free software: you can redistribute it and/or modify
7    * it under the terms of the GNU Affero General Public License as
8    * published by the Free Software Foundation, either version 3 of the
9    * License, or (at your option) any later version.
10   * 
11   * This program is distributed in the hope that it will be useful,
12   * but WITHOUT ANY WARRANTY; without even the implied warranty of
13   * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
14   * GNU Affero General Public License for more details.
15   * 
16   * You should have received a copy of the GNU Affero General Public License
17   * along with this program.  If not, see <http://www.gnu.org/licenses/>.
18   */
19  package org.kuali.kfs.fp.document.web.struts;
20  
21  import java.io.FileNotFoundException;
22  import java.io.IOException;
23  import java.util.ArrayList;
24  import java.util.Iterator;
25  import java.util.List;
26  
27  import javax.servlet.http.HttpServletRequest;
28  import javax.servlet.http.HttpServletResponse;
29  
30  import org.apache.commons.lang.StringUtils;
31  import org.apache.struts.action.ActionForm;
32  import org.apache.struts.action.ActionForward;
33  import org.apache.struts.action.ActionMapping;
34  import org.apache.struts.upload.FormFile;
35  import org.kuali.kfs.fp.businessobject.ProcurementCardTargetAccountingLine;
36  import org.kuali.kfs.fp.businessobject.ProcurementCardTransactionDetail;
37  import org.kuali.kfs.fp.document.ProcurementCardDocument;
38  import org.kuali.kfs.sys.KFSConstants;
39  import org.kuali.kfs.sys.KFSKeyConstants;
40  import org.kuali.kfs.sys.businessobject.AccountingLine;
41  import org.kuali.kfs.sys.businessobject.AccountingLineParser;
42  import org.kuali.kfs.sys.businessobject.TargetAccountingLine;
43  import org.kuali.kfs.sys.context.SpringContext;
44  import org.kuali.kfs.sys.document.AccountingDocument;
45  import org.kuali.kfs.sys.document.validation.event.AddAccountingLineEvent;
46  import org.kuali.kfs.sys.document.validation.event.DeleteAccountingLineEvent;
47  import org.kuali.kfs.sys.exception.AccountingLineParserException;
48  import org.kuali.kfs.sys.web.struts.KualiAccountingDocumentFormBase;
49  import org.kuali.rice.kew.api.exception.WorkflowException;
50  import org.kuali.rice.kns.web.struts.form.KualiDocumentFormBase;
51  import org.kuali.rice.krad.service.KualiRuleService;
52  import org.kuali.rice.krad.service.PersistenceService;
53  import org.kuali.rice.krad.util.GlobalVariables;
54  import org.kuali.rice.krad.util.KRADConstants;
55  /**
56   * This class handles specific Actions requests for the ProcurementCard.
57   */
58  public class ProcurementCardAction extends CapitalAccountingLinesActionBase {
59      private static org.apache.log4j.Logger LOG = org.apache.log4j.Logger.getLogger(ProcurementCardAction.class);
60  
61      @Override
62      protected void loadDocument(KualiDocumentFormBase kualiDocumentFormBase) throws WorkflowException {
63          super.loadDocument(kualiDocumentFormBase);
64          ProcurementCardDocument procureCardDocument = (ProcurementCardDocument)kualiDocumentFormBase.getDocument();
65          int transactionsCount = procureCardDocument.getTransactionEntries().size();
66          ProcurementCardForm procurementCardForm = (ProcurementCardForm)kualiDocumentFormBase;
67          procurementCardForm.buildNewTargetAccountingLines(transactionsCount);
68      }
69  
70      /**
71       * Override to accomodate multiple target lines.
72       *
73       * @param transForm
74       */
75      @Override
76      protected void processAccountingLineOverrides(KualiAccountingDocumentFormBase transForm) {
77          ProcurementCardForm procurementCardForm = (ProcurementCardForm) transForm;
78  
79          processAccountingLineOverrides(procurementCardForm.getNewSourceLine());
80          processAccountingLineOverrides(procurementCardForm.getNewTargetLines());
81          if (procurementCardForm.hasDocumentId()) {
82              AccountingDocument financialDocument = (AccountingDocument) procurementCardForm.getDocument();
83  
84              processAccountingLineOverrides(financialDocument.getSourceAccountingLines());
85              processAccountingLineOverrides(financialDocument.getTargetAccountingLines());
86          }
87      }
88  
89      /**
90       * Override to add the new accounting line to the correct transaction
91       *
92       * @see org.kuali.module.financial.web.struts.action.KualiFinancialDocumentActionBase#insertTargetLine(org.apache.struts.action.ActionMapping,
93       *      org.apache.struts.action.ActionForm, javax.servlet.http.HttpServletRequest, javax.servlet.http.HttpServletResponse)
94       */
95      @Override
96      public ActionForward insertTargetLine(ActionMapping mapping, ActionForm form, HttpServletRequest request, HttpServletResponse response) throws Exception {
97          ProcurementCardForm procurementCardForm = (ProcurementCardForm) form;
98          ProcurementCardDocument procurementCardDocument = (ProcurementCardDocument) procurementCardForm.getDocument();
99  
100         int targetContainerIndex = this.getSelectedContainer(request);
101         ProcurementCardTargetAccountingLine line = (ProcurementCardTargetAccountingLine)procurementCardForm.getNewTargetLines().get(targetContainerIndex);
102 
103         ProcurementCardTransactionDetail transactionDetail = (ProcurementCardTransactionDetail) procurementCardDocument.getTransactionEntries().get(targetContainerIndex);
104         line.setFinancialDocumentTransactionLineNumber(transactionDetail.getFinancialDocumentTransactionLineNumber());
105 
106         // check any business rules
107         boolean rulePassed = SpringContext.getBean(KualiRuleService.class).applyRules(new AddAccountingLineEvent(KFSConstants.NEW_TARGET_ACCT_LINES_PROPERTY_NAME + "[" + Integer.toString(targetContainerIndex) + "]", procurementCardForm.getDocument(), line));
108 
109         if (rulePassed) {
110             // add accountingLine
111             SpringContext.getBean(PersistenceService.class).retrieveNonKeyFields(line);
112             insertAccountingLine(false, procurementCardForm, line);
113 
114             ProcurementCardTargetAccountingLine newLine = new ProcurementCardTargetAccountingLine();
115             newLine.setTransactionContainerIndex(targetContainerIndex);
116 
117             procurementCardForm.getNewTargetLines().set(targetContainerIndex, newLine);
118         }
119 
120         return mapping.findForward(KFSConstants.MAPPING_BASIC);
121     }
122 
123     /**
124      * @see org.kuali.kfs.sys.web.struts.KualiAccountingDocumentActionBase#performBalanceInquiryForTargetLine(org.apache.struts.action.ActionMapping,
125      *      org.apache.struts.action.ActionForm, javax.servlet.http.HttpServletRequest, javax.servlet.http.HttpServletResponse)
126      */
127     @Override
128     public ActionForward performBalanceInquiryForTargetLine(ActionMapping mapping, ActionForm form, HttpServletRequest request, HttpServletResponse response) throws Exception {
129         ProcurementCardForm procurementCardForm = (ProcurementCardForm) form;
130         ProcurementCardDocument procurementCardDocument = (ProcurementCardDocument) procurementCardForm.getDocument();
131 
132         int targetContainerIndex = this.getSelectedContainer(request);
133         ProcurementCardTransactionDetail ProcurementCardTransactionDetail = (ProcurementCardTransactionDetail) procurementCardDocument.getTransactionEntries().get(targetContainerIndex);
134 
135         int targetIndex = super.getSelectedLine(request);
136         TargetAccountingLine targetLine = (ProcurementCardTargetAccountingLine) ProcurementCardTransactionDetail.getTargetAccountingLines().get(targetIndex);
137 
138         return performBalanceInquiryForAccountingLine(mapping, form, request, targetLine);
139     }
140 
141     /**
142      * Override to resync base accounting lines. New lines on the PCDO document can be inserted anywhere in the list, not necessary
143      * at the end.
144      *
145      * @see org.kuali.module.financial.web.struts.action.KualiFinancialDocumentActionBase#insertAccountingLine(boolean,
146      *      org.kuali.module.financial.web.struts.form.KualiFinancialDocumentFormBase, org.kuali.rice.krad.bo.AccountingLine)
147      */
148     @Override
149     protected void insertAccountingLine(boolean isSource, KualiAccountingDocumentFormBase financialDocumentForm, AccountingLine line) {
150         AccountingDocument tdoc = financialDocumentForm.getFinancialDocument();
151 
152         // add it to the document
153         tdoc.addTargetAccountingLine((TargetAccountingLine) line);
154     }
155 
156     /**
157      * Override to get the correct container of the transaction and then delete the correct accounting line
158      *
159      * @see org.kuali.module.financial.web.struts.action.KualiFinancialDocumentActionBase#deleteTargetLine(ActionMapping mapping, ActionForm form, HttpServletRequest request, HttpServletResponse response
160      */
161     @Override
162     public ActionForward deleteTargetLine(ActionMapping mapping, ActionForm form, HttpServletRequest request, HttpServletResponse response) throws Exception {
163         int targetContainerIndex = this.getSelectedContainer(request);
164         int targetIndex = this.getSelectedLine(request);
165 
166         KualiAccountingDocumentFormBase financialDocumentForm = (KualiAccountingDocumentFormBase) form;
167 
168         String errorPath = KFSConstants.DOCUMENT_PROPERTY_NAME + "." + KFSConstants.EXISTING_TARGET_ACCT_LINE_PROPERTY_NAME + "[" + targetIndex + "]";
169         boolean rulePassed = SpringContext.getBean(KualiRuleService.class).applyRules(new DeleteAccountingLineEvent(errorPath, financialDocumentForm.getDocument(), ((AccountingDocument) financialDocumentForm.getDocument()).getTargetAccountingLine(targetIndex), false));
170 
171         // if the rule evaluation passed, let's delete it
172         if (rulePassed) {
173             deleteAccountingLineFromTransactionContainer(financialDocumentForm, targetContainerIndex, targetIndex);
174         }
175         else {
176             String[] errorParams = new String[] { "target", Integer.toString(targetIndex + 1) };
177             GlobalVariables.getMessageMap().putError(errorPath, KFSKeyConstants.ERROR_ACCOUNTINGLINE_DELETERULE_INVALIDACCOUNT, errorParams);
178         }
179 
180         return mapping.findForward(KFSConstants.MAPPING_BASIC);
181     }
182 
183     /**
184      * Override to remove the accounting line from the correct transaction
185      *
186      * @see org.kuali.module.financial.web.struts.action.KualiFinancialDocumentActionBase#deleteAccountingLine(boolean,
187      *      org.kuali.module.financial.web.struts.form.KualiFinancialDocumentFormBase, int)
188      */
189     @Override
190     protected void deleteAccountingLine(boolean isSource, KualiAccountingDocumentFormBase financialDocumentForm, int deleteIndex) {
191         ProcurementCardDocument procurementCardDocument = (ProcurementCardDocument) financialDocumentForm.getDocument();
192         procurementCardDocument.removeTargetAccountingLine(deleteIndex);
193     }
194 
195     /**
196      * Ensures that ProcurementCardForm.newTargetLines is cleared. Otherwise works like super.reload.
197      *
198      * @see org.kuali.rice.kns.web.struts.action.KualiDocumentActionBase#reload(org.apache.struts.action.ActionMapping,
199      *      org.apache.struts.action.ActionForm, javax.servlet.http.HttpServletRequest, javax.servlet.http.HttpServletResponse)
200      */
201     @Override
202     public ActionForward reload(ActionMapping mapping, ActionForm form, HttpServletRequest request, HttpServletResponse response) throws Exception {
203         ProcurementCardForm procurementCardForm = (ProcurementCardForm) form;
204         procurementCardForm.setNewTargetLines(new ArrayList<ProcurementCardTargetAccountingLine>());
205 
206         return super.reload(mapping, procurementCardForm, request, response);
207     }
208 
209     // get the index of selected transaction entry
210     protected int getSelectedContainer(HttpServletRequest request) {
211         int selectedContainer = -1;
212         String parameterName = (String) request.getAttribute(KRADConstants.METHOD_TO_CALL_ATTRIBUTE);
213         if (StringUtils.isNotBlank(parameterName)) {
214             String lineNumber = StringUtils.substringBetween(parameterName, ".transactionEntries[", "].");
215             selectedContainer = Integer.parseInt(lineNumber);
216         }
217 
218         return selectedContainer;
219     }
220 
221     /**
222      * Removes the target accounting line at the given index from the transaction container transaction entries.
223      *
224      * @param financialDocumentForm, targetContainerIndex, targetIndex
225      */
226     protected void deleteAccountingLineFromTransactionContainer(KualiAccountingDocumentFormBase financialDocumentForm, int targetContainerIndex, int targetIndex) {
227         ProcurementCardDocument procurementCardDocument = (ProcurementCardDocument) financialDocumentForm.getDocument();
228         ProcurementCardTransactionDetail procurementCardTransactionDetail = (ProcurementCardTransactionDetail) procurementCardDocument.getTransactionEntries().get(targetContainerIndex);
229         procurementCardTransactionDetail.getTargetAccountingLines().remove(targetIndex);
230     }
231 
232     /**
233      *
234      * @see org.kuali.kfs.sys.web.struts.KualiAccountingDocumentActionBase#uploadTargetLines(org.apache.struts.action.ActionMapping,
235      *      org.apache.struts.action.ActionForm, javax.servlet.http.HttpServletRequest, javax.servlet.http.HttpServletResponse)
236      */
237     @Override
238     public ActionForward uploadTargetLines(ActionMapping mapping, ActionForm form, HttpServletRequest request, HttpServletResponse response) throws Exception {
239         ProcurementCardForm procurementCardForm = (ProcurementCardForm) form;
240         ProcurementCardDocument procurementCardDocument = (ProcurementCardDocument) procurementCardForm.getDocument();
241 
242         // get index of transaction line
243         int tranasactionIndex = getTransactionLineIndex(request);
244 
245         uploadTargetAccountingLines(form, tranasactionIndex);
246 
247         return mapping.findForward(KFSConstants.MAPPING_BASIC);
248     }
249 
250     /**
251      * This method handles retrieving the actual upload file as an input stream into the document.
252      *
253      * @param isSource
254      * @param form
255      * @throws FileNotFoundException
256      * @throws IOException
257      */
258     protected void uploadTargetAccountingLines(ActionForm form, int tranasactionIndex) throws FileNotFoundException, IOException {
259         ProcurementCardForm pcardForm = (ProcurementCardForm) form;
260 
261         List importedLines = null;
262 
263         ProcurementCardDocument procurementCardDocument = (ProcurementCardDocument) pcardForm.getFinancialDocument();
264         ProcurementCardTransactionDetail transactionDetail = (ProcurementCardTransactionDetail) procurementCardDocument.getTransactionEntries().get(tranasactionIndex);
265 
266         AccountingLineParser accountingLineParser = procurementCardDocument.getAccountingLineParser();
267 
268         // import the lines
269         String errorPathPrefix = null;
270         try {
271             errorPathPrefix = KFSConstants.DOCUMENT_PROPERTY_NAME + "." + KFSConstants.TARGET_ACCOUNTING_LINE_ERRORS;
272             // get the import file
273             FormFile targetFile = ((ProcurementCardTransactionDetail) (procurementCardDocument.getTransactionEntries().get(tranasactionIndex))).getTargetFile();
274             checkUploadFile(targetFile);
275             importedLines = accountingLineParser.importTargetAccountingLines(targetFile.getFileName(), targetFile.getInputStream(), procurementCardDocument);
276         }
277         catch (AccountingLineParserException e) {
278             GlobalVariables.getMessageMap().putError(errorPathPrefix, e.getErrorKey(), e.getErrorParameters());
279         }
280 
281         // add line to list for those lines which were successfully imported
282         if (importedLines != null) {
283             for (Iterator i = importedLines.iterator(); i.hasNext();) {
284                 ProcurementCardTargetAccountingLine importedLine = (ProcurementCardTargetAccountingLine) i.next();
285                 importedLine.setFinancialDocumentTransactionLineNumber(transactionDetail.getFinancialDocumentTransactionLineNumber());
286                 super.insertAccountingLine(false, pcardForm, importedLine);
287             }
288         }
289     }
290 
291     /**
292      * Parses the method to call attribute to pick off the transaction line number which should have an action performed
293      * on it.
294      *
295      * @param request
296      * @return
297      */
298     protected int getTransactionLineIndex(HttpServletRequest request) {
299         int selectedLine = -1;
300         String parameterName = (String) request.getAttribute(KFSConstants.METHOD_TO_CALL_ATTRIBUTE);
301         if (StringUtils.isNotBlank(parameterName)) {
302             String lineNumber = StringUtils.substringBetween(parameterName, "document.transactionEntries[", "]");
303             selectedLine = Integer.parseInt(lineNumber);
304         }
305 
306         return selectedLine;
307     }
308 }