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  import java.util.Collections;
22  import java.util.List;
23  
24  import javax.servlet.http.HttpServletRequest;
25  import javax.servlet.http.HttpServletResponse;
26  
27  import org.apache.struts.action.ActionForm;
28  import org.apache.struts.action.ActionForward;
29  import org.apache.struts.action.ActionMapping;
30  import org.kuali.ole.fp.businessobject.CapitalAccountingLines;
31  import org.kuali.ole.fp.businessobject.CapitalAssetAccountsGroupDetails;
32  import org.kuali.ole.fp.businessobject.CapitalAssetInformation;
33  import org.kuali.ole.fp.businessobject.CapitalAssetInformationDetail;
34  import org.kuali.ole.fp.businessobject.options.CapitalAccountingLinesComparator;
35  import org.kuali.ole.fp.document.CapitalAccountingLinesDocumentBase;
36  import org.kuali.ole.fp.document.validation.event.CapitalAccountingLinesSameObjectCodeSubTypeEvent;
37  import org.kuali.ole.integration.cab.CapitalAssetBuilderModuleService;
38  import org.kuali.ole.sys.OLEConstants;
39  import org.kuali.ole.sys.OLEKeyConstants;
40  import org.kuali.ole.sys.businessobject.AccountingLine;
41  import org.kuali.ole.sys.businessobject.SourceAccountingLine;
42  import org.kuali.ole.sys.businessobject.TargetAccountingLine;
43  import org.kuali.ole.sys.context.SpringContext;
44  import org.kuali.ole.sys.document.AccountingDocument;
45  import org.kuali.ole.sys.web.struts.KualiAccountingDocumentFormBase;
46  import org.kuali.rice.core.api.config.property.ConfigurationService;
47  import org.kuali.rice.core.api.util.RiceConstants;
48  import org.kuali.rice.kew.api.exception.WorkflowException;
49  import org.kuali.rice.kns.question.ConfirmationQuestion;
50  import org.kuali.rice.kns.web.struts.form.KualiDocumentFormBase;
51  import org.kuali.rice.kns.web.struts.form.KualiForm;
52  import org.kuali.rice.krad.document.Document;
53  import org.kuali.rice.krad.service.KualiRuleService;
54  import org.kuali.rice.krad.util.GlobalVariables;
55  import org.kuali.rice.krad.util.ObjectUtils;
56  
57  /**
58   * This is the action class for the CapitalAccountingLinesActionBase.
59   */
60  public abstract class CapitalAccountingLinesActionBase extends CapitalAssetInformationActionBase {
61      private CapitalAssetBuilderModuleService capitalAssetBuilderModuleService = SpringContext.getBean(CapitalAssetBuilderModuleService.class);
62  
63      /**
64       * removes capitalaccountinglines which is a transient bo.. and call the super method to
65       * create a error correction document.
66       * @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)
67       */
68      @Override
69      public ActionForward correct(ActionMapping mapping, ActionForm form, HttpServletRequest request, HttpServletResponse response) throws Exception {
70          CapitalAccountingLinesFormBase capitalAccountingLinesFormBase = (CapitalAccountingLinesFormBase) form;
71          CapitalAccountingLinesDocumentBase caldb = (CapitalAccountingLinesDocumentBase) capitalAccountingLinesFormBase.getFinancialDocument();
72          caldb.getCapitalAccountingLines().clear();
73  
74          super.correct(mapping, capitalAccountingLinesFormBase, request, response);
75  
76          KualiAccountingDocumentFormBase kadfb = (KualiAccountingDocumentFormBase) form;
77          List<CapitalAssetInformation> currentCapitalAssetInformation =  this.getCurrentCapitalAssetInformationObject(kadfb);
78          for (CapitalAssetInformation capitalAsset : currentCapitalAssetInformation) {
79              capitalAsset.setCapitalAssetProcessedIndicator(false);
80              capitalAsset.setCapitalAssetLineAmount(capitalAsset.getCapitalAssetLineAmount().negated());
81              //remove capital asset tag/location asset tag number and serial number as
82              //they will fail because these values will be duplicates.
83              List<CapitalAssetInformationDetail> tagLocationDetails = capitalAsset.getCapitalAssetInformationDetails();
84              for (CapitalAssetInformationDetail tagLocationDetail : tagLocationDetails) {
85                  tagLocationDetail.setCapitalAssetTagNumber(null);
86                  tagLocationDetail.setCapitalAssetSerialNumber(null);
87              }
88  
89              List<CapitalAssetAccountsGroupDetails> groupAccountLines = capitalAsset.getCapitalAssetAccountsGroupDetails();
90              for (CapitalAssetAccountsGroupDetails groupAccountLine : groupAccountLines) {
91                  groupAccountLine.setAmount(groupAccountLine.getAmount().negated());
92              }
93          }
94  
95          String distributionAmountCode = capitalAccountingLinesFormBase.getCapitalAccountingLine().getDistributionCode();
96  
97          AccountingDocument tdoc = (AccountingDocument) capitalAccountingLinesFormBase.getDocument();
98  
99          List<CapitalAccountingLines> capitalAccountingLines = new ArrayList();
100         //for every source/target accounting line that has an object code that requires a
101         //capital asset, creates a capital accounting line that the user can select to
102         //perform create or modify asset functions.
103         createCapitalAccountingLines(capitalAccountingLines, tdoc, distributionAmountCode);
104         sortCaptitalAccountingLines(capitalAccountingLines);
105 
106         caldb.setCapitalAccountingLines(capitalAccountingLines);
107         //checks capital accounting lines for capital assets and if so checks the select box
108         checkSelectForCapitalAccountingLines(capitalAccountingLinesFormBase);
109 
110         checkCapitalAccountingLinesSelected(capitalAccountingLinesFormBase);
111         calculatePercentsForSelectedCapitalAccountingLines(capitalAccountingLinesFormBase);
112 
113         //setup the initial next sequence number column..
114         setupIntialNextCapitalAssetLineNumber(capitalAccountingLinesFormBase);
115 
116         return mapping.findForward(RiceConstants.MAPPING_BASIC);
117     }
118 
119     /**
120      * All document-load operations get routed through here
121      *
122      * @see org.kuali.rice.kns.web.struts.action.KualiDocumentActionBase#loadDocument(org.kuali.rice.kns.web.struts.form.KualiDocumentFormBase)
123      */
124     @Override
125     protected void loadDocument(KualiDocumentFormBase kualiDocumentFormBase) throws WorkflowException {
126         super.loadDocument(kualiDocumentFormBase);
127 
128         CapitalAccountingLinesFormBase capitalAccountingLinesFormBase = (CapitalAccountingLinesFormBase) kualiDocumentFormBase;
129         String distributionAmountCode = capitalAccountingLinesFormBase.getCapitalAccountingLine().getDistributionCode();
130 
131         AccountingDocument tdoc = (AccountingDocument) kualiDocumentFormBase.getDocument();
132 
133         List<CapitalAccountingLines> capitalAccountingLines = new ArrayList();
134         //for every source/target accounting line that has an object code that requires a
135         //capital asset, creates a capital accounting line that the user can select to
136         //perform create or modify asset functions.
137         createCapitalAccountingLines(capitalAccountingLines, tdoc, distributionAmountCode);
138         sortCaptitalAccountingLines(capitalAccountingLines);
139 
140         CapitalAccountingLinesDocumentBase caldb = (CapitalAccountingLinesDocumentBase) tdoc;
141         caldb.setCapitalAccountingLines(capitalAccountingLines);
142         //checks capital accounting lines for capital assets and if so checks the select box
143         checkSelectForCapitalAccountingLines(capitalAccountingLinesFormBase);
144 
145         checkCapitalAccountingLinesSelected(capitalAccountingLinesFormBase);
146         calculatePercentsForSelectedCapitalAccountingLines(capitalAccountingLinesFormBase);
147 
148         //setup the initial next sequence number column..
149         setupIntialNextCapitalAssetLineNumber(kualiDocumentFormBase);
150 
151         KualiForm kualiForm = kualiDocumentFormBase;
152         //based on the records in capital accounting lines, capital asset information lists
153         //set the tabs to open if lists not empty else set to close
154         setTabStatesForCapitalAssets(kualiForm);
155     }
156 
157     /**
158      *
159      * @see org.kuali.rice.kns.web.struts.action.KualiAction#refresh(org.apache.struts.action.ActionMapping,
160      *      org.apache.struts.action.ActionForm, javax.servlet.http.HttpServletRequest, javax.servlet.http.HttpServletResponse)
161      */
162    // @Override
163     @Override
164     public ActionForward refresh(ActionMapping mapping, ActionForm form, HttpServletRequest request, HttpServletResponse response) throws Exception {
165         super.refresh(mapping, form, request, response);
166 
167         CapitalAccountingLinesFormBase capitalAccountingLinesFormBase = (CapitalAccountingLinesFormBase) form;
168         CapitalAccountingLinesDocumentBase caldb = (CapitalAccountingLinesDocumentBase) capitalAccountingLinesFormBase.getFinancialDocument();
169 
170         List<CapitalAccountingLines> capitalAccountingLines = caldb.getCapitalAccountingLines();
171         KualiDocumentFormBase kualiDocumentFormBase = (KualiDocumentFormBase) form;
172         AccountingDocument tdoc = (AccountingDocument) kualiDocumentFormBase.getDocument();
173 
174         capitalAccountingLines = updateCapitalAccountingLines(capitalAccountingLines, tdoc);
175         sortCaptitalAccountingLines(capitalAccountingLines);
176         caldb.setCapitalAccountingLines(capitalAccountingLines);
177 
178         //now remove distributed accounting lines if they are not in the capital
179         //accounting lines list.
180 
181         KualiAccountingDocumentFormBase kadfb = (KualiAccountingDocumentFormBase) form;
182         List<CapitalAssetInformation> currentCapitalAssetInformation =  this.getCurrentCapitalAssetInformationObject(kadfb);
183 
184         removeOrphanDisributedAccountingLines(capitalAccountingLines, currentCapitalAssetInformation);
185         checkCapitalAccountingLinesSelected(capitalAccountingLinesFormBase);
186         setTabStatesForCapitalAssets(form);
187 
188         return mapping.findForward(OLEConstants.MAPPING_BASIC);
189     }
190 
191     /**
192      * When user adds an accounting line to the either source or target, if the object code on
193      * that line has capital object type code group then a capital accounting line is created.
194      * @see org.kuali.ole.sys.web.struts.KualiAccountingDocumentActionBase#insertAccountingLine(boolean, org.kuali.ole.sys.web.struts.KualiAccountingDocumentFormBase, org.kuali.ole.sys.businessobject.AccountingLine)
195      */
196     @Override
197     protected void insertAccountingLine(boolean isSource, KualiAccountingDocumentFormBase financialDocumentForm, AccountingLine line) {
198         super.insertAccountingLine(isSource, financialDocumentForm, line);
199 
200         CapitalAccountingLinesFormBase capitalAccountingLinesFormBase = (CapitalAccountingLinesFormBase) financialDocumentForm;
201         CapitalAccountingLinesDocumentBase caldb = (CapitalAccountingLinesDocumentBase) capitalAccountingLinesFormBase.getFinancialDocument();
202         String distributionAmountCode = capitalAccountingLinesFormBase.getCapitalAccountingLine().getDistributionCode();
203 
204         List<CapitalAccountingLines> capitalAccountingLines = caldb.getCapitalAccountingLines();
205 
206         //create the corresponding capital accounting line and then
207         //sort the capital accounting lines by object code and account number
208         createCapitalAccountingLine(capitalAccountingLines, line, distributionAmountCode);
209         sortCaptitalAccountingLines(capitalAccountingLines);
210 
211         KualiForm kualiForm = financialDocumentForm;
212         //sets the tab states for create/modify capital asset tabs...
213         setTabStatesForCapitalAssets(kualiForm);
214     }
215 
216     /**
217      * When user deletes an accounting line to the either source or target, the corresponding line in
218      * capital accounting line is deleted and the distributed accounting line under the
219      * created or modified capital asset line.  When a capital asset does not have any
220      * accounting lines, the capital asset is removed.
221      * @see org.kuali.ole.sys.web.struts.KualiAccountingDocumentActionBase#deleteAccountingLine(boolean, org.kuali.ole.sys.web.struts.KualiAccountingDocumentFormBase, int)
222      */
223     @Override
224     protected void deleteAccountingLine(boolean isSource, KualiAccountingDocumentFormBase financialDocumentForm, int deleteIndex) {
225 
226         CapitalAccountingLinesFormBase capitalAccountingLinesFormBase = (CapitalAccountingLinesFormBase) financialDocumentForm;
227         CapitalAccountingLinesDocumentBase caldb = (CapitalAccountingLinesDocumentBase) capitalAccountingLinesFormBase.getFinancialDocument();
228 
229         List<CapitalAccountingLines> capitalAccountingLines = caldb.getCapitalAccountingLines();
230 
231         if (isSource) {
232             // remove from capital accounting lines for this source line
233             AccountingLine line = (AccountingLine) financialDocumentForm.getFinancialDocument().getSourceAccountingLines().get(deleteIndex);
234             deleteCapitalAccountingLine(capitalAccountingLines, line);
235             deleteCapitalAssetLines(financialDocumentForm, line);
236         }
237         else {
238             // remove from document
239             AccountingLine line = (AccountingLine) financialDocumentForm.getFinancialDocument().getTargetAccountingLines().get(deleteIndex);
240             deleteCapitalAccountingLine(capitalAccountingLines, line);
241             deleteCapitalAssetLines(financialDocumentForm, line);
242         }
243 
244         super.deleteAccountingLine(isSource, financialDocumentForm, deleteIndex);
245         sortCaptitalAccountingLines(capitalAccountingLines);
246 
247         KualiForm kualiForm = financialDocumentForm;
248 
249         //checks capital accounting lines for capital assets and if so checks the select box
250         checkSelectForCapitalAccountingLines(capitalAccountingLinesFormBase);
251         checkCapitalAccountingLinesSelected(capitalAccountingLinesFormBase);
252         calculatePercentsForSelectedCapitalAccountingLines(capitalAccountingLinesFormBase);
253         setTabStatesForCapitalAssets(kualiForm);
254     }
255 
256     /**
257      * After uploading the accounting lines, the capital accounting lines will be created from these.
258      * @see org.kuali.ole.sys.web.struts.KualiAccountingDocumentActionBase#uploadAccountingLines(boolean, org.apache.struts.action.ActionForm)
259      */
260     @Override
261     protected void uploadAccountingLines(boolean isSource, ActionForm form) throws FileNotFoundException, IOException {
262         super.uploadAccountingLines(isSource, form);
263 
264         KualiAccountingDocumentFormBase kualiAccountingDocumentFormBase = (KualiAccountingDocumentFormBase) form;
265         CapitalAccountingLinesFormBase capitalAccountingLinesFormBase = (CapitalAccountingLinesFormBase) form;
266         CapitalAccountingLinesDocumentBase caldb = (CapitalAccountingLinesDocumentBase) capitalAccountingLinesFormBase.getFinancialDocument();
267 
268         String distributionAmountCode = capitalAccountingLinesFormBase.getCapitalAccountingLine().getDistributionCode();
269 
270         List<CapitalAccountingLines> capitalAccountingLines = caldb.getCapitalAccountingLines();
271         AccountingDocument tdoc = (AccountingDocument) kualiAccountingDocumentFormBase.getDocument();
272 
273         createCapitalAccountingLines(capitalAccountingLines, tdoc, distributionAmountCode);
274         sortCaptitalAccountingLines(capitalAccountingLines);
275 
276         KualiForm kualiForm = (KualiForm) form;
277         setTabStatesForCapitalAssets(kualiForm);
278     }
279 
280     /**
281      * creates the capital accounting lines looking at source and/or target accounting lines.
282      *
283      * @param capitalAccountingLines
284      * @param tdoc
285      * @param distributionAmountCode distribution amount code for the line
286      */
287     protected void createCapitalAccountingLines(List<CapitalAccountingLines> capitalAccountingLines, AccountingDocument tdoc, String distributionAmountCode) {
288         List<SourceAccountingLine> sourceAccountLines = tdoc.getSourceAccountingLines();
289 
290         CapitalAccountingLinesDocumentBase caldb = (CapitalAccountingLinesDocumentBase) tdoc;
291 
292         for (SourceAccountingLine line : sourceAccountLines) {
293             //create source capital accounting line
294             createCapitalAccountingLine(capitalAccountingLines, line, distributionAmountCode);
295         }
296 
297         List<TargetAccountingLine> targetAccountLines = tdoc.getTargetAccountingLines();
298 
299         for (TargetAccountingLine line : targetAccountLines) {
300             // create target capital accounting line
301             createCapitalAccountingLine(capitalAccountingLines, line, distributionAmountCode);
302         }
303 
304         //sort the capital accounting lines collection
305         sortCaptitalAccountingLines(capitalAccountingLines);
306     }
307 
308     /**
309      * updates the capital accounting lines looking at source and/or target accounting lines.
310      *
311      * @param capitalAccountingLines
312      * @param tdoc
313      */
314     protected List<CapitalAccountingLines> updateCapitalAccountingLines(List<CapitalAccountingLines> capitalAccountingLines, AccountingDocument tdoc) {
315         List<SourceAccountingLine> sourceAccountLines = tdoc.getSourceAccountingLines();
316 
317         for (SourceAccountingLine line : sourceAccountLines) {
318             //updates source capital accounting line
319             updateCapitalAccountingLine(capitalAccountingLines, line);
320         }
321 
322         List<TargetAccountingLine> targetAccountLines = tdoc.getTargetAccountingLines();
323 
324         for (TargetAccountingLine line : targetAccountLines) {
325             //updates source capital accounting line
326             updateCapitalAccountingLine(capitalAccountingLines, line);
327         }
328 
329         //remove the orphan capital accounting lines that does not have corresponding
330         //accounting line from either source or target.
331        return removeOrphanCapitalAccountingLines(capitalAccountingLines, tdoc);
332     }
333 
334     /**
335      * updates the capital accounting lines looking at source and/or target accounting lines.
336      * Removes any capital accounting line that does not have a corresponding
337      * source or target accounting line.
338      * @param capitalAccountingLines
339      * @param tdoc
340      */
341     protected List<CapitalAccountingLines> removeOrphanCapitalAccountingLines(List<CapitalAccountingLines> capitalAccountingLines, AccountingDocument tdoc) {
342         List<CapitalAccountingLines> newCapitalAccountingLines = new ArrayList<CapitalAccountingLines>();
343         if ( capitalAccountingLines != null ) {
344         List<AccountingLine> sourceAccountLines = tdoc.getSourceAccountingLines();
345         for (CapitalAccountingLines capitalAccountingLine : capitalAccountingLines) {
346             if (removeOrphanCapitalAccountingLine(sourceAccountLines, capitalAccountingLine)) {
347                 newCapitalAccountingLines.add(capitalAccountingLine);
348             }
349         }
350 
351         List<AccountingLine> targetAccountLines = tdoc.getTargetAccountingLines();
352         for (CapitalAccountingLines capitalAccountingLine : capitalAccountingLines) {
353             if (removeOrphanCapitalAccountingLine(targetAccountLines, capitalAccountingLine)) {
354                 newCapitalAccountingLines.add(capitalAccountingLine);
355             }
356         }
357         }
358         return newCapitalAccountingLines;
359     }
360 
361     /**
362      * If the line exists in capital accounting lines, and that line does not exist in
363      * accounting lines (source or target) then remove the line from capital accounting lines.
364      *
365      * @param capitalAccountingLines
366      * @param line to remove
367      * @return true if the capital accounting line to be removed is found in accounting lines, else false
368      */
369     protected boolean removeOrphanCapitalAccountingLine(List<AccountingLine> accountLines, CapitalAccountingLines capitalAccountingLine) {
370         boolean found = false;
371 
372         for (AccountingLine accountingLine : accountLines) {
373             if (capitalAccountingLine.getChartOfAccountsCode().equals(accountingLine.getChartOfAccountsCode()) &&
374                     capitalAccountingLine.getAccountNumber().equals(accountingLine.getAccountNumber()) &&
375                     capitalAccountingLine.getFinancialObjectCode().equals(accountingLine.getFinancialObjectCode()) &&
376                     capitalAccountingLine.getLineType().equalsIgnoreCase(accountingLine instanceof SourceAccountingLine ? OLEConstants.SOURCE : OLEConstants.TARGET)) {
377                 found = true;
378             }
379         }
380 
381         return found;
382     }
383 
384     /**
385      * Method to check for any distributed accounting lines that are not listed in the
386      * capital accounting lines and remove them.
387      *
388      * @param capitalAccountingLines
389      * @param capitalAssets
390      */
391     protected void removeOrphanDisributedAccountingLines(List<CapitalAccountingLines> capitalAccountingLines, List<CapitalAssetInformation> capitalAssets) {
392         List<CapitalAssetInformation> removalCaiList = new ArrayList<CapitalAssetInformation>();
393 
394         for (CapitalAssetInformation capitalAsset : capitalAssets) {
395             removeOrphanDisributedAccountingLine(capitalAccountingLines, capitalAsset);
396             if (capitalAsset.getCapitalAssetAccountsGroupDetails().size() == 0) {
397                 capitalAsset.getCapitalAssetInformationDetails().clear();
398                 removalCaiList.add(capitalAsset);
399             }
400         }
401         //if the removal list is not empty, remove these bunch of capital asset records
402         //for that accounting line.
403         if (ObjectUtils.isNotNull(removalCaiList)) {
404             capitalAssets.removeAll(removalCaiList);
405         }
406     }
407 
408     /**
409      * Method to check for any distributed accounting line for a given capital
410      * accounting line that are not listed in the capital assets accounting lines and remove it.
411      *
412      * @param capitalAccountingLines
413      * @param capitalAsset
414      */
415     protected void removeOrphanDisributedAccountingLine(List<CapitalAccountingLines> capitalAccountingLines, CapitalAssetInformation capitalAsset) {
416         List<CapitalAssetAccountsGroupDetails> groupAccountLines = capitalAsset.getCapitalAssetAccountsGroupDetails();
417         CapitalAssetAccountsGroupDetails accountLineToDelete = null;
418 
419         for (CapitalAssetAccountsGroupDetails groupAccountLine : groupAccountLines) {
420             if (!checkDistributedAccountingLineExists(capitalAccountingLines, groupAccountLine)) {
421                 accountLineToDelete = groupAccountLine;
422                 break;
423             }
424         }
425 
426         if (ObjectUtils.isNotNull(accountLineToDelete)) {
427             // remove all the group accounting lines so that the asset line can be removed.
428             capitalAsset.getCapitalAssetAccountsGroupDetails().clear();
429         }
430     }
431 
432     /**
433      * checks capital accounting lines again the distributed accounting line and if found
434      * return true else false so that this distributed accounting line may be removed.
435      *
436      * @param capitalAccountingLines
437      * @param groupAccountLine
438      * @return true if accounting line exists else return false
439      */
440     protected boolean checkDistributedAccountingLineExists(List<CapitalAccountingLines> capitalAccountingLines, CapitalAssetAccountsGroupDetails groupAccountLine) {
441         boolean exists = false;
442 
443         for (CapitalAccountingLines capitalAccountingLine : capitalAccountingLines) {
444             if (groupAccountLine.getSequenceNumber().compareTo(capitalAccountingLine.getSequenceNumber()) == 0 &&
445                     groupAccountLine.getFinancialDocumentLineTypeCode().equals(OLEConstants.SOURCE.equals(capitalAccountingLine.getLineType()) ? OLEConstants.SOURCE_ACCT_LINE_TYPE_CODE : OLEConstants.TARGET_ACCT_LINE_TYPE_CODE) &&
446                     groupAccountLine.getChartOfAccountsCode().equals(capitalAccountingLine.getChartOfAccountsCode()) &&
447                     groupAccountLine.getAccountNumber().equals(capitalAccountingLine.getAccountNumber()) &&
448                     groupAccountLine.getFinancialObjectCode().equals(capitalAccountingLine.getFinancialObjectCode())) {
449                 return true;
450             }
451         }
452 
453         return false;
454     }
455 
456     /**
457      * Checks if the accounting line has an object code that belongs to object sub type group codes and
458      * if so, creates a capital accounting line that will be displayed on the jsp.
459      *
460      * @param capitalAccountingLines
461      * @param line
462      * @param distributionAmountCode
463      * @return List of capitalAccountingLines
464      */
465     protected List<CapitalAccountingLines> createCapitalAccountingLine(List<CapitalAccountingLines> capitalAccountingLines, AccountingLine line, String distributionAmountCode) {
466         Integer sequenceNumber = capitalAccountingLines.size() + 1;
467 
468         if (capitalAssetBuilderModuleService.hasCapitalAssetObjectSubType(line)) {
469             //capital object code so we need to build the capital accounting line...
470             CapitalAccountingLines cal = addCapitalAccountingLine(capitalAccountingLines, line);
471             cal.setDistributionAmountCode(distributionAmountCode);
472             capitalAccountingLines.add(cal);
473         }
474 
475         return capitalAccountingLines;
476     }
477 
478     /**
479      * Checks if the accounting line exits in the capital accounting lines
480      * and if so, updates the other information.
481      * else inserts a new record into the collection
482      *
483      * @param capitalAccountingLines
484      * @param line
485      * @return List of capitalAccountingLines
486      */
487     protected void updateCapitalAccountingLine(List<CapitalAccountingLines> capitalAccountingLines, AccountingLine line) {
488         boolean found = false;
489 
490         for (CapitalAccountingLines capitalAccountingLine : capitalAccountingLines) {
491             if (capitalAccountingLine.getChartOfAccountsCode().equals(line.getChartOfAccountsCode()) &&
492                     capitalAccountingLine.getAccountNumber().equals(line.getAccountNumber()) &&
493                     capitalAccountingLine.getFinancialObjectCode().equals(line.getFinancialObjectCode()) &&
494                     capitalAccountingLine.getLineType().equalsIgnoreCase(line instanceof SourceAccountingLine ? OLEConstants.SOURCE : OLEConstants.TARGET) &&
495                     capitalAccountingLine.getSequenceNumber().compareTo(line.getSequenceNumber()) == 0) {
496                 capitalAccountingLine.setFinancialSubObjectCode(line.getFinancialSubObjectCode());
497                 capitalAccountingLine.setSubAccountNumber(line.getSubAccountNumber());
498                 capitalAccountingLine.setProjectCode(line.getProjectCode());
499                 capitalAccountingLine.setOrganizationReferenceId(line.getOrganizationReferenceId());
500                 capitalAccountingLine.setAmount(line.getAmount());
501                 capitalAccountingLine.setFinancialDocumentLineDescription(line.getFinancialDocumentLineDescription());
502                 found = true;
503                 break;
504             }
505         }
506 
507         if (!found) {
508             //capital object code so we need to build the capital accounting line...
509             if (capitalAssetBuilderModuleService.hasCapitalAssetObjectSubType(line)) {
510                 CapitalAccountingLines cal = addCapitalAccountingLine(capitalAccountingLines, line);
511                 capitalAccountingLines.add(cal);
512             }
513         }
514     }
515 
516     /**
517      * convenience method to add a new capital accounting line to the collection of capital
518      * accounting lines.
519      *
520      * @param capitalAccountingLines
521      * @param line
522      * @return cal newly created capital accounting line
523      */
524     protected CapitalAccountingLines addCapitalAccountingLine(List<CapitalAccountingLines> capitalAccountingLines, AccountingLine line) {
525         CapitalAccountingLines cal = new CapitalAccountingLines();
526 
527         if (line instanceof SourceAccountingLine) {
528             cal.setLineType(OLEConstants.SOURCE);
529         }
530         else {
531             cal.setLineType(OLEConstants.TARGET);
532         }
533         cal.setSequenceNumber(line.getSequenceNumber());
534         cal.setChartOfAccountsCode(line.getChartOfAccountsCode());
535         cal.setAccountNumber(line.getAccountNumber());
536         cal.setSubAccountNumber(line.getSubAccountNumber());
537         cal.setFinancialObjectCode(line.getFinancialObjectCode());
538         cal.setFinancialSubObjectCode(line.getFinancialSubObjectCode());
539         cal.setProjectCode(line.getProjectCode());
540         cal.setOrganizationReferenceId(line.getOrganizationReferenceId());
541         cal.setFinancialDocumentLineDescription(line.getFinancialDocumentLineDescription());
542         cal.setAmount(line.getAmount());
543         cal.setAccountLinePercent(null);
544         cal.setSelectLine(false);
545 
546         return cal;
547     }
548 
549     /**
550      * If the line exists in capital accounting lines, that will be deleted.
551      *
552      * @param capitalAccountingLines
553      * @param line to remove
554      * @return List of capitalAccountingLines
555      */
556     protected List<CapitalAccountingLines> deleteCapitalAccountingLine(List<CapitalAccountingLines> capitalAccountingLines, AccountingLine line) {
557         CapitalAccountingLines cal = null;
558 
559         for (CapitalAccountingLines capitalAccountingLine : capitalAccountingLines) {
560             if (capitalAccountingLine.getChartOfAccountsCode().equals(line.getChartOfAccountsCode()) &&
561                     capitalAccountingLine.getAccountNumber().equals(line.getAccountNumber()) &&
562                     capitalAccountingLine.getFinancialObjectCode().equals(line.getFinancialObjectCode()) &&
563                     capitalAccountingLine.getLineType().equalsIgnoreCase(line instanceof SourceAccountingLine ? OLEConstants.SOURCE : OLEConstants.TARGET)) {
564                 cal = capitalAccountingLine;
565                 break;
566             }
567         }
568 
569         if (ObjectUtils.isNotNull(cal)) {
570             capitalAccountingLines.remove(cal);
571         }
572 
573         return capitalAccountingLines;
574     }
575 
576     /**
577      * sort the capital accounting lines collection based on financial object code and account number.
578      * @param capitalAccountingLines List of capital accounting lines
579      */
580     protected void sortCaptitalAccountingLines(List<CapitalAccountingLines> capitalAccountingLines) {
581         CapitalAccountingLinesComparator calComparator = new CapitalAccountingLinesComparator();
582 
583         //sort the collection based on financial object code and account number
584         Collections.sort(capitalAccountingLines, calComparator);
585     }
586 
587     /**
588      * Action "create" creates assets for the selected capital
589      * accounting lines.  An error message is shown if no capital accounting lines
590      * are selected for processing.  The action checks if the selected
591      * capital accounting lines object sub type cross based on the system paramter
592      * values for the object subtypes and if so prompts the user to confirm to continue
593      * to create the assets for the select capital accounting lines.
594      *
595      * @param mapping
596      * @param form
597      * @param request
598      * @param response
599      * @return ActionForward
600      * @throws Exception
601      */
602     public ActionForward createAsset(ActionMapping mapping, ActionForm form, HttpServletRequest request, HttpServletResponse response) throws Exception {
603         CapitalAccountingLinesFormBase calfb = (CapitalAccountingLinesFormBase) form;
604         String distributionAmountCode = calfb.getCapitalAccountingLine().getDistributionCode();
605         if (OLEConstants.CapitalAssets.DISTRIBUTE_COST_EQUALLY_CODE.equals(distributionAmountCode)) {
606            calfb.setDistributeEqualAmount(true);
607         }
608         else {
609             calfb.setDistributeEqualAmount(false);
610         }
611 
612         boolean createAction = calfb.getCapitalAccountingLine().isCanCreateAsset();
613         calfb.setEditCreateOrModify(false);
614 
615         GlobalVariables.getMessageMap().clearErrorMessages();
616         if (!capitalAccountingLinesSelected(calfb)) {
617             GlobalVariables.getMessageMap().putError(OLEConstants.EDIT_ACCOUNTING_LINES_FOR_CAPITALIZATION_ERRORS, OLEKeyConstants.ERROR_DOCUMENT_ACCOUNTING_LINE_FOR_CAPITALIZATAION_REQUIRED_CREATE);
618             return mapping.findForward(OLEConstants.MAPPING_BASIC);
619         }
620         else {
621             calfb.setEditCreateOrModify(false);
622         }
623 
624         Document document = calfb.getFinancialDocument();
625 
626         //if same object subtypes then continue creating capital assets....
627         if (checkObjecSubTypeCrossingCapitalAccountingLines(document)) {
628             //question the user if to continue....
629             ActionForward forward = performQuestionPrompt(mapping, form, request, response, OLEConstants.CapitalAssets.CAPITAL_ASSET_CREATE_ACTION_INDICATOR, distributionAmountCode);
630             if (forward != null) {
631                 return forward;
632             }
633         }
634         else {
635             createCapitalAssetsForSelectedAccountingLines(form , calfb, OLEConstants.CapitalAssets.CAPITAL_ASSET_CREATE_ACTION_INDICATOR, distributionAmountCode);
636         }
637 
638         //restore the tab states....
639         setTabStatesForCapitalAssets(form);
640 
641         return mapping.findForward(OLEConstants.MAPPING_BASIC);
642     }
643 
644     /**
645      * Action "modify" creates assets for the selected capital
646      * accounting lines.  An error message is shown if no capital accounting lines
647      * are selected for processing.  The action checks if the selected
648      * capital accounting lines object sub type cross based on the system paramter
649      * values for the object subtypes and if so prompts the user to confirm to continue
650      * to create the assets for the select capital accounting lines.
651      *
652      * @param mapping
653      * @param form
654      * @param request
655      * @param response
656      * @return ActionForward
657      * @throws Exception
658      */
659     public ActionForward modifyAsset(ActionMapping mapping, ActionForm form, HttpServletRequest request, HttpServletResponse response) throws Exception {
660         CapitalAccountingLinesFormBase calfb = (CapitalAccountingLinesFormBase) form;
661         String distributionAmountCode = calfb.getCapitalAccountingLine().getDistributionCode();
662 
663         if (OLEConstants.CapitalAssets.DISTRIBUTE_COST_EQUALLY_CODE.equals(distributionAmountCode)) {
664             calfb.setDistributeEqualAmount(true);
665          }
666         else {
667             calfb.setDistributeEqualAmount(false);
668         }
669 
670         GlobalVariables.getMessageMap().clearErrorMessages();
671         if (!capitalAccountingLinesSelected(calfb)) {
672             GlobalVariables.getMessageMap().putError(OLEConstants.EDIT_ACCOUNTING_LINES_FOR_CAPITALIZATION_ERRORS, OLEKeyConstants.ERROR_DOCUMENT_ACCOUNTING_LINE_FOR_CAPITALIZATAION_REQUIRED_MODIFY);
673             return mapping.findForward(OLEConstants.MAPPING_BASIC);
674         }
675         else {
676             calfb.setEditCreateOrModify(false);
677         }
678 
679         Document document = calfb.getFinancialDocument();
680 
681         //if same object subtypes then continue creating capital assets....
682         if (checkObjecSubTypeCrossingCapitalAccountingLines(document)) {
683             //question the user if to continue....
684             ActionForward forward = performQuestionPrompt(mapping, form, request, response, OLEConstants.CapitalAssets.CAPITAL_ASSET_MODIFY_ACTION_INDICATOR, distributionAmountCode);
685             if (forward != null) {
686                 return forward;
687             }
688         }
689         else {
690             createCapitalAssetsForSelectedAccountingLines(form , calfb, OLEConstants.CapitalAssets.CAPITAL_ASSET_MODIFY_ACTION_INDICATOR, distributionAmountCode);
691         }
692 
693         //restore the tab states....
694         setTabStatesForCapitalAssets(form);
695 
696         return mapping.findForward(OLEConstants.MAPPING_BASIC);
697     }
698 
699     /**
700      * Helper method to first calculate the percents for the selected capital accounting lines as
701      * the percent is required if the user is distributing the amounts by individual amount
702      * method.  It then populates created or modified assets with asset accounting lines.
703      *
704      * @param form
705      * @param calfb
706      * @param actionTypeIndicator indicates whether creating an asset for "create" or "modify" actions.
707      * @param distributionAmountCode amount distribution code
708      */
709     protected void createCapitalAssetsForSelectedAccountingLines(ActionForm form, CapitalAccountingLinesFormBase calfb, String actionTypeIndicator, String distributionAmountCode) {
710         calculatePercentsForSelectedCapitalAccountingLines(calfb);
711         createCapitalAssetForGroupAccountingLines(calfb, actionTypeIndicator, distributionAmountCode);
712             checkCapitalAccountingLinesSelected(calfb);
713 
714             KualiForm kualiForm = (KualiForm) form;
715             setTabStatesForCapitalAssets(kualiForm);
716         }
717 
718 
719     /**
720      * checks the capital accounting lines if any of the lines have been selected for
721      * further processing.
722      *
723      * @param calfb
724      * @return selected return true if lines have been selected else return false
725      */
726     protected boolean capitalAccountingLinesSelected(CapitalAccountingLinesFormBase calfb) {
727         boolean selected = false;
728 
729         CapitalAccountingLinesDocumentBase caldb = (CapitalAccountingLinesDocumentBase) calfb.getFinancialDocument();
730         List<CapitalAccountingLines> capitalAccountingLines = caldb.getCapitalAccountingLines();
731 
732         for (CapitalAccountingLines capitalAccountingLine : capitalAccountingLines) {
733             if (capitalAccountingLine.isSelectLine()) {
734                 selected = true;
735                 break;
736             }
737         }
738 
739         return selected;
740     }
741 
742    /**
743     * runs the validation to check if object subtypes crosses groups on
744     * selected capital accounting lines.
745     *
746     * @param form
747     * @return true if rule passed else false
748     */
749     protected boolean checkObjecSubTypeCrossingCapitalAccountingLines(Document document) {
750         boolean differentObjecSubtypes = true;
751         differentObjecSubtypes &= getRuleService().applyRules(new CapitalAccountingLinesSameObjectCodeSubTypeEvent(document));
752 
753         return differentObjecSubtypes;
754     }
755 
756     /**
757      *
758      * @param mapping An ActionMapping
759      * @param form An ActionForm
760      * @param request The HttpServletRequest
761      * @param response The HttpServletResponse
762      * @throws Exception
763      * @param distributionAmountCode
764      * @return An ActionForward
765      */
766     protected ActionForward performQuestionPrompt(ActionMapping mapping, ActionForm form, HttpServletRequest request, HttpServletResponse response, String actionTypeCode, String distributionAmountCode) throws Exception {
767         ActionForward forward = null;
768         Object question = request.getParameter(OLEConstants.QUESTION_INST_ATTRIBUTE_NAME);
769         CapitalAccountingLinesFormBase calfb = (CapitalAccountingLinesFormBase) form;
770 
771         if (question == null) {
772             String questionText = SpringContext.getBean(ConfigurationService.class).getPropertyValueAsString(OLEKeyConstants.WARNING_NOT_SAME_OBJECT_SUB_TYPES);
773             return this.performQuestionWithoutInput(mapping, form, request, response, OLEConstants.OBJECT_SUB_TYPES_DIFFERENT_QUESTION, questionText, OLEConstants.CONFIRMATION_QUESTION, OLEConstants.ROUTE_METHOD, "");
774         }
775         else {
776             Object buttonClicked = request.getParameter(OLEConstants.QUESTION_CLICKED_BUTTON);
777             // If the user replies 'Yes' the question, proceed..
778             if (OLEConstants.OBJECT_SUB_TYPES_DIFFERENT_QUESTION.equals(question) && ConfirmationQuestion.YES.equals(buttonClicked)) {
779                 createCapitalAssetsForSelectedAccountingLines(form , calfb, actionTypeCode, distributionAmountCode);
780                 
781                 KualiForm kualiForm = (KualiForm) form;
782                 setTabStatesForCapitalAssets(kualiForm);
783 
784                 return mapping.findForward(OLEConstants.MAPPING_BASIC);
785 
786             }
787             // If the user replies 'No' to either of the questions
788             else {
789                 uncheckCapitalAccountingLinesSelected(calfb);
790                 forward = mapping.findForward(OLEConstants.MAPPING_BASIC);
791             }
792         }
793 
794         return forward;
795     }
796 
797     /**
798      * Get the rule service
799      *
800      * @return ruleService
801      */
802     protected KualiRuleService getRuleService() {
803         return SpringContext.getBean(KualiRuleService.class);
804     }
805 }