001    /*
002     * Copyright 2011 The Kuali Foundation.
003     * 
004     * Licensed under the Educational Community License, Version 2.0 (the "License");
005     * you may not use this file except in compliance with the License.
006     * You may obtain a copy of the License at
007     * 
008     * http://www.opensource.org/licenses/ecl2.php
009     * 
010     * Unless required by applicable law or agreed to in writing, software
011     * distributed under the License is distributed on an "AS IS" BASIS,
012     * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
013     * See the License for the specific language governing permissions and
014     * limitations under the License.
015     */
016    package org.kuali.kfs.module.endow.document.web.struts;
017    
018    import java.io.FileNotFoundException;
019    import java.io.IOException;
020    import java.util.Iterator;
021    import java.util.List;
022    import java.util.Properties;
023    
024    import javax.servlet.http.HttpServletRequest;
025    import javax.servlet.http.HttpServletResponse;
026    
027    import org.apache.commons.lang.StringUtils;
028    import org.apache.struts.action.ActionForm;
029    import org.apache.struts.action.ActionForward;
030    import org.apache.struts.action.ActionMapping;
031    import org.apache.struts.upload.FormFile;
032    import org.kuali.kfs.module.endow.EndowConstants;
033    import org.kuali.kfs.module.endow.EndowKeyConstants;
034    import org.kuali.kfs.module.endow.EndowPropertyConstants;
035    import org.kuali.kfs.module.endow.businessobject.EndowmentAccountingLine;
036    import org.kuali.kfs.module.endow.businessobject.EndowmentAccountingLineParser;
037    import org.kuali.kfs.module.endow.businessobject.KEMIDCurrentBalance;
038    import org.kuali.kfs.module.endow.businessobject.SourceEndowmentAccountingLine;
039    import org.kuali.kfs.module.endow.businessobject.TargetEndowmentAccountingLine;
040    import org.kuali.kfs.module.endow.document.EndowmentAccountingLinesDocument;
041    import org.kuali.kfs.module.endow.document.EndowmentAccountingLinesDocumentBase;
042    import org.kuali.kfs.module.endow.document.validation.event.AddEndowmentAccountingLineEvent;
043    import org.kuali.kfs.module.endow.document.validation.event.DeleteAccountingLineEvent;
044    import org.kuali.kfs.module.endow.exception.EndowmentAccountingLineException;
045    import org.kuali.kfs.sys.KFSConstants;
046    import org.kuali.kfs.sys.KFSKeyConstants;
047    import org.kuali.kfs.sys.businessobject.FinancialSystemDocumentHeader;
048    import org.kuali.kfs.sys.context.SpringContext;
049    import org.kuali.kfs.sys.document.AmountTotaling;
050    import org.kuali.rice.kns.service.KualiConfigurationService;
051    import org.kuali.rice.kns.service.KualiRuleService;
052    import org.kuali.rice.kns.util.GlobalVariables;
053    import org.kuali.rice.kns.util.KNSConstants;
054    import org.kuali.rice.kns.util.UrlFactory;
055    import org.kuali.rice.kns.web.struts.form.KualiForm;
056    
057    public class EndowmentAccountingLinesDocumentActionBase extends EndowmentTransactionLinesDocumentActionBase {
058        protected static org.apache.log4j.Logger log = org.apache.log4j.Logger.getLogger(EndowmentAccountingLinesDocumentActionBase.class);
059    
060        /**
061         * This action executes an insert of an TargetEndowmentAccountingLine into a document only after validating the Accounting line
062         * and checking any appropriate business rules.
063         * 
064         * @param mapping
065         * @param form
066         * @param request
067         * @param response
068         * @return
069         * @throws Exception
070         */
071        public ActionForward insertTargetAccountingLine(ActionMapping mapping, ActionForm form, HttpServletRequest request, HttpServletResponse response) throws Exception {
072            EndowmentAccountingLinesDocumentFormBase documentForm = (EndowmentAccountingLinesDocumentFormBase) form;
073            EndowmentAccountingLinesDocument endowmentDocument = (EndowmentAccountingLinesDocument) documentForm.getDocument();
074    
075            TargetEndowmentAccountingLine accLine = (TargetEndowmentAccountingLine) documentForm.getNewTargetAccountingLine();
076    
077            boolean rulePassed = true;
078    
079            // check any business rules
080            rulePassed &= SpringContext.getBean(KualiRuleService.class).applyRules(new AddEndowmentAccountingLineEvent(EndowConstants.NEW_TARGET_ACC_LINE_PROPERTY_NAME, endowmentDocument, accLine));
081    
082            if (rulePassed) {
083                // add accountingLine
084    
085                // SpringContext.getBean(PersistenceService.class).refreshAllNonUpdatingReferences(transLine);
086                insertAccountingLine(false, documentForm, accLine);
087    
088                // clear the used newTargetLine
089                documentForm.setNewTargetAccountingLine(new TargetEndowmentAccountingLine());
090            }
091    
092            return mapping.findForward(KFSConstants.MAPPING_BASIC);
093        }
094    
095        /**
096         * This action executes an insert of an SourceEndowmentAccountingLine into a document only after validating the Accounting line
097         * and checking any appropriate business rules.
098         * 
099         * @param mapping
100         * @param form
101         * @param request
102         * @param response
103         * @return
104         * @throws Exception
105         */
106        public ActionForward insertSourceAccountingLine(ActionMapping mapping, ActionForm form, HttpServletRequest request, HttpServletResponse response) throws Exception {
107            EndowmentAccountingLinesDocumentFormBase documentForm = (EndowmentAccountingLinesDocumentFormBase) form;
108            EndowmentAccountingLinesDocument endowmentDocument = (EndowmentAccountingLinesDocument) documentForm.getDocument();
109    
110            SourceEndowmentAccountingLine accLine = (SourceEndowmentAccountingLine) documentForm.getNewSourceAccountingLine();
111    
112            boolean rulePassed = true;
113    
114            // check any business rules
115            rulePassed &= SpringContext.getBean(KualiRuleService.class).applyRules(new AddEndowmentAccountingLineEvent(EndowConstants.NEW_SOURCE_ACC_LINE_PROPERTY_NAME, endowmentDocument, accLine));
116    
117            if (rulePassed) {
118                // add accountingLine
119                // SpringContext.getBean(PersistenceService.class).refreshAllNonUpdatingReferences(transLine);
120                insertAccountingLine(true, documentForm, accLine);
121    
122                // clear the used newTargetLine
123                documentForm.setNewSourceAccountingLine(new SourceEndowmentAccountingLine());
124            }
125    
126            return mapping.findForward(KFSConstants.MAPPING_BASIC);
127        }
128    
129        /**
130         * Adds the given accountingLine to the appropriate form-related data structures.
131         * 
132         * @param isSource
133         * @param etlDocumentForm
134         * @param line
135         */
136        protected void insertAccountingLine(boolean isSource, EndowmentAccountingLinesDocumentFormBase etaDocumentForm, EndowmentAccountingLine line) {
137            EndowmentAccountingLinesDocumentBase etaDoc = etaDocumentForm.getEndowmentAccountingLinesDocumentBase();
138    
139            if (isSource) {
140                // add it to the document
141                etaDoc.addSourceAccountingLine((SourceEndowmentAccountingLine) line);
142            }
143            else {
144                // add it to the document
145                etaDoc.addTargetAccountingLine((TargetEndowmentAccountingLine) line);
146            }
147    
148            // Update the doc total
149            if (etaDoc instanceof AmountTotaling)
150                ((FinancialSystemDocumentHeader) etaDocumentForm.getDocument().getDocumentHeader()).setFinancialDocumentTotalAmount(((AmountTotaling) etaDoc).getTotalDollarAmount());
151        }
152    
153        /**
154         * This action deletes an EndowmentSourceAccountingLine from a document.
155         * 
156         * @param mapping
157         * @param form
158         * @param request
159         * @param response
160         * @return
161         * @throws Exception
162         */
163        public ActionForward deleteSourceAccountingLine(ActionMapping mapping, ActionForm form, HttpServletRequest request, HttpServletResponse response) throws Exception {
164            EndowmentAccountingLinesDocumentFormBase etlForm = (EndowmentAccountingLinesDocumentFormBase) form;
165            EndowmentAccountingLinesDocument etlDoc = etlForm.getEndowmentAccountingLinesDocumentBase();
166    
167            int deleteIndex = getLineToDelete(request);
168            String errorPath = EndowPropertyConstants.EXISTING_SOURCE_ACCT_LINE_PREFIX + "[" + deleteIndex + "]";
169            boolean rulePassed = SpringContext.getBean(KualiRuleService.class).applyRules(new DeleteAccountingLineEvent(errorPath, etlDoc, etlDoc.getSourceAccountingLine(deleteIndex)));
170    
171            // if the rule evaluation passed, let's delete it
172            if (rulePassed) {
173                deleteAccountingLine(true, etlForm, deleteIndex);
174            }
175            else {
176                String[] errorParams = new String[] { "source", Integer.toString(deleteIndex + 1) };
177                GlobalVariables.getMessageMap().putError(errorPath, EndowKeyConstants.EndowmentTransactionDocumentConstants.ERROR_DELETING_ACCOUNTING_LINE, errorParams);
178            }
179    
180            return mapping.findForward(KFSConstants.MAPPING_BASIC);
181        }
182    
183        /**
184         * This action deletes an EndowmentTargetAccountingLine from a document.
185         * 
186         * @param mapping
187         * @param form
188         * @param request
189         * @param response
190         * @return
191         * @throws Exception
192         */
193        public ActionForward deleteTargetAccountingLine(ActionMapping mapping, ActionForm form, HttpServletRequest request, HttpServletResponse response) throws Exception {
194            EndowmentAccountingLinesDocumentFormBase etlForm = (EndowmentAccountingLinesDocumentFormBase) form;
195            EndowmentAccountingLinesDocument etlDoc = etlForm.getEndowmentAccountingLinesDocumentBase();
196    
197            int deleteIndex = getLineToDelete(request);
198            String errorPath = EndowPropertyConstants.EXISTING_TARGET_ACCT_LINE_PREFIX + "[" + deleteIndex + "]";
199            boolean rulePassed = SpringContext.getBean(KualiRuleService.class).applyRules(new DeleteAccountingLineEvent(errorPath, etlDoc, etlDoc.getTargetAccountingLine(deleteIndex)));
200    
201            // if the rule evaluation passed, let's delete it
202            if (rulePassed) {
203                deleteAccountingLine(false, etlForm, deleteIndex);
204            }
205            else {
206                String[] errorParams = new String[] { "target", Integer.toString(deleteIndex + 1) };
207                GlobalVariables.getMessageMap().putError(errorPath, EndowKeyConstants.EndowmentTransactionDocumentConstants.ERROR_DELETING_ACCOUNTING_LINE, errorParams);
208            }
209    
210            return mapping.findForward(KFSConstants.MAPPING_BASIC);
211        }
212    
213        /**
214         * Deletes a Accounting Line.
215         * 
216         * @param isSource
217         * @param etlDocumentForm
218         * @param index
219         */
220        protected void deleteAccountingLine(boolean isSource, EndowmentAccountingLinesDocumentFormBase etlDocumentForm, int index) {
221            if (isSource) {
222                // remove from document
223                etlDocumentForm.getEndowmentAccountingLinesDocumentBase().getSourceAccountingLines().remove(index);
224    
225            }
226            else {
227                // remove from document
228                etlDocumentForm.getEndowmentAccountingLinesDocumentBase().getTargetAccountingLines().remove(index);
229            }
230            // update the doc total
231            EndowmentAccountingLinesDocument tdoc = etlDocumentForm.getEndowmentAccountingLinesDocumentBase();
232            if (tdoc instanceof AmountTotaling) {
233                ((FinancialSystemDocumentHeader) etlDocumentForm.getDocument().getDocumentHeader()).setFinancialDocumentTotalAmount(((AmountTotaling) tdoc).getTotalDollarAmount());
234            }
235        }
236    
237        /**
238         * This method returns the balance inquiry for target accounting lines.
239         * 
240         * @param mapping
241         * @param form
242         * @param request
243         * @param response
244         * @return
245         * @throws Exception
246         */
247        public ActionForward performBalanceInquiryForTargetAccountingLine(ActionMapping mapping, ActionForm form, HttpServletRequest request, HttpServletResponse response) throws Exception {
248            return performBalanceInquiry(false, mapping, form, request, response);
249        }
250    
251        /**
252         * This method returns the balance inquiry for source accounting lines.
253         * 
254         * @param mapping
255         * @param form
256         * @param request
257         * @param response
258         * @return
259         * @throws Exception
260         */
261        public ActionForward performBalanceInquiryForSourceAccountingLine(ActionMapping mapping, ActionForm form, HttpServletRequest request, HttpServletResponse response) throws Exception {
262            return performBalanceInquiry(true, mapping, form, request, response);
263        }
264    
265        /**
266         * This method provides the KEMIDCurrentBalance as the default lookup object. If a different lookup is needed this method should
267         * be overriden.
268         * 
269         * @param isSource
270         * @param mapping
271         * @param form
272         * @param request
273         * @param response
274         * @return
275         * @throws Exception
276         */
277        public ActionForward performBalanceInquiry(boolean isSource, ActionMapping mapping, ActionForm form, HttpServletRequest request, HttpServletResponse response) throws Exception {
278            String boName = KEMIDCurrentBalance.class.getName();
279            return performBalanceInquiry(isSource, boName, mapping, form, request, response);
280        }
281    
282        /**
283         * This method is similar to org.kuali.kfs.sys.web.struts.KualiAccountingDocumentActionBase.performBalanceInquiry()
284         * 
285         * @param isRevenue
286         * @param mapping
287         * @param form
288         * @param request
289         * @param response
290         * @return
291         * @throws Exception
292         */
293        public ActionForward performBalanceInquiry(boolean isSource, String boName, ActionMapping mapping, ActionForm form, HttpServletRequest request, HttpServletResponse response) throws Exception {
294            final String docNumber;
295    
296            // get the selected line, setup parms and redirect to balance inquiry
297            EndowmentAccountingLinesDocumentFormBase etlForm = (EndowmentAccountingLinesDocumentFormBase) form;
298            EndowmentAccountingLinesDocumentBase etlDoc = ((EndowmentAccountingLinesDocumentFormBase) form).getEndowmentAccountingLinesDocumentBase();
299    
300    
301            // when we return from the lookup, our next request's method to call is going to be refresh
302            etlForm.registerEditableProperty(KNSConstants.DISPATCH_REQUEST_PARAMETER);
303    
304            EndowmentAccountingLine etLine;
305            if (isSource) {
306                etLine = etlDoc.getSourceAccountingLines().get(this.getSelectedLine(request));
307            }
308            else {
309                etLine = etlDoc.getTargetAccountingLines().get(this.getSelectedLine(request));
310            }
311    
312            // build out base path for return location, use config service
313            String basePath = SpringContext.getBean(KualiConfigurationService.class).getPropertyString(KFSConstants.APPLICATION_URL_KEY);
314    
315            // this hack sets the return anchor we want to return too after the inquiry
316            // do this here so it gets into the session stored form version
317            // refresh checks for this after and resets the anchor
318            if (form instanceof KualiForm && StringUtils.isNotEmpty(((KualiForm) form).getAnchor())) {
319                etlForm.setBalanceInquiryReturnAnchor(((KualiForm) form).getAnchor());
320            }
321    
322            // build out the actual form key that will be used to retrieve the form on refresh
323            String callerDocFormKey = GlobalVariables.getUserSession().addObject(form);
324    
325            // now add required parameters
326            Properties params = new Properties();
327            params.put(KFSConstants.DISPATCH_REQUEST_PARAMETER, KFSConstants.START_METHOD);
328            // params.put(KFSConstants.BUSINESS_OBJECT_CLASS_ATTRIBUTE, boName);
329            params.put(KFSConstants.BALANCE_INQUIRY_REPORT_MENU_CALLER_DOC_FORM_KEY, callerDocFormKey);
330            params.put(KFSConstants.DOC_FORM_KEY, callerDocFormKey);
331            // params.put(KFSConstants.HIDE_LOOKUP_RETURN_LINK, "true");
332            params.put(KFSConstants.BACK_LOCATION, basePath + mapping.getPath() + ".do");
333    
334    
335            if (StringUtils.isNotBlank(etLine.getChartOfAccountsCode())) {
336                params.put("chartOfAccountsCode", etLine.getChartOfAccountsCode());
337            }
338            if (StringUtils.isNotBlank(etLine.getAccountNumber())) {
339                params.put("accountNumber", etLine.getAccountNumber());
340            }
341            if (StringUtils.isNotBlank(etLine.getFinancialObjectCode())) {
342                params.put("financialObjectCode", etLine.getFinancialObjectCode());
343            }
344            if (StringUtils.isNotBlank(etLine.getSubAccountNumber())) {
345                params.put("subAccountNumber", etLine.getSubAccountNumber());
346            }
347            if (StringUtils.isNotBlank(etLine.getFinancialSubObjectCode())) {
348                params.put("financialSubObjectCode", etLine.getFinancialSubObjectCode());
349            }
350            if (StringUtils.isNotBlank(etLine.getProjectCode())) {
351                params.put("projectCode", etLine.getProjectCode());
352            }
353    
354    
355            String lookupUrl = UrlFactory.parameterizeUrl(basePath + "/" + KFSConstants.BALANCE_INQUIRY_REPORT_MENU_ACTION, params);
356    
357            // register that we're going to come back w/ to this form w/ a refresh methodToCall
358            etlForm.registerEditableProperty(KNSConstants.DISPATCH_REQUEST_PARAMETER);
359    
360            return new ActionForward(lookupUrl, true);
361        }
362    
363        /**
364         * This action executes a call to upload CSV accounting line values as TargetAccountingLines for a given transactional document.
365         * The "uploadAccountingLines()" method handles the multi-part request.
366         * 
367         * @param mapping
368         * @param form
369         * @param request
370         * @param response
371         * @return ActionForward
372         * @throws Exception
373         */
374        public ActionForward uploadTargetLines(ActionMapping mapping, ActionForm form, HttpServletRequest request, HttpServletResponse response) throws Exception {
375    
376            // call method that sourceform and destination list
377            uploadAccountingLines(false, form);
378    
379            return mapping.findForward(KFSConstants.MAPPING_BASIC);
380        }
381    
382    
383        /**
384         * This action executes a call to upload CSV accounting line values as SourceAccountingLines for a given transactional document.
385         * The "uploadAccountingLines()" method handles the multi-part request.
386         * 
387         * @param mapping
388         * @param form
389         * @param request
390         * @param response
391         * @return ActionForward
392         * @throws FileNotFoundException
393         * @throws IOException
394         */
395        public ActionForward uploadSourceLines(ActionMapping mapping, ActionForm form, HttpServletRequest request, HttpServletResponse response) throws FileNotFoundException, IOException {
396    
397            // call method that sourceform and destination list
398            uploadAccountingLines(true, form);
399    
400            return mapping.findForward(KFSConstants.MAPPING_BASIC);
401        }
402    
403        /**
404         * This method determines whether we are uploading source or target lines, and then calls uploadAccountingLines directly on the
405         * document object. This method handles retrieving the actual upload file as an input stream into the document.
406         * 
407         * @param isSource
408         * @param form
409         * @throws FileNotFoundException
410         * @throws IOException
411         */
412        protected void uploadAccountingLines(boolean isSource, ActionForm form) throws FileNotFoundException, IOException {
413            EndowmentAccountingLinesDocumentFormBase tmpForm = (EndowmentAccountingLinesDocumentFormBase) form;
414    
415            List importedLines = null;
416    
417            EndowmentAccountingLinesDocument financialDocument = tmpForm.getEndowmentAccountingLinesDocumentBase();
418            EndowmentAccountingLineParser accountingLineParser = financialDocument.getEndowmentAccountingLineParser();
419    
420            // import the lines
421            String errorPathPrefix = null;
422            try {
423                if (isSource) {
424                    errorPathPrefix = EndowPropertyConstants.EXISTING_SOURCE_ACCT_LINE_PREFIX;
425                    FormFile sourceFile = tmpForm.getSourceFile();
426                    checkUploadFile(sourceFile);
427                    importedLines = accountingLineParser.importSourceEndowmentAccountingLines(sourceFile.getFileName(), sourceFile.getInputStream(), financialDocument);
428                }
429                else {
430                    errorPathPrefix = EndowPropertyConstants.EXISTING_TARGET_ACCT_LINE_PREFIX;
431                    FormFile targetFile = tmpForm.getTargetFile();
432                    checkUploadFile(targetFile);
433                    importedLines = accountingLineParser.importTargetEndowmentAccountingLines(targetFile.getFileName(), targetFile.getInputStream(), financialDocument);
434                }
435            }
436            catch (EndowmentAccountingLineException e) {
437                GlobalVariables.getMessageMap().putError(errorPathPrefix, e.getErrorKey(), e.getErrorParameters());
438            }
439    
440            // add line to list for those lines which were successfully imported
441            if (importedLines != null) {
442                for (Iterator i = importedLines.iterator(); i.hasNext();) {
443                    EndowmentAccountingLine importedLine = (EndowmentAccountingLine) i.next();
444                    insertAccountingLine(isSource, tmpForm, importedLine);
445                }
446            }
447        }
448    
449        /**
450         * This method...
451         * 
452         * @param file
453         */
454        protected void checkUploadFile(FormFile file) {
455            if (file == null) {
456                throw new EndowmentAccountingLineException("invalid (null) upload file", KFSKeyConstants.ERROR_UPLOADFILE_NULL);
457            }
458        }
459    
460    
461    }