001/*
002 * The Kuali Financial System, a comprehensive financial management system for higher education.
003 * 
004 * Copyright 2005-2014 The Kuali Foundation
005 * 
006 * This program is free software: you can redistribute it and/or modify
007 * it under the terms of the GNU Affero General Public License as
008 * published by the Free Software Foundation, either version 3 of the
009 * License, or (at your option) any later version.
010 * 
011 * This program is distributed in the hope that it will be useful,
012 * but WITHOUT ANY WARRANTY; without even the implied warranty of
013 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
014 * GNU Affero General Public License for more details.
015 * 
016 * You should have received a copy of the GNU Affero General Public License
017 * along with this program.  If not, see <http://www.gnu.org/licenses/>.
018 */
019package org.kuali.kfs.fp.document.web.struts;
020
021import java.util.ArrayList;
022import java.util.Collections;
023import java.util.List;
024
025import javax.servlet.http.HttpServletRequest;
026import javax.servlet.http.HttpServletResponse;
027
028import org.apache.struts.action.ActionForm;
029import org.apache.struts.action.ActionForward;
030import org.apache.struts.action.ActionMapping;
031import org.kuali.kfs.fp.businessobject.CapitalAccountingLines;
032import org.kuali.kfs.fp.businessobject.CapitalAssetAccountsGroupDetails;
033import org.kuali.kfs.fp.businessobject.CapitalAssetInformation;
034import org.kuali.kfs.fp.businessobject.CapitalAssetInformationDetail;
035import org.kuali.kfs.fp.businessobject.options.CapitalAccountingLinesComparator;
036import org.kuali.kfs.fp.document.CapitalAccountingLinesDocumentBase;
037import org.kuali.kfs.fp.document.validation.event.CapitalAccountingLinesSameObjectCodeSubTypeEvent;
038import org.kuali.kfs.fp.document.validation.impl.CapitalAssetAccountingLineUniquenessEnforcementValidation;
039import org.kuali.kfs.integration.cab.CapitalAssetBuilderModuleService;
040import org.kuali.kfs.sys.KFSConstants;
041import org.kuali.kfs.sys.KFSKeyConstants;
042import org.kuali.kfs.sys.businessobject.AccountingLine;
043import org.kuali.kfs.sys.businessobject.SourceAccountingLine;
044import org.kuali.kfs.sys.businessobject.TargetAccountingLine;
045import org.kuali.kfs.sys.context.SpringContext;
046import org.kuali.kfs.sys.document.AccountingDocument;
047import org.kuali.kfs.sys.document.validation.event.AttributedRouteDocumentEvent;
048import org.kuali.kfs.sys.web.struts.KualiAccountingDocumentFormBase;
049import org.kuali.rice.core.api.config.property.ConfigurationService;
050import org.kuali.rice.core.api.util.RiceConstants;
051import org.kuali.rice.kew.api.exception.WorkflowException;
052import org.kuali.rice.kns.question.ConfirmationQuestion;
053import org.kuali.rice.kns.web.struts.form.KualiDocumentFormBase;
054import org.kuali.rice.kns.web.struts.form.KualiForm;
055import org.kuali.rice.krad.document.Document;
056import org.kuali.rice.krad.rules.rule.event.SaveDocumentEvent;
057import org.kuali.rice.krad.service.KualiRuleService;
058import org.kuali.rice.krad.util.GlobalVariables;
059import org.kuali.rice.krad.util.KRADConstants;
060
061/**
062 * This is the action class for the CapitalAccountingLinesActionBase.
063 */
064public abstract class CapitalAccountingLinesActionBase extends CapitalAssetInformationActionBase {
065    private CapitalAssetBuilderModuleService capitalAssetBuilderModuleService = SpringContext.getBean(CapitalAssetBuilderModuleService.class);
066
067    /**
068     * Upon entry we need to set the capitalAccountingLinesExist boolean and check the tab states
069     * @see org.kuali.kfs.sys.web.struts.KualiAccountingDocumentActionBase#execute(org.apache.struts.action.ActionMapping, org.apache.struts.action.ActionForm, javax.servlet.http.HttpServletRequest, javax.servlet.http.HttpServletResponse)
070     */
071    @Override
072    public ActionForward execute(ActionMapping mapping, ActionForm form, HttpServletRequest request, HttpServletResponse response) throws Exception {
073        KualiDocumentFormBase kualiDocumentFormBase = (KualiDocumentFormBase) form;
074        AccountingDocument tdoc = (AccountingDocument) kualiDocumentFormBase.getDocument();
075
076        initializeCapitalAccountingLinesExist(tdoc);
077        setTabStatesForCapitalAssets(form);
078
079        return super.execute(mapping, form, request, response);
080    }
081
082    /**
083     * Upon entry we need to set the capitalAccountingLinesExist boolean and check the tab states
084     * @see org.kuali.rice.kns.web.struts.action.KualiDocumentActionBase#docHandler(org.apache.struts.action.ActionMapping, org.apache.struts.action.ActionForm, javax.servlet.http.HttpServletRequest, javax.servlet.http.HttpServletResponse)
085     */
086    @Override
087    public ActionForward docHandler(ActionMapping mapping, ActionForm form, HttpServletRequest request, HttpServletResponse response) throws Exception {
088        KualiDocumentFormBase kualiDocumentFormBase = (KualiDocumentFormBase) form;
089        AccountingDocument tdoc = (AccountingDocument) kualiDocumentFormBase.getDocument();
090
091        initializeCapitalAccountingLinesExist(tdoc);
092        setTabStatesForCapitalAssets(form);
093
094        return super.docHandler(mapping, form, request, response);
095    }
096
097    /**
098     * removes capitalaccountinglines which is a transient bo.. and call the super method to
099     * create a error correction document.
100     * @see org.kuali.kfs.sys.document.web.struts.FinancialSystemTransactionalDocumentActionBase#correct(org.apache.struts.action.ActionMapping, org.apache.struts.action.ActionForm, javax.servlet.http.HttpServletRequest, javax.servlet.http.HttpServletResponse)
101     */
102    @Override
103    public ActionForward correct(ActionMapping mapping, ActionForm form, HttpServletRequest request, HttpServletResponse response) throws Exception {
104        CapitalAccountingLinesFormBase capitalAccountingLinesFormBase = (CapitalAccountingLinesFormBase) form;
105        CapitalAccountingLinesDocumentBase caldb = (CapitalAccountingLinesDocumentBase) capitalAccountingLinesFormBase.getFinancialDocument();
106        caldb.getCapitalAccountingLines().clear();
107
108        super.correct(mapping, capitalAccountingLinesFormBase, request, response);
109
110        KualiAccountingDocumentFormBase kadfb = (KualiAccountingDocumentFormBase) form;
111        List<CapitalAssetInformation> currentCapitalAssetInformation =  this.getCurrentCapitalAssetInformationObject(kadfb);
112        for (CapitalAssetInformation capitalAsset : currentCapitalAssetInformation) {
113            capitalAsset.setCapitalAssetProcessedIndicator(false);
114            capitalAsset.setCapitalAssetLineAmount(capitalAsset.getCapitalAssetLineAmount().negated());
115            //remove capital asset tag/location asset tag number and serial number as
116            //they will fail because these values will be duplicates.
117            List<CapitalAssetInformationDetail> tagLocationDetails = capitalAsset.getCapitalAssetInformationDetails();
118            for (CapitalAssetInformationDetail tagLocationDetail : tagLocationDetails) {
119                tagLocationDetail.setCapitalAssetTagNumber(null);
120                tagLocationDetail.setCapitalAssetSerialNumber(null);
121            }
122
123            List<CapitalAssetAccountsGroupDetails> groupAccountLines = capitalAsset.getCapitalAssetAccountsGroupDetails();
124            for (CapitalAssetAccountsGroupDetails groupAccountLine : groupAccountLines) {
125                groupAccountLine.setAmount(groupAccountLine.getAmount().negated());
126            }
127        }
128
129        String distributionAmountCode = capitalAccountingLinesFormBase.getCapitalAccountingLine().getDistributionCode();
130
131        AccountingDocument tdoc = (AccountingDocument) capitalAccountingLinesFormBase.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        caldb.setCapitalAccountingLines(capitalAccountingLines);
141        //checks capital accounting lines for capital assets and if so checks the select box
142        checkSelectForCapitalAccountingLines(capitalAccountingLinesFormBase);
143
144        checkCapitalAccountingLinesSelected(capitalAccountingLinesFormBase);
145        calculatePercentsForSelectedCapitalAccountingLines(capitalAccountingLinesFormBase);
146
147        //setup the initial next sequence number column..
148        setupIntialNextCapitalAssetLineNumber(capitalAccountingLinesFormBase);
149
150        return mapping.findForward(RiceConstants.MAPPING_BASIC);
151    }
152
153    /**
154     * All document-load operations get routed through here
155     *
156     * @see org.kuali.rice.kns.web.struts.action.KualiDocumentActionBase#loadDocument(org.kuali.rice.kns.web.struts.form.KualiDocumentFormBase)
157     */
158    @Override
159    protected void loadDocument(KualiDocumentFormBase kualiDocumentFormBase) throws WorkflowException {
160        super.loadDocument(kualiDocumentFormBase);
161
162        CapitalAccountingLinesFormBase capitalAccountingLinesFormBase = (CapitalAccountingLinesFormBase) kualiDocumentFormBase;
163        AccountingDocument tdoc = (AccountingDocument) kualiDocumentFormBase.getDocument();
164
165        initializeCapitalAccountingLinesExist(tdoc);
166        setTabStatesForCapitalAssets(kualiDocumentFormBase);
167
168        // Since the UI display depends on whether or not capitalAccountingLines is empty to display asset information, we
169        // need to be careful of only generating them if there actually is asset information. Otherwise the user is forced to
170        // select the generate button when they are ready
171        if (checkCreateAssetsExist(capitalAccountingLinesFormBase) || checkModifyAssetsExist(capitalAccountingLinesFormBase)) {
172            String distributionAmountCode = capitalAccountingLinesFormBase.getCapitalAccountingLine().getDistributionCode();
173
174            List<CapitalAccountingLines> capitalAccountingLines = new ArrayList();
175            //for every source/target accounting line that has an object code that requires a
176            //capital asset, creates a capital accounting line that the user can select to
177            //perform create or modify asset functions.
178            createCapitalAccountingLines(capitalAccountingLines, tdoc, distributionAmountCode);
179            sortCaptitalAccountingLines(capitalAccountingLines);
180
181            CapitalAccountingLinesDocumentBase caldb = (CapitalAccountingLinesDocumentBase) tdoc;
182            caldb.setCapitalAccountingLines(capitalAccountingLines);
183            //checks capital accounting lines for capital assets and if so checks the select box
184            checkSelectForCapitalAccountingLines(capitalAccountingLinesFormBase);
185
186            checkCapitalAccountingLinesSelected(capitalAccountingLinesFormBase);
187            calculatePercentsForSelectedCapitalAccountingLines(capitalAccountingLinesFormBase);
188
189            //setup the initial next sequence number column..
190            setupIntialNextCapitalAssetLineNumber(kualiDocumentFormBase);
191
192            KualiForm kualiForm = kualiDocumentFormBase;
193            //based on the records in capital accounting lines, capital asset information lists
194            //set the tabs to open if lists not empty else set to close
195            setTabStatesForCapitalAssets(kualiForm);
196        }
197    }
198
199    /**
200     * checks if the document has any capital accounting lines associated with it and sets
201     * CapitalAccountingLinesDocumentBase.capitalAccountingLinesExist if necessary
202     *
203     * @param tdoc
204     */
205    protected void initializeCapitalAccountingLinesExist(AccountingDocument tdoc) {
206        CapitalAccountingLinesDocumentBase caldb = (CapitalAccountingLinesDocumentBase) tdoc;
207
208        List<SourceAccountingLine> sourceAccountLines = tdoc.getSourceAccountingLines();
209        for (SourceAccountingLine line : sourceAccountLines) {
210            if (capitalAssetBuilderModuleService.hasCapitalAssetObjectSubType(line)) {
211                caldb.setCapitalAccountingLinesExist(true);
212                break;
213            }
214        }
215
216        // If it isn't true already, check the target lines
217        if (!caldb.isCapitalAccountingLinesExist()) {
218            List<TargetAccountingLine> targetAccountLines = tdoc.getTargetAccountingLines();
219            for (TargetAccountingLine line : targetAccountLines) {
220                if (capitalAssetBuilderModuleService.hasCapitalAssetObjectSubType(line)) {
221                    caldb.setCapitalAccountingLinesExist(true);
222                    break;
223                }
224            }
225        }
226    }
227
228    /**
229     * When user adds an accounting line to the either source or target, if the object code on
230     * that line has capital object type code group then a capital accounting line is created.
231     * @see org.kuali.kfs.sys.web.struts.KualiAccountingDocumentActionBase#insertAccountingLine(boolean, org.kuali.kfs.sys.web.struts.KualiAccountingDocumentFormBase, org.kuali.kfs.sys.businessobject.AccountingLine)
232     */
233    @Override
234    protected void insertAccountingLine(boolean isSource, KualiAccountingDocumentFormBase kualiDocumentFormBase, AccountingLine line) {
235        AccountingDocument tdoc = (AccountingDocument) kualiDocumentFormBase.getDocument();
236        CapitalAccountingLinesDocumentBase caldb = (CapitalAccountingLinesDocumentBase) tdoc;
237
238        if(capitalAssetBuilderModuleService.hasCapitalAssetObjectSubType(line) && caldb.getCapitalAccountingLines().size() > 0) {
239            if (line.isSourceAccountingLine()) {
240                GlobalVariables.getMessageMap().putError(KFSConstants.NEW_SOURCE_LINE_ERRORS, KFSKeyConstants.ERROR_DOCUMENT_CANT_ADD_CAPITALIZATION_ACCOUNTING_LINES);
241            } else {
242                GlobalVariables.getMessageMap().putError(KFSConstants.NEW_TARGET_LINE_ERRORS, KFSKeyConstants.ERROR_DOCUMENT_CANT_ADD_CAPITALIZATION_ACCOUNTING_LINES);
243            }
244        } else {
245            super.insertAccountingLine(isSource, kualiDocumentFormBase, line);
246
247            initializeCapitalAccountingLinesExist(tdoc);
248
249            setTabStatesForCapitalAssets(kualiDocumentFormBase);
250        }
251    }
252
253    /**
254     * creates the capital accounting lines looking at source and/or target accounting lines.
255     *
256     * @param capitalAccountingLines
257     * @param tdoc
258     * @param distributionAmountCode distribution amount code for the line
259     */
260    protected void createCapitalAccountingLines(List<CapitalAccountingLines> capitalAccountingLines, AccountingDocument tdoc, String distributionAmountCode) {
261        List<SourceAccountingLine> sourceAccountLines = tdoc.getSourceAccountingLines();
262
263        CapitalAccountingLinesDocumentBase caldb = (CapitalAccountingLinesDocumentBase) tdoc;
264
265        for (SourceAccountingLine line : sourceAccountLines) {
266            //create source capital accounting line
267            createCapitalAccountingLine(capitalAccountingLines, line, distributionAmountCode);
268        }
269
270        List<TargetAccountingLine> targetAccountLines = tdoc.getTargetAccountingLines();
271
272        for (TargetAccountingLine line : targetAccountLines) {
273            // create target capital accounting line
274            createCapitalAccountingLine(capitalAccountingLines, line, distributionAmountCode);
275        }
276
277        //sort the capital accounting lines collection
278        sortCaptitalAccountingLines(capitalAccountingLines);
279    }
280
281    /**
282     * Checks if the accounting line has an object code that belongs to object sub type group codes and
283     * if so, creates a capital accounting line that will be displayed on the jsp.
284     *
285     * @param capitalAccountingLines
286     * @param line
287     * @param distributionAmountCode
288     * @return List of capitalAccountingLines
289     */
290    protected List<CapitalAccountingLines> createCapitalAccountingLine(List<CapitalAccountingLines> capitalAccountingLines, AccountingLine line, String distributionAmountCode) {
291        Integer sequenceNumber = capitalAccountingLines.size() + 1;
292
293        if (capitalAssetBuilderModuleService.hasCapitalAssetObjectSubType(line)) {
294            //capital object code so we need to build the capital accounting line...
295            CapitalAccountingLines cal = addCapitalAccountingLine(capitalAccountingLines, line);
296            cal.setDistributionAmountCode(distributionAmountCode);
297            capitalAccountingLines.add(cal);
298        }
299
300        return capitalAccountingLines;
301    }
302
303    /**
304     * convenience method to add a new capital accounting line to the collection of capital
305     * accounting lines.
306     *
307     * @param capitalAccountingLines
308     * @param line
309     * @return cal newly created capital accounting line
310     */
311    protected CapitalAccountingLines addCapitalAccountingLine(List<CapitalAccountingLines> capitalAccountingLines, AccountingLine line) {
312        CapitalAccountingLines cal = new CapitalAccountingLines();
313
314        if (line instanceof SourceAccountingLine) {
315            cal.setLineType(KFSConstants.SOURCE);
316        }
317        else {
318            cal.setLineType(KFSConstants.TARGET);
319        }
320        cal.setSequenceNumber(line.getSequenceNumber());
321        cal.setChartOfAccountsCode(line.getChartOfAccountsCode());
322        cal.setAccountNumber(line.getAccountNumber());
323        cal.setSubAccountNumber(line.getSubAccountNumber());
324        cal.setFinancialObjectCode(line.getFinancialObjectCode());
325        cal.setFinancialSubObjectCode(line.getFinancialSubObjectCode());
326        cal.setProjectCode(line.getProjectCode());
327        cal.setOrganizationReferenceId(line.getOrganizationReferenceId());
328        cal.setFinancialDocumentLineDescription(line.getFinancialDocumentLineDescription());
329        cal.setAmount(line.getAmount());
330        cal.setAccountLinePercent(null);
331        cal.setSelectLine(false);
332
333        return cal;
334    }
335
336    /**
337     * sort the capital accounting lines collection based on financial object code and account number.
338     * @param capitalAccountingLines List of capital accounting lines
339     */
340    protected void sortCaptitalAccountingLines(List<CapitalAccountingLines> capitalAccountingLines) {
341        CapitalAccountingLinesComparator calComparator = new CapitalAccountingLinesComparator();
342
343        //sort the collection based on financial object code and account number
344        Collections.sort(capitalAccountingLines, calComparator);
345    }
346
347    /**
348     * Supports the generate button on the UI. It generates the capital accounting lines
349     * @param mapping
350     * @param form
351     * @param request
352     * @param response
353     * @return
354     * @throws Exception
355     */
356    public ActionForward generateAccountingLinesForCapitalization(ActionMapping mapping, ActionForm form, HttpServletRequest request, HttpServletResponse response) throws Exception {
357        KualiAccountingDocumentFormBase kualiAccountingDocumentFormBase = (KualiAccountingDocumentFormBase) form;
358        CapitalAccountingLinesFormBase capitalAccountingLinesFormBase = (CapitalAccountingLinesFormBase) form;
359        CapitalAccountingLinesDocumentBase caldb = (CapitalAccountingLinesDocumentBase) capitalAccountingLinesFormBase.getFinancialDocument();
360
361        CapitalAssetAccountingLineUniquenessEnforcementValidation uniquenessValidation = new CapitalAssetAccountingLineUniquenessEnforcementValidation();
362        uniquenessValidation.setAccountingDocumentForValidation(caldb);
363        if (uniquenessValidation.validate(new AttributedRouteDocumentEvent(caldb))
364                && getRuleService().applyRules(new SaveDocumentEvent(caldb))) {
365            String distributionAmountCode = capitalAccountingLinesFormBase.getCapitalAccountingLine().getDistributionCode();
366
367            List<CapitalAccountingLines> capitalAccountingLines = caldb.getCapitalAccountingLines();
368            AccountingDocument tdoc = (AccountingDocument) kualiAccountingDocumentFormBase.getDocument();
369
370            createCapitalAccountingLines(capitalAccountingLines, tdoc, distributionAmountCode);
371        }
372
373        return mapping.findForward(KFSConstants.MAPPING_BASIC);
374    }
375
376    /**
377     * Supports the delete button for capital accounting lines on the UI
378     * @param mapping
379     * @param form
380     * @param request
381     * @param response
382     * @return
383     * @throws Exception
384     */
385    public ActionForward deleteAccountingLinesForCapitalization(ActionMapping mapping, ActionForm form, HttpServletRequest request, HttpServletResponse response) throws Exception {
386        CapitalAccountingLinesFormBase capitalAccountingLinesFormBase = (CapitalAccountingLinesFormBase) form;
387        CapitalAccountingLinesDocumentBase caldb = (CapitalAccountingLinesDocumentBase) capitalAccountingLinesFormBase.getFinancialDocument();
388
389        if (capitalAccountingLinesFormBase.getDocumentActions().containsKey(KRADConstants.KUALI_ACTION_CAN_EDIT)) {
390            caldb.setCapitalAccountingLines(new ArrayList<CapitalAccountingLines>());
391            caldb.setCapitalAssetInformation(new ArrayList());
392        }
393
394        return mapping.findForward(KFSConstants.MAPPING_BASIC);
395    }
396
397    /**
398     * Action "create" creates assets for the selected capital
399     * accounting lines.  An error message is shown if no capital accounting lines
400     * are selected for processing.  The action checks if the selected
401     * capital accounting lines object sub type cross based on the system paramter
402     * values for the object subtypes and if so prompts the user to confirm to continue
403     * to create the assets for the select capital accounting lines.
404     *
405     * @param mapping
406     * @param form
407     * @param request
408     * @param response
409     * @return ActionForward
410     * @throws Exception
411     */
412    public ActionForward createAsset(ActionMapping mapping, ActionForm form, HttpServletRequest request, HttpServletResponse response) throws Exception {
413        CapitalAccountingLinesFormBase calfb = (CapitalAccountingLinesFormBase) form;
414        String distributionAmountCode = calfb.getCapitalAccountingLine().getDistributionCode();
415        if (KFSConstants.CapitalAssets.DISTRIBUTE_COST_EQUALLY_CODE.equals(distributionAmountCode)) {
416           calfb.setDistributeEqualAmount(true);
417        }
418        else {
419            calfb.setDistributeEqualAmount(false);
420        }
421
422        boolean createAction = calfb.getCapitalAccountingLine().isCanCreateAsset();
423        calfb.setEditCreateOrModify(false);
424
425        GlobalVariables.getMessageMap().clearErrorMessages();
426        if (!capitalAccountingLinesSelected(calfb)) {
427            GlobalVariables.getMessageMap().putError(KFSConstants.EDIT_ACCOUNTING_LINES_FOR_CAPITALIZATION_ERRORS, KFSKeyConstants.ERROR_DOCUMENT_ACCOUNTING_LINE_FOR_CAPITALIZATAION_REQUIRED_CREATE);
428            return mapping.findForward(KFSConstants.MAPPING_BASIC);
429        }
430        else {
431            calfb.setEditCreateOrModify(false);
432        }
433
434        Document document = calfb.getFinancialDocument();
435
436        //if same object subtypes then continue creating capital assets....
437        if (checkObjecSubTypeCrossingCapitalAccountingLines(document)) {
438            //question the user if to continue....
439            ActionForward forward = performQuestionPrompt(mapping, form, request, response, KFSConstants.CapitalAssets.CAPITAL_ASSET_CREATE_ACTION_INDICATOR, distributionAmountCode);
440            if (forward != null) {
441                return forward;
442            }
443        }
444        else {
445            createCapitalAssetsForSelectedAccountingLines(form , calfb, KFSConstants.CapitalAssets.CAPITAL_ASSET_CREATE_ACTION_INDICATOR, distributionAmountCode);
446        }
447
448        //restore the tab states....
449        setTabStatesForCapitalAssets(form);
450
451        return mapping.findForward(KFSConstants.MAPPING_BASIC);
452    }
453
454    /**
455     * Action "modify" creates assets for the selected capital
456     * accounting lines.  An error message is shown if no capital accounting lines
457     * are selected for processing.  The action checks if the selected
458     * capital accounting lines object sub type cross based on the system paramter
459     * values for the object subtypes and if so prompts the user to confirm to continue
460     * to create the assets for the select capital accounting lines.
461     *
462     * @param mapping
463     * @param form
464     * @param request
465     * @param response
466     * @return ActionForward
467     * @throws Exception
468     */
469    public ActionForward modifyAsset(ActionMapping mapping, ActionForm form, HttpServletRequest request, HttpServletResponse response) throws Exception {
470        CapitalAccountingLinesFormBase calfb = (CapitalAccountingLinesFormBase) form;
471        String distributionAmountCode = calfb.getCapitalAccountingLine().getDistributionCode();
472
473        if (KFSConstants.CapitalAssets.DISTRIBUTE_COST_EQUALLY_CODE.equals(distributionAmountCode)) {
474            calfb.setDistributeEqualAmount(true);
475         }
476        else {
477            calfb.setDistributeEqualAmount(false);
478        }
479
480        GlobalVariables.getMessageMap().clearErrorMessages();
481        if (!capitalAccountingLinesSelected(calfb)) {
482            GlobalVariables.getMessageMap().putError(KFSConstants.EDIT_ACCOUNTING_LINES_FOR_CAPITALIZATION_ERRORS, KFSKeyConstants.ERROR_DOCUMENT_ACCOUNTING_LINE_FOR_CAPITALIZATAION_REQUIRED_MODIFY);
483            return mapping.findForward(KFSConstants.MAPPING_BASIC);
484        }
485        else {
486            calfb.setEditCreateOrModify(false);
487        }
488
489        Document document = calfb.getFinancialDocument();
490
491        //if same object subtypes then continue creating capital assets....
492        if (checkObjecSubTypeCrossingCapitalAccountingLines(document)) {
493            //question the user if to continue....
494            ActionForward forward = performQuestionPrompt(mapping, form, request, response, KFSConstants.CapitalAssets.CAPITAL_ASSET_MODIFY_ACTION_INDICATOR, distributionAmountCode);
495            if (forward != null) {
496                return forward;
497            }
498        }
499        else {
500            createCapitalAssetsForSelectedAccountingLines(form , calfb, KFSConstants.CapitalAssets.CAPITAL_ASSET_MODIFY_ACTION_INDICATOR, distributionAmountCode);
501        }
502
503        //restore the tab states....
504        setTabStatesForCapitalAssets(form);
505
506        return mapping.findForward(KFSConstants.MAPPING_BASIC);
507    }
508
509    /**
510     * Helper method to first calculate the percents for the selected capital accounting lines as
511     * the percent is required if the user is distributing the amounts by individual amount
512     * method.  It then populates created or modified assets with asset accounting lines.
513     *
514     * @param form
515     * @param calfb
516     * @param actionTypeIndicator indicates whether creating an asset for "create" or "modify" actions.
517     * @param distributionAmountCode amount distribution code
518     */
519    protected void createCapitalAssetsForSelectedAccountingLines(ActionForm form, CapitalAccountingLinesFormBase calfb, String actionTypeIndicator, String distributionAmountCode) {
520        calculatePercentsForSelectedCapitalAccountingLines(calfb);
521        createCapitalAssetForGroupAccountingLines(calfb, actionTypeIndicator, distributionAmountCode);
522        checkCapitalAccountingLinesSelected(calfb);
523
524        KualiForm kualiForm = (KualiForm) form;
525        setTabStatesForCapitalAssets(kualiForm);
526    }
527
528
529    /**
530     * checks the capital accounting lines if any of the lines have been selected for
531     * further processing.
532     *
533     * @param calfb
534     * @return selected return true if lines have been selected else return false
535     */
536    protected boolean capitalAccountingLinesSelected(CapitalAccountingLinesFormBase calfb) {
537        boolean selected = false;
538
539        CapitalAccountingLinesDocumentBase caldb = (CapitalAccountingLinesDocumentBase) calfb.getFinancialDocument();
540        List<CapitalAccountingLines> capitalAccountingLines = caldb.getCapitalAccountingLines();
541
542        for (CapitalAccountingLines capitalAccountingLine : capitalAccountingLines) {
543            if (capitalAccountingLine.isSelectLine()) {
544                selected = true;
545                break;
546            }
547        }
548
549        return selected;
550    }
551
552   /**
553    * runs the validation to check if object subtypes crosses groups on
554    * selected capital accounting lines.
555    *
556    * @param form
557    * @return true if rule passed else false
558    */
559    protected boolean checkObjecSubTypeCrossingCapitalAccountingLines(Document document) {
560        boolean differentObjecSubtypes = true;
561        differentObjecSubtypes &= getRuleService().applyRules(new CapitalAccountingLinesSameObjectCodeSubTypeEvent(document));
562
563        return differentObjecSubtypes;
564    }
565
566    /**
567     *
568     * @param mapping An ActionMapping
569     * @param form An ActionForm
570     * @param request The HttpServletRequest
571     * @param response The HttpServletResponse
572     * @throws Exception
573     * @param distributionAmountCode
574     * @return An ActionForward
575     */
576    protected ActionForward performQuestionPrompt(ActionMapping mapping, ActionForm form, HttpServletRequest request, HttpServletResponse response, String actionTypeCode, String distributionAmountCode) throws Exception {
577        ActionForward forward = null;
578        Object question = request.getParameter(KFSConstants.QUESTION_INST_ATTRIBUTE_NAME);
579        CapitalAccountingLinesFormBase calfb = (CapitalAccountingLinesFormBase) form;
580
581        if (question == null) {
582            String questionText = SpringContext.getBean(ConfigurationService.class).getPropertyValueAsString(KFSKeyConstants.WARNING_NOT_SAME_OBJECT_SUB_TYPES);
583            return this.performQuestionWithoutInput(mapping, form, request, response, KFSConstants.OBJECT_SUB_TYPES_DIFFERENT_QUESTION, questionText, KFSConstants.CONFIRMATION_QUESTION, KFSConstants.ROUTE_METHOD, "");
584        }
585        else {
586            Object buttonClicked = request.getParameter(KFSConstants.QUESTION_CLICKED_BUTTON);
587            // If the user replies 'Yes' the question, proceed..
588            if (KFSConstants.OBJECT_SUB_TYPES_DIFFERENT_QUESTION.equals(question) && ConfirmationQuestion.YES.equals(buttonClicked)) {
589                createCapitalAssetsForSelectedAccountingLines(form , calfb, actionTypeCode, distributionAmountCode);
590
591                KualiForm kualiForm = (KualiForm) form;
592                setTabStatesForCapitalAssets(kualiForm);
593
594                return mapping.findForward(KFSConstants.MAPPING_BASIC);
595
596            }
597            // If the user replies 'No' to either of the questions
598            else {
599                uncheckCapitalAccountingLinesSelected(calfb);
600                forward = mapping.findForward(KFSConstants.MAPPING_BASIC);
601            }
602        }
603
604        return forward;
605    }
606
607    /**
608     * Get the rule service
609     *
610     * @return ruleService
611     */
612    protected KualiRuleService getRuleService() {
613        return SpringContext.getBean(KualiRuleService.class);
614    }
615}