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.validation.impl;
017    
018    import org.apache.commons.lang.StringUtils;
019    import org.kuali.kfs.coa.businessobject.Account;
020    import org.kuali.kfs.coa.businessobject.Chart;
021    import org.kuali.kfs.coa.businessobject.ObjectCode;
022    import org.kuali.kfs.coa.businessobject.ObjectLevel;
023    import org.kuali.kfs.coa.businessobject.ProjectCode;
024    import org.kuali.kfs.coa.businessobject.SubAccount;
025    import org.kuali.kfs.coa.businessobject.SubObjectCode;
026    import org.kuali.kfs.coa.service.AccountService;
027    import org.kuali.kfs.coa.service.ChartService;
028    import org.kuali.kfs.coa.service.ObjectCodeService;
029    import org.kuali.kfs.coa.service.ObjectLevelService;
030    import org.kuali.kfs.module.endow.EndowConstants;
031    import org.kuali.kfs.module.endow.EndowKeyConstants;
032    import org.kuali.kfs.module.endow.EndowPropertyConstants;
033    import org.kuali.kfs.module.endow.businessobject.EndowmentAccountingLine;
034    import org.kuali.kfs.module.endow.businessobject.SourceEndowmentAccountingLine;
035    import org.kuali.kfs.module.endow.document.EndowmentAccountingLinesDocument;
036    import org.kuali.kfs.module.endow.document.EndowmentAccountingLinesDocumentBase;
037    import org.kuali.kfs.module.endow.document.validation.AddEndowmentAccountingLineRule;
038    import org.kuali.kfs.module.endow.document.validation.DeleteEndowmentAccountingLineRule;
039    import org.kuali.kfs.sys.KFSConstants;
040    import org.kuali.kfs.sys.KFSKeyConstants;
041    import org.kuali.kfs.sys.KFSPropertyConstants;
042    import org.kuali.kfs.sys.context.SpringContext;
043    import org.kuali.rice.kns.datadictionary.DataDictionary;
044    import org.kuali.rice.kns.document.Document;
045    import org.kuali.rice.kns.service.DataDictionaryService;
046    import org.kuali.rice.kns.util.GlobalVariables;
047    import org.kuali.rice.kns.util.KualiDecimal;
048    import org.kuali.rice.kns.util.ObjectUtils;
049    
050    public class EndowmentAccountingLinesDocumentBaseRules extends EndowmentTransactionLinesDocumentBaseRules implements AddEndowmentAccountingLineRule<EndowmentAccountingLinesDocument, EndowmentAccountingLine>, DeleteEndowmentAccountingLineRule<EndowmentAccountingLinesDocument, EndowmentAccountingLine> {
051    
052        /**
053         * @see org.kuali.kfs.module.endow.document.validation.AddEndowmentAccountingLineRule#processAddEndowmentAccountingLineRules(org.kuali.kfs.module.endow.document.EndowmentAccountingLinesDocument,
054         *      org.kuali.kfs.module.endow.businessobject.EndowmentAccountingLine)
055         */
056        public boolean processAddEndowmentAccountingLineRules(EndowmentAccountingLinesDocument endowmentAccountingLinesDocument, EndowmentAccountingLine endowmentAccountingLine) {
057            boolean isValid = true;
058            isValid &= validateAccountingLine(endowmentAccountingLinesDocument, endowmentAccountingLine, -1);
059            return isValid;
060        }
061    
062        /**
063         * @see org.kuali.kfs.module.endow.document.validation.DeleteEndowmentAccountingLineRule#processDeleteAccountingLineRules(org.kuali.kfs.module.endow.document.EndowmentAccountingLinesDocument,
064         *      org.kuali.kfs.module.endow.businessobject.EndowmentAccountingLine)
065         */
066        public boolean processDeleteAccountingLineRules(EndowmentAccountingLinesDocument EndowmentAccountingLinesDocument, EndowmentAccountingLine EndowmentAccountingLine) {
067            // TODO Auto-generated method stub
068            return true;
069        }
070    
071        /**
072         * Validates the given accounting Line.
073         * 
074         * @param accountingLinesDocument
075         * @param accountingLine
076         * @param index
077         * @return true if valid, false otherwise
078         */
079        protected boolean validateAccountingLine(EndowmentAccountingLinesDocument accountingLinesDocument, EndowmentAccountingLine accountingLine, int index) {
080            boolean isValid = true;
081    
082            // validate chart code
083            if (isChartCodeEmpty(accountingLine, index)) {
084                return false;
085            }
086    
087            if (!validateChartCode(accountingLine, index)) {
088                return false;
089            }
090    
091            isValid &= validateChartCodeIsActive(accountingLine, index);
092    
093            // validate account
094            if (isAccountNumberEmpty(accountingLine, index)) {
095                return false;
096            }
097    
098            if (!validateAccount(accountingLine, index)) {
099                return false;
100            }
101    
102            isValid &= validateAccountIsActive(accountingLine, index);
103            isValid &= validateAccountNotExpired(accountingLine, index);
104    
105            // validate object code
106            if (isObjectCodeEmpty(accountingLine, index)) {
107                return false;
108            }
109    
110            if (!validateObjectCode(accountingLine, index)) {
111                return false;
112            }
113    
114            isValid &= validateObjectCodeIsActive(accountingLine, index);
115            isValid &= validateObjectCodeObjectConsolidation(accountingLine, index);
116            isValid &= validateObjectCodeType(accountingLine, index);
117    
118            isValid &= validateSubAccountNumber(accountingLine, index);
119            isValid &= validateSubObjectCode(accountingLine, index);
120            isValid &= validateProjectCode(accountingLine, index);
121    
122            isValid &= validateTransactionAmount(accountingLine, index);
123    
124            return isValid;
125        }
126    
127    
128        /**
129         * Validates the transaction amount for the given accounting line.
130         * 
131         * @param accountingLine
132         * @param index
133         * @return true if valid, false otherwise
134         */
135        private boolean validateTransactionAmount(EndowmentAccountingLine accountingLine, int index) {
136            boolean isValid = true;
137    
138            if (accountingLine.getAmount().isLessEqual(KualiDecimal.ZERO)) {
139                putFieldError(getAcctLineErrorPrefix(accountingLine, index) + EndowPropertyConstants.ENDOWMENT_ACCOUNTING_LINE_AMOUNT, EndowKeyConstants.EndowmentTransactionDocumentConstants.ERROR_ACCT_LINE_AMT_INVALID);
140                isValid = false;
141            }
142    
143            return isValid;
144    
145        }
146    
147    
148        /**
149         * Gets the prefix for an accounting line error.
150         * 
151         * @param line
152         * @param index
153         * @return the prefix
154         */
155        public String getAcctLineErrorPrefix(EndowmentAccountingLine line, int index) {
156            String ERROR_PREFIX = null;
157            if (line instanceof SourceEndowmentAccountingLine) {
158                if (index == -1) {
159                    ERROR_PREFIX = EndowPropertyConstants.SOURCE_ACCT_LINE_PREFIX;
160                }
161                else {
162                    ERROR_PREFIX = EndowPropertyConstants.EXISTING_SOURCE_ACCT_LINE_PREFIX + "[" + index + "].";
163                }
164            }
165            else {
166                if (index == -1) {
167                    ERROR_PREFIX = EndowPropertyConstants.TARGET_ACCT_LINE_PREFIX;
168                }
169                else {
170                    ERROR_PREFIX = EndowPropertyConstants.EXISTING_TARGET_ACCT_LINE_PREFIX + "[" + index + "].";
171                }
172            }
173            return ERROR_PREFIX;
174    
175        }
176    
177        /**
178         * Checks if the chart code is empty.
179         * 
180         * @param line
181         * @param index
182         * @return true if valid, false otherwise
183         */
184        protected boolean isChartCodeEmpty(EndowmentAccountingLine line, int index) {
185            if (StringUtils.isBlank(line.getChartOfAccountsCode())) {
186                putFieldError(getAcctLineErrorPrefix(line, index) + EndowPropertyConstants.ENDOWMENT_ACCOUNTING_LINE_CHART_CD, EndowKeyConstants.EndowmentTransactionDocumentConstants.ERROR_ACCT_LINE_CHART_CODE_REQUIRED);
187                return true;
188            }
189            else
190                return false;
191        }
192    
193        /**
194         * Validates that the chart code exists in the database.
195         * 
196         * @param line
197         * @param index
198         * @return true if valid, false otherwise
199         */
200        protected boolean validateChartCode(EndowmentAccountingLine line, int index) {
201            boolean isValid = true;
202    
203            String chartOfAccountsCode = line.getChartOfAccountsCode();
204    
205            Chart chartCode = SpringContext.getBean(ChartService.class).getByPrimaryId(chartOfAccountsCode);
206    
207            if (ObjectUtils.isNull(chartCode)) {
208                isValid = false;
209                putFieldError(getAcctLineErrorPrefix(line, index) + EndowPropertyConstants.ENDOWMENT_ACCOUNTING_LINE_CHART_CD, EndowKeyConstants.EndowmentTransactionDocumentConstants.ERROR_ACCT_LINE_CHART_CODE_INVALID);
210            }
211    
212            return isValid;
213        }
214    
215        /**
216         * Validates if the chart code is Active.
217         * 
218         * @param line
219         * @param index
220         * @return true of active, false otherwise
221         */
222        protected boolean validateChartCodeIsActive(EndowmentAccountingLine line, int index) {
223            boolean isValid = true;
224    
225            String chartOfAccountsCode = line.getChartOfAccountsCode();
226    
227            Chart chartCode = SpringContext.getBean(ChartService.class).getByPrimaryId(chartOfAccountsCode);
228    
229            if (ObjectUtils.isNotNull(chartCode)) {
230                if (!chartCode.isActive()) {
231                    isValid = false;
232                    putFieldError(getAcctLineErrorPrefix(line, index) + EndowPropertyConstants.ENDOWMENT_ACCOUNTING_LINE_CHART_CD, EndowKeyConstants.EndowmentTransactionDocumentConstants.ERROR_ACCT_LINE_CHART_CODE_INACTIVE);
233                }
234            }
235    
236            return isValid;
237        }
238    
239        /**
240         * Checks if the account number is empty.
241         * 
242         * @param line
243         * @param index
244         * @return true if empty, false otherwise
245         */
246        protected boolean isAccountNumberEmpty(EndowmentAccountingLine line, int index) {
247            if (StringUtils.isBlank(line.getAccountNumber())) {
248                putFieldError(getAcctLineErrorPrefix(line, index) + EndowPropertyConstants.ENDOWMENT_ACCOUNTING_LINE_ACCT_NBR, EndowKeyConstants.EndowmentTransactionDocumentConstants.ERROR_ACCT_LINE_CHART_CODE_REQUIRED);
249                return true;
250            }
251            else
252                return false;
253        }
254    
255        /**
256         * Validates if the account exists in the database.
257         * 
258         * @param line
259         * @param index
260         * @return true if it exists, false otherwise
261         */
262        protected boolean validateAccount(EndowmentAccountingLine line, int index) {
263            boolean isValid = true;
264    
265            String accountNumber = line.getAccountNumber();
266            String chartOfAccountsCode = line.getChartOfAccountsCode();
267    
268            Account account = SpringContext.getBean(AccountService.class).getByPrimaryId(chartOfAccountsCode, accountNumber);
269    
270            if (ObjectUtils.isNull(account)) {
271                isValid = false;
272                putFieldError(getAcctLineErrorPrefix(line, index) + EndowPropertyConstants.ENDOWMENT_ACCOUNTING_LINE_ACCT_NBR, EndowKeyConstants.EndowmentTransactionDocumentConstants.ERROR_ACCT_LINE_ACCT_NBR_INVALID);
273            }
274    
275            return isValid;
276        }
277    
278        /**
279         * Validates that the account is active.
280         * 
281         * @param line
282         * @param index
283         * @return true if active, false otherwise
284         */
285        protected boolean validateAccountIsActive(EndowmentAccountingLine line, int index) {
286            boolean isValid = true;
287    
288            String accountNumber = line.getAccountNumber();
289            String chartOfAccountsCode = line.getChartOfAccountsCode();
290    
291            Account account = SpringContext.getBean(AccountService.class).getByPrimaryId(chartOfAccountsCode, accountNumber);
292    
293            if (ObjectUtils.isNotNull(account)) {
294                if (!account.isActive()) {
295                    isValid = false;
296                    putFieldError(getAcctLineErrorPrefix(line, index) + EndowPropertyConstants.ENDOWMENT_ACCOUNTING_LINE_ACCT_NBR, EndowKeyConstants.EndowmentTransactionDocumentConstants.ERROR_ACCT_LINE_ACCT_NBR_INACTIVE);
297                }
298            }
299    
300            return isValid;
301        }
302    
303        /**
304         * Validates if the account is expired.
305         * 
306         * @param line
307         * @param index
308         * @return true if not expired, false otherwise.
309         */
310        protected boolean validateAccountNotExpired(EndowmentAccountingLine line, int index) {
311            boolean isValid = true;
312    
313            String accountNumber = line.getAccountNumber();
314            String chartOfAccountsCode = line.getChartOfAccountsCode();
315    
316            Account account = SpringContext.getBean(AccountService.class).getByPrimaryId(chartOfAccountsCode, accountNumber);
317    
318            if (ObjectUtils.isNotNull(account)) {
319                if (account.isExpired()) {
320                    isValid = false;
321                    putFieldError(getAcctLineErrorPrefix(line, index) + EndowPropertyConstants.ENDOWMENT_ACCOUNTING_LINE_ACCT_NBR, EndowKeyConstants.EndowmentTransactionDocumentConstants.ERROR_ACCT_LINE_ACCT_NBR_EXPIRED);
322                }
323            }
324    
325            return isValid;
326        }
327    
328        /**
329         * Checks if the object code is empty.
330         * 
331         * @param line
332         * @param index
333         * @return true if empty, false otherwise
334         */
335        protected boolean isObjectCodeEmpty(EndowmentAccountingLine line, int index) {
336    
337            if (StringUtils.isBlank(line.getFinancialObjectCode())) {
338                putFieldError(getAcctLineErrorPrefix(line, index) + EndowPropertyConstants.ENDOWMENT_ACCOUNTING_LINE_OBJECT_CD, EndowKeyConstants.EndowmentTransactionDocumentConstants.ERROR_ACCT_LINE_OBJECT_CODE_REQUIRED);
339                return true;
340            }
341            else
342                return false;
343        }
344    
345        /**
346         * Validates that the object code exists.
347         * 
348         * @param line
349         * @param index
350         * @return true if valid, false otherwise
351         */
352        protected boolean validateObjectCode(EndowmentAccountingLine line, int index) {
353            boolean isValid = true;
354    
355            String financialObjectCode = line.getFinancialObjectCode();
356            String chartOfAccountsCode = line.getChartOfAccountsCode();
357    
358            ObjectCode objectCode = SpringContext.getBean(ObjectCodeService.class).getByPrimaryIdForCurrentYear(chartOfAccountsCode, financialObjectCode);
359    
360            if (ObjectUtils.isNull(objectCode)) {
361                isValid = false;
362                putFieldError(getAcctLineErrorPrefix(line, index) + EndowPropertyConstants.ENDOWMENT_ACCOUNTING_LINE_OBJECT_CD, EndowKeyConstants.EndowmentTransactionDocumentConstants.ERROR_ACCT_LINE_OBJECT_CODE_INVALID);
363            }
364    
365            return isValid;
366        }
367    
368        /**
369         * Validates that the object code is active.
370         * 
371         * @param line
372         * @param index
373         * @return true if active, false otherwise
374         */
375        protected boolean validateObjectCodeIsActive(EndowmentAccountingLine line, int index) {
376            boolean isValid = true;
377    
378            String financialObjectCode = line.getFinancialObjectCode();
379            String chartOfAccountsCode = line.getChartOfAccountsCode();
380    
381            ObjectCode objectCode = SpringContext.getBean(ObjectCodeService.class).getByPrimaryIdForCurrentYear(chartOfAccountsCode, financialObjectCode);
382    
383            if (ObjectUtils.isNotNull(objectCode)) {
384                if (!objectCode.isActive()) {
385                    isValid = false;
386                    putFieldError(getAcctLineErrorPrefix(line, index) + EndowPropertyConstants.ENDOWMENT_ACCOUNTING_LINE_OBJECT_CD, EndowKeyConstants.EndowmentTransactionDocumentConstants.ERROR_ACCT_LINE_OBJECT_CODE_INACTIVE);
387                }
388            }
389    
390            return isValid;
391        }
392    
393        /**
394         * Validate that the object code does not represent assets, liabilities or funds balances (as indicated by the object code's
395         * object consolidation).
396         * 
397         * @param line
398         * @param index
399         * @return true if valid, false otherwise
400         */
401        protected boolean validateObjectCodeObjectConsolidation(EndowmentAccountingLine line, int index) {
402            boolean isValid = true;
403    
404            String financialObjectCode = line.getFinancialObjectCode();
405            String chartOfAccountsCode = line.getChartOfAccountsCode();
406    
407            ObjectCode objectCode = SpringContext.getBean(ObjectCodeService.class).getByPrimaryIdForCurrentYear(chartOfAccountsCode, financialObjectCode);
408            ObjectLevel objectLevel = SpringContext.getBean(ObjectLevelService.class).getByPrimaryId(chartOfAccountsCode, objectCode.getFinancialObjectLevelCode());
409    
410            if (ObjectUtils.isNotNull(objectLevel)) {
411                String consolidatedObjectCode = objectCode.getFinancialObjectLevel().getFinancialConsolidationObjectCode();
412    
413                if (EndowConstants.ConsolidatedObjectCode.ASSETS.equalsIgnoreCase(consolidatedObjectCode) || EndowConstants.ConsolidatedObjectCode.LIABILITIES.equalsIgnoreCase(consolidatedObjectCode) || EndowConstants.ConsolidatedObjectCode.FUND_BALANCE.equalsIgnoreCase(consolidatedObjectCode)) {
414                    isValid &= false;
415                    putFieldError(getAcctLineErrorPrefix(line, index) + EndowPropertyConstants.ENDOWMENT_ACCOUNTING_LINE_OBJECT_CD, EndowKeyConstants.EndowmentTransactionDocumentConstants.ERROR_ACCT_LINE_OBJECT_CODE_NOT_ASSET_LIABILITY_OR_FUND_BAL);
416                }
417            }
418    
419            return isValid;
420        }
421    
422        /**
423         * Validates that Object codes belonging to the object types of Expense not Expenditure and Income not Cash may not be used on a
424         * Transfer of Funds document.
425         * 
426         * @param line
427         * @param index
428         * @return true if valid, false otherwise
429         */
430        protected boolean validateObjectCodeType(EndowmentAccountingLine line, int index) {
431            boolean isValid = true;
432    
433            String financialObjectCode = line.getFinancialObjectCode();
434            String chartOfAccountsCode = line.getChartOfAccountsCode();
435    
436            ObjectCode objectCode = SpringContext.getBean(ObjectCodeService.class).getByPrimaryIdForCurrentYear(chartOfAccountsCode, financialObjectCode);
437            String objectType = objectCode.getFinancialObjectTypeCode();
438    
439            if (StringUtils.isNotBlank(objectType)) {
440    
441                if (EndowConstants.ObjectTypeCode.EXPENSE_NOT_EXPENDITURE.equalsIgnoreCase(objectType) || EndowConstants.ObjectTypeCode.INCOME_NOT_CASH.equalsIgnoreCase(objectType)) {
442                    isValid &= false;
443                    putFieldError(getAcctLineErrorPrefix(line, index) + EndowPropertyConstants.ENDOWMENT_ACCOUNTING_LINE_OBJECT_CD, EndowKeyConstants.EndowmentTransactionDocumentConstants.ERROR_ACCT_LINE_OBJECT_TYPE_NOT_VALID);
444                }
445            }
446    
447            return isValid;
448        }
449    
450        /**
451         * Validates that if the sub account number is not empty it exists in the DB and is active.
452         * 
453         * @param line
454         * @param index
455         * @return true if valid, false otherwise
456         */
457        protected boolean validateSubAccountNumber(EndowmentAccountingLine line, int index) {
458            boolean isValid = true;
459    
460            DataDictionary dd = SpringContext.getBean(DataDictionaryService.class).getDataDictionary();
461            String label = dd.getBusinessObjectEntry(SubAccount.class.getName()).getAttributeDefinition(KFSConstants.SUB_ACCOUNT_NUMBER_PROPERTY_NAME).getShortLabel();
462    
463            // sub object is not required
464            if (StringUtils.isNotBlank(line.getSubAccountNumber())) {
465                line.refreshReferenceObject("subAccount");
466                SubAccount subAccount = line.getSubAccount();
467    
468                // make sure it exists
469                if (ObjectUtils.isNull(subAccount)) {
470                    putFieldError(getAcctLineErrorPrefix(line, index) + EndowPropertyConstants.ENDOWMENT_ACCOUNTING_LINE_SUBACCT_NBR, KFSKeyConstants.ERROR_EXISTENCE, label);
471                    return false;
472                }
473    
474                // check active flag
475                if (!subAccount.isActive()) {
476                    putFieldError(getAcctLineErrorPrefix(line, index) + EndowPropertyConstants.ENDOWMENT_ACCOUNTING_LINE_SUBACCT_NBR, KFSKeyConstants.ERROR_INACTIVE, label);
477                    return false;
478                }
479            }
480    
481            return isValid;
482        }
483    
484        /**
485         * Validates that if the sub object code is not empty it exists in the DB and is active.
486         * 
487         * @param line
488         * @param index
489         * @return true if valid, false otherwise
490         */
491        protected boolean validateSubObjectCode(EndowmentAccountingLine line, int index) {
492            boolean isValid = true;
493    
494            DataDictionary dd = SpringContext.getBean(DataDictionaryService.class).getDataDictionary();
495            String label = dd.getBusinessObjectEntry(SubObjectCode.class.getName()).getAttributeDefinition(KFSConstants.FINANCIAL_SUB_OBJECT_CODE_PROPERTY_NAME).getShortLabel();
496    
497            // sub object is not required
498            if (StringUtils.isNotBlank(line.getFinancialSubObjectCode())) {
499                line.refreshReferenceObject("subObjectCode");
500                SubObjectCode subObjectCode = line.getSubObjectCode();
501    
502                // make sure it exists
503                if (ObjectUtils.isNull(subObjectCode)) {
504                    putFieldError(getAcctLineErrorPrefix(line, index) + EndowPropertyConstants.ENDOWMENT_ACCOUNTING_LINE_SUBOBJ_CD, KFSKeyConstants.ERROR_EXISTENCE, label);
505                    return false;
506                }
507    
508                // check active flag
509                if (!subObjectCode.isActive()) {
510                    putFieldError(getAcctLineErrorPrefix(line, index) + EndowPropertyConstants.ENDOWMENT_ACCOUNTING_LINE_SUBOBJ_CD, KFSKeyConstants.ERROR_INACTIVE, label);
511                    return false;
512                }
513            }
514    
515            return isValid;
516        }
517    
518        /**
519         * Validates that if the project code is not empty it exists in the DB and is active.
520         * 
521         * @param line
522         * @param index
523         * @return true if valid, false otherwise
524         */
525        protected boolean validateProjectCode(EndowmentAccountingLine line, int index) {
526            boolean isValid = true;
527    
528            DataDictionary dd = SpringContext.getBean(DataDictionaryService.class).getDataDictionary();
529            String label = dd.getBusinessObjectEntry(ProjectCode.class.getName()).getAttributeDefinition(KFSPropertyConstants.CODE).getShortLabel();
530    
531            // sub object is not required
532            if (StringUtils.isNotBlank(line.getProjectCode())) {
533                line.refreshReferenceObject("project");
534                ProjectCode project = line.getProject();
535    
536                // make sure it exists
537                if (ObjectUtils.isNull(project)) {
538                    putFieldError(getAcctLineErrorPrefix(line, index) + EndowPropertyConstants.ENDOWMENT_ACCOUNTING_LINE_PROJECT_CD, KFSKeyConstants.ERROR_EXISTENCE, label);
539                    return false;
540                }
541    
542                // check active flag
543                if (!project.isActive()) {
544                    putFieldError(getAcctLineErrorPrefix(line, index) + EndowPropertyConstants.ENDOWMENT_ACCOUNTING_LINE_PROJECT_CD, KFSKeyConstants.ERROR_INACTIVE, label);
545                    return false;
546                }
547            }
548    
549            return isValid;
550        }
551    
552        /**
553         * Validates that the document has at least one accounting line.
554         * 
555         * @param document
556         * @param isSource
557         * @return true if valid, false otherwise
558         */
559        protected boolean validateAccountingLinesSizeGreaterThanZero(EndowmentAccountingLinesDocument document, boolean isSource) {
560            boolean isValid = true;
561            if (isSource) {
562                isValid &= (document.getSourceAccountingLines().size() > 0);
563            }
564            else {
565                isValid &= (document.getTargetAccountingLines().size() > 0);
566            }
567    
568            if (!isValid) {
569                putFieldError(EndowConstants.ACCOUNTING_LINE_ERRORS, EndowKeyConstants.EndowmentTransactionDocumentConstants.ERROR_ACCT_LINE_COUNT_INSUFFICIENT);
570            }
571            return isValid;
572        }
573    
574        /**
575         * @see org.kuali.kfs.module.endow.document.validation.impl.EndowmentTransactionLinesDocumentBaseRules#processCustomRouteDocumentBusinessRules(org.kuali.rice.kns.document.Document)
576         */
577        @Override
578        protected boolean processCustomRouteDocumentBusinessRules(Document document) {
579            boolean isValid = super.processCustomRouteDocumentBusinessRules(document);
580    
581            EndowmentAccountingLinesDocumentBase endowmentAccountingLinesDocumentBase = null;
582    
583            if (isValid) {
584                endowmentAccountingLinesDocumentBase = (EndowmentAccountingLinesDocumentBase) document;
585    
586                // check that the document is not out of balance
587                isValid &= validateGLTotalAmountMatchesKEMTotalAmount(endowmentAccountingLinesDocumentBase);
588    
589                // validate source Accounting lines
590                if (endowmentAccountingLinesDocumentBase.getSourceAccountingLines() != null) {
591                    for (int i = 0; i < endowmentAccountingLinesDocumentBase.getSourceAccountingLines().size(); i++) {
592                        EndowmentAccountingLine accountingLine = endowmentAccountingLinesDocumentBase.getSourceAccountingLines().get(i);
593                        isValid &= validateAccountingLine(endowmentAccountingLinesDocumentBase, accountingLine, i);
594                    }
595                }
596    
597                // validate target Accounting lines
598                if (endowmentAccountingLinesDocumentBase.getTargetAccountingLines() != null) {
599                    for (int i = 0; i < endowmentAccountingLinesDocumentBase.getTargetAccountingLines().size(); i++) {
600                        EndowmentAccountingLine accountingLine = endowmentAccountingLinesDocumentBase.getTargetAccountingLines().get(i);
601                        isValid &= validateAccountingLine(endowmentAccountingLinesDocumentBase, accountingLine, i);
602                    }
603                }
604    
605            }
606    
607            return isValid;
608        }
609    
610    
611        /**
612         * Validates that the total amount in the FROM section equals the total amount in the To section.
613         * 
614         * @param endowmentAccountingLinesDocumentBase
615         * @return true if valid, false otherwise
616         */
617        protected boolean validateGLTotalAmountMatchesKEMTotalAmount(EndowmentAccountingLinesDocumentBase endowmentAccountingLinesDocumentBase) {
618            boolean isValid = true;
619    
620            KualiDecimal glTotalAmount = endowmentAccountingLinesDocumentBase.getTotalAccountingLinesAmount();
621            KualiDecimal kemTotalAmount = endowmentAccountingLinesDocumentBase.getTotalDollarAmount();
622    
623            if (!glTotalAmount.equals(kemTotalAmount)) {
624                isValid = false;
625                GlobalVariables.getMessageMap().putError(EndowConstants.TRANSACTION_LINE_ERRORS, KFSKeyConstants.ERROR_DOCUMENT_BALANCE);
626            }
627    
628            return isValid;
629        }
630    }