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 java.sql.Date;
019    import java.util.ArrayList;
020    import java.util.HashMap;
021    import java.util.List;
022    import java.util.Map;
023    
024    import org.apache.commons.lang.StringUtils;
025    import org.apache.log4j.Logger;
026    import org.kuali.kfs.module.endow.EndowConstants;
027    import org.kuali.kfs.module.endow.EndowKeyConstants;
028    import org.kuali.kfs.module.endow.EndowParameterKeyConstants;
029    import org.kuali.kfs.module.endow.EndowPropertyConstants;
030    import org.kuali.kfs.module.endow.businessobject.CloseCode;
031    import org.kuali.kfs.module.endow.businessobject.KEMID;
032    import org.kuali.kfs.module.endow.businessobject.KemidAgreement;
033    import org.kuali.kfs.module.endow.businessobject.KemidAuthorizations;
034    import org.kuali.kfs.module.endow.businessobject.KemidBenefittingOrganization;
035    import org.kuali.kfs.module.endow.businessobject.KemidCombineDonorStatement;
036    import org.kuali.kfs.module.endow.businessobject.KemidDonorStatement;
037    import org.kuali.kfs.module.endow.businessobject.KemidFee;
038    import org.kuali.kfs.module.endow.businessobject.KemidGeneralLedgerAccount;
039    import org.kuali.kfs.module.endow.businessobject.KemidPayoutInstruction;
040    import org.kuali.kfs.module.endow.businessobject.KemidReportGroup;
041    import org.kuali.kfs.module.endow.businessobject.KemidSourceOfFunds;
042    import org.kuali.kfs.module.endow.businessobject.KemidSpecialInstruction;
043    import org.kuali.kfs.module.endow.businessobject.KemidUseCriteria;
044    import org.kuali.kfs.module.endow.document.service.KemidCurrentCashService;
045    import org.kuali.kfs.module.endow.document.service.KemidHoldingTaxLotOpenRecordsService;
046    import org.kuali.kfs.module.endow.document.service.ValidateDateBasedOnFrequencyCodeService;
047    import org.kuali.kfs.sys.KFSConstants;
048    import org.kuali.kfs.sys.KFSKeyConstants;
049    import org.kuali.kfs.sys.context.SpringContext;
050    import org.kuali.rice.kns.bo.PersistableBusinessObject;
051    import org.kuali.rice.kns.document.Document;
052    import org.kuali.rice.kns.document.MaintenanceDocument;
053    import org.kuali.rice.kns.maintenance.rules.MaintenanceDocumentRuleBase;
054    import org.kuali.rice.kns.service.BusinessObjectService;
055    import org.kuali.rice.kns.service.DateTimeService;
056    import org.kuali.rice.kns.service.ParameterService;
057    import org.kuali.rice.kns.util.GlobalVariables;
058    import org.kuali.rice.kns.util.KualiDecimal;
059    import org.kuali.rice.kns.util.MessageMap;
060    import org.kuali.rice.kns.util.ObjectUtils;
061    
062    /**
063     * This KEMIDRule class implements the Business rules associated with the KEMID.
064     */
065    public class KEMIDRule extends MaintenanceDocumentRuleBase {
066    
067        protected static Logger LOG = org.apache.log4j.Logger.getLogger(KEMIDRule.class);
068        private KEMID newKemid;
069        private KEMID oldKemid;
070    
071        /**
072         * This method initializes the old and new kemid.
073         * 
074         * @param document
075         */
076        private void initializeAttributes(MaintenanceDocument document) {
077            if (newKemid == null) {
078                newKemid = (KEMID) document.getNewMaintainableObject().getBusinessObject();
079            }
080            if (oldKemid == null) {
081                oldKemid = (KEMID) document.getOldMaintainableObject().getBusinessObject();
082            }
083        }
084    
085        /**
086         * @see org.kuali.rice.kns.maintenance.rules.MaintenanceDocumentRuleBase#processCustomRouteDocumentBusinessRules(org.kuali.rice.kns.document.MaintenanceDocument)
087         */
088        @Override
089        protected boolean processCustomRouteDocumentBusinessRules(MaintenanceDocument document) {
090    
091            boolean isValid = true;
092            isValid &= super.processCustomRouteDocumentBusinessRules(document);
093            MessageMap errorMap = GlobalVariables.getMessageMap();
094            isValid &= errorMap.hasNoErrors();
095    
096            if (isValid) {
097    
098                initializeAttributes(document);
099                isValid &= checkCloseCode();
100                isValid &= checkIfKemidHasCurrentCashOpenRecordsIfClosed();
101                isValid &= checkIfKemidHasHoldingTaxLotOpenRecordsIfClosed();
102                isValid &= validateIncomeRestrictionCode(document);
103                isValid &= validateAgreements();
104                isValid &= validateUseTransactionRestrictionFromAgreement();
105                isValid &= validateSourceOfFunds();
106                isValid &= validateBenefittingOrgs();
107                isValid &= validateGeneralLedgerAccounts();
108                isValid &= validateKemidAuthorizations();
109                isValid &= validatePayoutInstructions();
110                isValid &= validateKemidDonorStatements();
111                isValid &= validateFees();
112            }
113    
114            return isValid;
115        }
116    
117        /**
118         * @see org.kuali.rice.kns.maintenance.rules.MaintenanceDocumentRuleBase#processCustomAddCollectionLineBusinessRules(org.kuali.rice.kns.document.MaintenanceDocument,
119         *      java.lang.String, org.kuali.rice.kns.bo.PersistableBusinessObject)
120         */
121        @Override
122        public boolean processCustomAddCollectionLineBusinessRules(MaintenanceDocument document, String collectionName, PersistableBusinessObject bo) {
123            boolean success = true;
124    
125            success &= super.processCustomAddCollectionLineBusinessRules(document, collectionName, bo);
126            MessageMap errorMap = GlobalVariables.getMessageMap();
127            success &= errorMap.hasNoErrors();
128    
129            if (success) {
130    
131                initializeAttributes(document);
132    
133                if (collectionName.equalsIgnoreCase(EndowPropertyConstants.KEMID_DONOR_STATEMENTS_TAB)) {
134                    KemidDonorStatement donorStatement = (KemidDonorStatement) bo;
135    
136                    if (!validCombineWithDonorId(donorStatement)) {
137                        success &= false;
138                    }
139                }
140    
141                if (bo instanceof KemidAgreement) {
142                    KemidAgreement agreement = (KemidAgreement) bo;
143                    success &= checkAgreement(agreement);
144    
145                }
146    
147                if (bo instanceof KemidSourceOfFunds) {
148                    KemidSourceOfFunds sourceOfFunds = (KemidSourceOfFunds) bo;
149                    success &= checkSourceOfFunds(sourceOfFunds);
150                }
151    
152                if (bo instanceof KemidBenefittingOrganization) {
153                    KemidBenefittingOrganization benefittingOrg = (KemidBenefittingOrganization) bo;
154                    success &= checkBenefittingOrg(benefittingOrg);
155                }
156    
157                if (bo instanceof KemidGeneralLedgerAccount) {
158                    KemidGeneralLedgerAccount generalLedgerAccount = (KemidGeneralLedgerAccount) bo;
159                    success &= checkGeneralLedgerAccount(generalLedgerAccount);
160    
161                    List<KemidGeneralLedgerAccount> generalLedgerAccounts = new ArrayList<KemidGeneralLedgerAccount>();
162                    generalLedgerAccounts.addAll(newKemid.getKemidGeneralLedgerAccounts());
163                    generalLedgerAccounts.add(generalLedgerAccount);
164    
165                    success &= validateIncomePrincipalGLAccounts(generalLedgerAccounts);
166                }
167    
168                if (bo instanceof KemidAuthorizations) {
169                    KemidAuthorizations authorization = (KemidAuthorizations) bo;
170                    success &= checkAuthorization(authorization, -1);
171                }
172    
173                if (bo instanceof KemidPayoutInstruction) {
174                    KemidPayoutInstruction payoutInstruction = (KemidPayoutInstruction) bo;
175                    success &= checkPayoutInstruction(payoutInstruction, -1);
176                }
177    
178                if (bo instanceof KemidUseCriteria) {
179                    KemidUseCriteria useCriteria = (KemidUseCriteria) bo;
180                    success &= checkUseCriteria(useCriteria);
181                }
182    
183                if (bo instanceof KemidSpecialInstruction) {
184                    KemidSpecialInstruction specialInstruction = (KemidSpecialInstruction) bo;
185                    success &= checkSpecialInstruction(specialInstruction);
186                }
187    
188                if (bo instanceof KemidReportGroup) {
189                    KemidReportGroup reportGroup = (KemidReportGroup) bo;
190                    success &= checkReportGroup(reportGroup);
191                }
192    
193                if (bo instanceof KemidDonorStatement) {
194                    KemidDonorStatement donorStatement = (KemidDonorStatement) bo;
195                    success &= checkDonorStatement(donorStatement);
196                }
197    
198                if (bo instanceof KemidCombineDonorStatement) {
199                    KemidCombineDonorStatement combineDonorStatement = (KemidCombineDonorStatement) bo;
200                    success &= checkCombineDonorStatement(combineDonorStatement);
201                }
202    
203                if (bo instanceof KemidFee) {
204                    KemidFee fee = (KemidFee) bo;
205                    success &= checkFee(fee);
206                    success &= validateFeePercentageTotal(fee, -1);
207                    success &= validatePercentageOfFeeChargedToPrincipal(fee, -1);
208                    success &= validateKemidFeeStartDate(fee, -1);
209                }
210            }
211            return success;
212        }
213    
214        /**
215         * This method will validate if income restriction code is "P" (Permanently Restricted) Rule: Type_inc_restr_cd cannot be P
216         * (Permanently Restricted).
217         * 
218         * @param document
219         * @return true if Income Restriction code is not "P" else return false
220         */
221        private boolean validateIncomeRestrictionCode(Document document) {
222            boolean rulesPassed = true;
223    
224            MaintenanceDocument maintenanceDocument = (MaintenanceDocument) document;
225            KEMID kemid = (KEMID) maintenanceDocument.getNewMaintainableObject().getBusinessObject();
226    
227            if (EndowConstants.TypeRestrictionPresetValueCodes.PERMANENT_TYPE_RESTRICTION_CODE.equalsIgnoreCase(kemid.getIncomeRestrictionCode())) {
228                GlobalVariables.getMessageMap().putError(EndowPropertyConstants.TYPE_INC_RESTR_CD, EndowKeyConstants.TypeRestrictionCodeConstants.ERROR_PERMANENT_INDICATOR_CANNOT_BE_USED_FOR_TYPE_RESTRICTION_CODE);
229                return false;
230    
231            }
232            return rulesPassed;
233        }
234    
235    
236        /**
237         * Checks that the agreement type and agreement status exist.
238         * 
239         * @param agreement
240         * @return true if they exist, false otherwise
241         */
242        private boolean checkAgreement(KemidAgreement agreement) {
243            boolean success = true;
244            int originalErrorCount = GlobalVariables.getMessageMap().getErrorCount();
245            String errorPathPrefix = KFSConstants.MAINTENANCE_ADD_PREFIX + EndowPropertyConstants.KEMID_AGREEMENTS_TAB + ".";
246    
247            // check that the agreement type exists
248            if (StringUtils.isNotBlank(agreement.getAgreementTypeCode())) {
249                agreement.refreshReferenceObject(EndowPropertyConstants.KEMID_AGRMNT_TYPE);
250    
251                if (ObjectUtils.isNull(agreement.getAgreementType())) {
252                    String label = this.getDataDictionaryService().getAttributeLabel(KemidAgreement.class, EndowPropertyConstants.KEMID_AGRMNT_TYP_CD);
253                    String message = label + "(" + agreement.getAgreementTypeCode() + ")";
254    
255                    putFieldError(errorPathPrefix + EndowPropertyConstants.KEMID_AGRMNT_TYP_CD, KFSKeyConstants.ERROR_EXISTENCE, message);
256                }
257            }
258    
259            // check that the agreement status exists
260            if (StringUtils.isNotBlank(agreement.getAgreementStatusCode())) {
261                agreement.refreshReferenceObject(EndowPropertyConstants.KEMID_AGRMNT_STATUS);
262    
263                if (ObjectUtils.isNull(agreement.getAgreementType())) {
264                    String label = this.getDataDictionaryService().getAttributeLabel(KemidAgreement.class, EndowPropertyConstants.KEMID_AGRMNT_STAT_CD);
265                    String message = label + "(" + agreement.getAgreementStatusCode() + ")";
266    
267                    putFieldError(errorPathPrefix + EndowPropertyConstants.KEMID_AGRMNT_STAT_CD, KFSKeyConstants.ERROR_EXISTENCE, message);
268                }
269            }
270    
271            success &= GlobalVariables.getMessageMap().getErrorCount() == originalErrorCount;
272    
273            return success;
274    
275        }
276    
277        /**
278         * Checks that the fund source and opened from kemid exist.
279         * 
280         * @param sourceOfFunds
281         * @return true if they exist, false otherwise
282         */
283        private boolean checkSourceOfFunds(KemidSourceOfFunds sourceOfFunds) {
284            boolean success = true;
285            int originalErrorCount = GlobalVariables.getMessageMap().getErrorCount();
286            String errorPathPrefix = KFSConstants.MAINTENANCE_ADD_PREFIX + EndowPropertyConstants.KEMID_SOURCE_OF_FUNDS_TAB + ".";
287    
288            // check that the fund source exists
289            if (StringUtils.isNotBlank(sourceOfFunds.getFundSourceCode())) {
290                sourceOfFunds.refreshReferenceObject(EndowPropertyConstants.KEMID_FND_SRC);
291    
292                if (ObjectUtils.isNull(sourceOfFunds.getFundSource())) {
293                    String label = this.getDataDictionaryService().getAttributeLabel(KemidAgreement.class, EndowPropertyConstants.KEMID_FND_SRC_CD);
294                    String message = label + "(" + sourceOfFunds.getFundSourceCode() + ")";
295    
296                    putFieldError(errorPathPrefix + EndowPropertyConstants.KEMID_FND_SRC_CD, KFSKeyConstants.ERROR_EXISTENCE, message);
297                }
298            }
299    
300            // check that the opened from kemid exists
301            if (StringUtils.isNotBlank(sourceOfFunds.getOpenedFromKemid())) {
302                sourceOfFunds.refreshReferenceObject(EndowPropertyConstants.KEMID_FND_SRC_OPND_FROM_KEMID_OBJ_REF);
303    
304                if (ObjectUtils.isNull(sourceOfFunds.getOpenedFromKemidObjRef())) {
305                    String label = this.getDataDictionaryService().getAttributeLabel(KemidSourceOfFunds.class, EndowPropertyConstants.KEMID_FND_SRC_OPND_FROM_KEMID);
306                    String message = label + "(" + sourceOfFunds.getOpenedFromKemid() + ")";
307    
308                    putFieldError(errorPathPrefix + EndowPropertyConstants.KEMID_FND_SRC_OPND_FROM_KEMID, KFSKeyConstants.ERROR_EXISTENCE, message);
309                }
310            }
311    
312            success &= GlobalVariables.getMessageMap().getErrorCount() == originalErrorCount;
313    
314            return success;
315    
316        }
317    
318        /**
319         * Checks that the pay income to kemid exists.
320         * 
321         * @param payoutInstruction
322         * @return true if it exists, false otherwise
323         */
324        private boolean checkBenefittingOrg(KemidBenefittingOrganization benefittingOrg) {
325            boolean success = true;
326            int originalErrorCount = GlobalVariables.getMessageMap().getErrorCount();
327            String errorPathPrefix = KFSConstants.MAINTENANCE_ADD_PREFIX + EndowPropertyConstants.KEMID_BENEFITTING_ORGS_TAB + ".";
328    
329            // check that the organization exists
330            if (StringUtils.isNotBlank(benefittingOrg.getBenefittingOrgCode())) {
331                benefittingOrg.refreshReferenceObject(EndowPropertyConstants.KEMID_BENE_ORG);
332    
333                if (ObjectUtils.isNull(benefittingOrg.getOrganization())) {
334                    String label = this.getDataDictionaryService().getAttributeLabel(KemidBenefittingOrganization.class, EndowPropertyConstants.KEMID_BENE_ORG_CD);
335                    String message = label + "(" + benefittingOrg.getBenefittingOrgCode() + ")";
336    
337                    putFieldError(errorPathPrefix + EndowPropertyConstants.KEMID_BENE_ORG_CD, KFSKeyConstants.ERROR_EXISTENCE, message);
338                }
339            }
340    
341            // check that the chart exists
342            if (StringUtils.isNotBlank(benefittingOrg.getBenefittingChartCode())) {
343                benefittingOrg.refreshReferenceObject(EndowPropertyConstants.KEMID_BENE_CHRT);
344    
345                if (ObjectUtils.isNull(benefittingOrg.getChart())) {
346                    String label = this.getDataDictionaryService().getAttributeLabel(KemidBenefittingOrganization.class, EndowPropertyConstants.KEMID_BENE_CHRT_CD);
347                    String message = label + "(" + benefittingOrg.getBenefittingChartCode() + ")";
348    
349                    putFieldError(errorPathPrefix + EndowPropertyConstants.KEMID_BENE_CHRT_CD, KFSKeyConstants.ERROR_EXISTENCE, message);
350                }
351            }
352    
353            success &= GlobalVariables.getMessageMap().getErrorCount() == originalErrorCount;
354    
355            return success;
356    
357        }
358    
359        /**
360         * Checks that the generalLedgerAccount chart and account status exist.
361         * 
362         * @param generalLedgerAccount
363         * @return true if they exist, false otherwise
364         */
365        private boolean checkGeneralLedgerAccount(KemidGeneralLedgerAccount generalLedgerAccount) {
366            boolean success = true;
367            int originalErrorCount = GlobalVariables.getMessageMap().getErrorCount();
368            String errorPathPrefix = KFSConstants.MAINTENANCE_ADD_PREFIX + EndowPropertyConstants.KEMID_GENERAL_LEDGER_ACCOUNTS_TAB + ".";
369    
370            // check that the chart exists
371            if (StringUtils.isNotBlank(generalLedgerAccount.getChartCode())) {
372                generalLedgerAccount.refreshReferenceObject(EndowPropertyConstants.KEMID_GL_ACCOUNT_CHART);
373    
374                if (ObjectUtils.isNull(generalLedgerAccount.getChart())) {
375                    String label = this.getDataDictionaryService().getAttributeLabel(KemidGeneralLedgerAccount.class, EndowPropertyConstants.KEMID_GL_ACCOUNT_CHART_CD);
376                    String message = label + "(" + generalLedgerAccount.getChartCode() + ")";
377    
378                    putFieldError(errorPathPrefix + EndowPropertyConstants.KEMID_GL_ACCOUNT_CHART_CD, KFSKeyConstants.ERROR_EXISTENCE, message);
379                }
380            }
381    
382            // check that the account exists
383            if (StringUtils.isNotBlank(generalLedgerAccount.getAccountNumber())) {
384                generalLedgerAccount.refreshReferenceObject(EndowPropertyConstants.KEMID_GL_ACCOUNT);
385    
386                if (ObjectUtils.isNull(generalLedgerAccount.getAccount())) {
387                    String label = this.getDataDictionaryService().getAttributeLabel(KemidGeneralLedgerAccount.class, EndowPropertyConstants.KEMID_GL_ACCOUNT_NBR);
388                    String message = label + "(" + generalLedgerAccount.getAccountNumber() + ")";
389    
390                    putFieldError(errorPathPrefix + EndowPropertyConstants.KEMID_GL_ACCOUNT_NBR, KFSKeyConstants.ERROR_EXISTENCE, message);
391                }
392            }
393    
394            success &= GlobalVariables.getMessageMap().getErrorCount() == originalErrorCount;
395    
396            return success;
397    
398        }
399    
400        /**
401         * Checks that the given authorization is valid.
402         * 
403         * @param authorization
404         * @param index
405         * @return true if valid, false otherwise
406         */
407        private boolean checkAuthorization(KemidAuthorizations authorization, int index) {
408            boolean success = true;
409    
410            if (authorization.isActive()) {
411                success &= validateRoleInKFSEndowNamespace(authorization, index);
412            }
413    
414            return success;
415        }
416    
417        /**
418         * Checks that the pay income to kemid exists.
419         * 
420         * @param payoutInstruction the payout instruction to be validated
421         * @param index -1 if cehcking the add payout instruction, the index of the payout instruction in the list of added payout
422         *        instruction otherwise
423         * @return true if it exists, false otherwise
424         */
425        private boolean checkPayoutInstruction(KemidPayoutInstruction payoutInstruction, int index) {
426            boolean success = true;
427            int originalErrorCount = GlobalVariables.getMessageMap().getErrorCount();
428    
429            // check that the pay income to kemid exists
430            if (StringUtils.isNotBlank(payoutInstruction.getPayIncomeToKemid()) && !payoutInstruction.getPayIncomeToKemid().equalsIgnoreCase(newKemid.getKemid())) {
431                payoutInstruction.refreshReferenceObject(EndowPropertyConstants.KEMID_PAY_INC_TO_KEMID_OBJ_REF);
432    
433                if (ObjectUtils.isNull(payoutInstruction.getPayIncomeToKemidObjRef())) {
434                    String label = this.getDataDictionaryService().getAttributeLabel(KemidPayoutInstruction.class, EndowPropertyConstants.KEMID_PAY_INC_TO_KEMID);
435                    String message = label + "(" + payoutInstruction.getPayIncomeToKemid() + ")";
436    
437                    if (index == -1) {
438                        putFieldError(KFSConstants.MAINTENANCE_ADD_PREFIX + EndowPropertyConstants.KEMID_PAY_INSTRUCTIONS_TAB + "." + EndowPropertyConstants.KEMID_PAY_INC_TO_KEMID, KFSKeyConstants.ERROR_EXISTENCE, message);
439                    }
440                    else {
441                        putFieldError(EndowPropertyConstants.KEMID_PAY_INSTRUCTIONS_TAB + "[" + index + "]" + "." + EndowPropertyConstants.KEMID_PAY_INC_TO_KEMID, KFSKeyConstants.ERROR_EXISTENCE, message);
442                    }
443                }
444            }
445    
446            // check that start date is prior to end date
447            Date startDate = payoutInstruction.getStartDate();
448            Date endDate = payoutInstruction.getEndDate();
449    
450            if (startDate != null && endDate != null) {
451                if (startDate.after(endDate)) {
452                    if (index == -1) {
453                        putFieldError(KFSConstants.MAINTENANCE_ADD_PREFIX + EndowPropertyConstants.KEMID_PAY_INSTRUCTIONS_TAB + "." + EndowPropertyConstants.KEMID_PAY_INC_START_DATE, EndowKeyConstants.KEMIDConstants.ERROR_KEMID_PAYOUT_INSTRUCTION_START_DATE_SHOULD_BE_PRIOR_TO_END_DATE);
454                    }
455                    else {
456                        putFieldError(EndowPropertyConstants.KEMID_PAY_INSTRUCTIONS_TAB + "[" + index + "]" + "." + EndowPropertyConstants.KEMID_PAY_INC_START_DATE, EndowKeyConstants.KEMIDConstants.ERROR_KEMID_PAYOUT_INSTRUCTION_START_DATE_SHOULD_BE_PRIOR_TO_END_DATE);
457                    }
458                }
459            }
460    
461            success &= GlobalVariables.getMessageMap().getErrorCount() == originalErrorCount;
462    
463            return success;
464    
465        }
466    
467        /**
468         * Checks that the use criteria exists.
469         * 
470         * @param useCriteria
471         * @return true if it exists, false otherwise
472         */
473        private boolean checkUseCriteria(KemidUseCriteria useCriteria) {
474            boolean success = true;
475            int originalErrorCount = GlobalVariables.getMessageMap().getErrorCount();
476            String errorPathPrefix = KFSConstants.MAINTENANCE_ADD_PREFIX + EndowPropertyConstants.KEMID_USE_CRITERIA_TAB + ".";
477    
478            // check that the use criteria exists
479            if (StringUtils.isNotBlank(useCriteria.getUseCriteriaCode())) {
480                useCriteria.refreshReferenceObject(EndowPropertyConstants.KEMID_USE_CRIT);
481    
482                if (ObjectUtils.isNull(useCriteria.getUseCriteria())) {
483                    String label = this.getDataDictionaryService().getAttributeLabel(KemidUseCriteria.class, EndowPropertyConstants.KEMID_USE_CRIT_CD);
484                    String message = label + "(" + useCriteria.getUseCriteriaCode() + ")";
485    
486                    putFieldError(errorPathPrefix + EndowPropertyConstants.KEMID_USE_CRIT_CD, KFSKeyConstants.ERROR_EXISTENCE, message);
487                }
488            }
489    
490            success &= GlobalVariables.getMessageMap().getErrorCount() == originalErrorCount;
491    
492            return success;
493    
494        }
495    
496        /**
497         * Checks that the agreement special instruction exists.
498         * 
499         * @param specialInstruction
500         * @return true if it exists, false otherwise
501         */
502        private boolean checkSpecialInstruction(KemidSpecialInstruction specialInstruction) {
503            boolean success = true;
504            int originalErrorCount = GlobalVariables.getMessageMap().getErrorCount();
505            String errorPathPrefix = KFSConstants.MAINTENANCE_ADD_PREFIX + EndowPropertyConstants.KEMID_SPECIAL_INSTRUCTIONS_TAB + ".";
506    
507            // check that the agreement special instruction exists
508            if (StringUtils.isNotBlank(specialInstruction.getAgreementSpecialInstructionCode())) {
509                specialInstruction.refreshReferenceObject(EndowPropertyConstants.KEMID_SPEC_INSTR);
510    
511                if (ObjectUtils.isNull(specialInstruction.getAgreementSpecialInstruction())) {
512                    String label = this.getDataDictionaryService().getAttributeLabel(KemidSpecialInstruction.class, EndowPropertyConstants.KEMID_SPEC_INSTR_CD);
513                    String message = label + "(" + specialInstruction.getAgreementSpecialInstructionCode() + ")";
514    
515                    putFieldError(errorPathPrefix + EndowPropertyConstants.KEMID_SPEC_INSTR_CD, KFSKeyConstants.ERROR_EXISTENCE, message);
516                }
517            }
518    
519            success &= GlobalVariables.getMessageMap().getErrorCount() == originalErrorCount;
520    
521            return success;
522    
523        }
524    
525        /**
526         * Checks that the fee method, charge fee to kemid exist.
527         * 
528         * @param fee
529         * @return true if it exist, false otherwise
530         */
531        private boolean checkFee(KemidFee fee) {
532            boolean success = true;
533            int originalErrorCount = GlobalVariables.getMessageMap().getErrorCount();
534            String errorPathPrefix = KFSConstants.MAINTENANCE_ADD_PREFIX + EndowPropertyConstants.KEMID_FEES_TAB + ".";
535    
536            // check that the fee method exists
537            if (StringUtils.isNotBlank(fee.getFeeMethodCode())) {
538                fee.refreshReferenceObject(EndowPropertyConstants.KEMID_FEE_MTHD);
539    
540                if (ObjectUtils.isNull(fee.getFeeMethod())) {
541                    String label = this.getDataDictionaryService().getAttributeLabel(KemidFee.class, EndowPropertyConstants.KEMID_FEE_MTHD_CD);
542                    String message = label + "(" + fee.getFeeMethodCode() + ")";
543    
544                    putFieldError(errorPathPrefix + EndowPropertyConstants.KEMID_FEE_MTHD_CD, KFSKeyConstants.ERROR_EXISTENCE, message);
545                }
546            }
547    
548            // check that charge fee to kemid exists
549            if (StringUtils.isNotBlank(fee.getChargeFeeToKemid())) {
550                fee.refreshReferenceObject(EndowPropertyConstants.KEMID_FEE_CHARGE_FEE_TO_KEMID_OBJ_REF);
551    
552                if (ObjectUtils.isNull(fee.getChargeFeeToKemidObjRef())) {
553                    String label = this.getDataDictionaryService().getAttributeLabel(KemidFee.class, EndowPropertyConstants.KEMID_FEE_CHARGE_FEE_TO_KEMID);
554                    String message = label + "(" + fee.getChargeFeeToKemid() + ")";
555    
556                    putFieldError(errorPathPrefix + EndowPropertyConstants.KEMID_FEE_CHARGE_FEE_TO_KEMID, KFSKeyConstants.ERROR_EXISTENCE, message);
557                }
558            }
559    
560            success &= GlobalVariables.getMessageMap().getErrorCount() == originalErrorCount;
561    
562            return success;
563    
564        }
565    
566        /**
567         * Checks that the combine Group exists.
568         * 
569         * @param reportGroup
570         * @return true if it exists, false otherwise
571         */
572        private boolean checkReportGroup(KemidReportGroup reportGroup) {
573            boolean success = true;
574            int originalErrorCount = GlobalVariables.getMessageMap().getErrorCount();
575            String errorPathPrefix = KFSConstants.MAINTENANCE_ADD_PREFIX + EndowPropertyConstants.KEMID_REPORT_GROUP_TAB + ".";
576    
577            // check that the combine Group exists
578            if (StringUtils.isNotBlank(reportGroup.getCombineGroupCode())) {
579                reportGroup.refreshReferenceObject(EndowPropertyConstants.KEMID_REPORT_GRP);
580    
581                if (ObjectUtils.isNull(reportGroup.getCombineGroup())) {
582                    String label = this.getDataDictionaryService().getAttributeLabel(KemidReportGroup.class, EndowPropertyConstants.KEMID_REPORT_GRP_CD);
583                    String message = label + "(" + reportGroup.getCombineGroupCode() + ")";
584    
585                    putFieldError(errorPathPrefix + EndowPropertyConstants.KEMID_REPORT_GRP_CD, KFSKeyConstants.ERROR_EXISTENCE, message);
586                }
587            }
588    
589            success &= GlobalVariables.getMessageMap().getErrorCount() == originalErrorCount;
590    
591            return success;
592    
593        }
594    
595        /**
596         * Checks that the donor, donor statement, combine with donor and donor label exist.
597         * 
598         * @param donorStatement
599         * @return true if they exist, false otherwise
600         */
601        private boolean checkDonorStatement(KemidDonorStatement donorStatement) {
602            boolean success = true;
603            int originalErrorCount = GlobalVariables.getMessageMap().getErrorCount();
604            String errorPathPrefix = KFSConstants.MAINTENANCE_ADD_PREFIX + EndowPropertyConstants.KEMID_DONOR_STATEMENTS_TAB + ".";
605    
606            // check that the donor exists
607            if (StringUtils.isNotBlank(donorStatement.getDonorId())) {
608                donorStatement.refreshReferenceObject(EndowPropertyConstants.KEMID_DONOR_STATEMENT_DONOR);
609    
610                if (ObjectUtils.isNull(donorStatement.getDonor())) {
611                    String label = this.getDataDictionaryService().getAttributeLabel(KemidDonorStatement.class, EndowPropertyConstants.KEMID_DONOR_STATEMENT_ID);
612                    String message = label + "(" + donorStatement.getDonorId() + ")";
613    
614                    putFieldError(errorPathPrefix + EndowPropertyConstants.KEMID_DONOR_STATEMENT_ID, KFSKeyConstants.ERROR_EXISTENCE, message);
615                }
616            }
617    
618            // check that the donor statement exists
619            if (StringUtils.isNotBlank(donorStatement.getDonorStatementCode())) {
620                donorStatement.refreshReferenceObject(EndowPropertyConstants.KEMID_DONOR_STATEMENT);
621    
622                if (ObjectUtils.isNull(donorStatement.getDonor())) {
623                    String label = this.getDataDictionaryService().getAttributeLabel(KemidDonorStatement.class, EndowPropertyConstants.KEMID_DONOR_STATEMENT_CD);
624                    String message = label + "(" + donorStatement.getDonorStatementCode() + ")";
625    
626                    putFieldError(errorPathPrefix + EndowPropertyConstants.KEMID_DONOR_STATEMENT_CD, KFSKeyConstants.ERROR_EXISTENCE, message);
627                }
628            }
629    
630            // check that the combine with donor exists
631            if (StringUtils.isNotBlank(donorStatement.getCombineWithDonorId())) {
632                donorStatement.refreshReferenceObject(EndowPropertyConstants.KEMID_DONOR_STATEMENT_COMBINE_WITH_DONOR);
633    
634                if (ObjectUtils.isNull(donorStatement.getCombineWithDonor())) {
635                    String label = this.getDataDictionaryService().getAttributeLabel(KemidDonorStatement.class, EndowPropertyConstants.KEMID_DONOR_STATEMENT_COMBINE_WITH_DONOR_ID);
636                    String message = label + "(" + donorStatement.getCombineWithDonorId() + ")";
637    
638                    putFieldError(errorPathPrefix + EndowPropertyConstants.KEMID_DONOR_STATEMENT_COMBINE_WITH_DONOR_ID, KFSKeyConstants.ERROR_EXISTENCE, message);
639                }
640            }
641    
642            // check that the donor label exists
643            if (StringUtils.isNotBlank(donorStatement.getDonorLabel())) {
644                donorStatement.refreshReferenceObject(EndowPropertyConstants.KEMID_DONOR_STATEMENT_DONOR_LABEL_OBJ_REF);
645    
646                if (ObjectUtils.isNull(donorStatement.getDonorLabelObjRef())) {
647                    String label = this.getDataDictionaryService().getAttributeLabel(KemidDonorStatement.class, EndowPropertyConstants.KEMID_DONOR_STATEMENT_DONOR_LABEL);
648                    String message = label + "(" + donorStatement.getDonorLabel() + ")";
649    
650                    putFieldError(errorPathPrefix + EndowPropertyConstants.KEMID_DONOR_STATEMENT_DONOR_LABEL, KFSKeyConstants.ERROR_EXISTENCE, message);
651                }
652            }
653    
654            success &= GlobalVariables.getMessageMap().getErrorCount() == originalErrorCount;
655    
656            return success;
657    
658        }
659    
660        /**
661         * Checks that the combine with kemid exists.
662         * 
663         * @param combineDonorStatement
664         * @return true if it exists, false otherwise
665         */
666        private boolean checkCombineDonorStatement(KemidCombineDonorStatement combineDonorStatement) {
667            boolean success = true;
668            int originalErrorCount = GlobalVariables.getMessageMap().getErrorCount();
669            String errorPathPrefix = KFSConstants.MAINTENANCE_ADD_PREFIX + EndowPropertyConstants.KEMID_COMBINE_DONOR_STATEMENTS_TAB + ".";
670    
671            // check that the combine with kemid exists
672            if (StringUtils.isNotBlank(combineDonorStatement.getCombineWithKemid())) {
673                combineDonorStatement.refreshReferenceObject(EndowPropertyConstants.KEMID_COMBINE_DONOR_STATEMENT_WITH_KEMID_OBJ_REF);
674    
675                if (ObjectUtils.isNull(combineDonorStatement.getCombineWithKemidObjRef())) {
676                    String label = this.getDataDictionaryService().getAttributeLabel(KemidCombineDonorStatement.class, EndowPropertyConstants.KEMID_COMBINE_DONOR_STATEMENT_WITH_KEMID);
677                    String message = label + "(" + combineDonorStatement.getCombineWithKemid() + ")";
678    
679                    putFieldError(errorPathPrefix + EndowPropertyConstants.KEMID_COMBINE_DONOR_STATEMENT_WITH_KEMID, KFSKeyConstants.ERROR_EXISTENCE, message);
680                }
681            }
682    
683            success &= GlobalVariables.getMessageMap().getErrorCount() == originalErrorCount;
684    
685            return success;
686    
687        }
688    
689        /**
690         * Checks that a valid Reason Closed is entered whe the Closed indicator is "Yes".
691         * 
692         * @return true if valid, false otherwise
693         */
694        private boolean checkCloseCode() {
695            boolean valid = true;
696    
697            if (newKemid.isClose()) {
698                String closeCode = newKemid.getCloseCode();
699    
700                Map pkMap = new HashMap();
701                pkMap.put(EndowPropertyConstants.ENDOWCODEBASE_CODE, closeCode);
702                CloseCode reasonClosed = (CloseCode) SpringContext.getBean(BusinessObjectService.class).findByPrimaryKey(CloseCode.class, pkMap);
703    
704                if (ObjectUtils.isNull(reasonClosed)) {
705                    putFieldError(EndowPropertyConstants.KEMID_CLOSE_CODE, EndowKeyConstants.KEMIDConstants.ERROR_INVALID_CLOSED_CODE);
706                    valid = false;
707                }
708            }
709            return valid;
710    
711        }
712    
713        /**
714         * Checks if the kemid has current cash open records in case the closed indicator is "Yes".
715         * 
716         * @return true if it does not have open records, false otherwise
717         */
718        private boolean checkIfKemidHasCurrentCashOpenRecordsIfClosed() {
719            boolean valid = true;
720    
721            if (newKemid.isClose()) {
722                String kemid = newKemid.getKemid();
723                boolean hasOpenRecords = SpringContext.getBean(KemidCurrentCashService.class).hasKemidOpenRecordsInCurrentCash(kemid);
724    
725                valid = !hasOpenRecords;
726    
727                if (!valid) {
728                    putFieldError(EndowPropertyConstants.KEMID_CLOSED_IND, EndowKeyConstants.KEMIDConstants.ERROR_HAS_OPEN_RECORDS_IN_CURRENT_CASH);
729                }
730            }
731            return valid;
732    
733        }
734    
735        /**
736         * Checks if the kemid has holding tax lot open records in case the closed indicator is "Yes".
737         * 
738         * @return true if it does not have open records, false otherwise
739         */
740        private boolean checkIfKemidHasHoldingTaxLotOpenRecordsIfClosed() {
741            boolean valid = true;
742    
743            if (newKemid.isClose()) {
744                String kemid = newKemid.getKemid();
745                boolean hasOpenRecords = SpringContext.getBean(KemidHoldingTaxLotOpenRecordsService.class).hasKemidHoldingTaxLotOpenRecords(kemid);
746    
747                valid = !hasOpenRecords;
748    
749                if (!valid) {
750                    putFieldError(EndowPropertyConstants.KEMID_CLOSED_IND, EndowKeyConstants.KEMIDConstants.ERROR_HAS_OPEN_RECORDS_IN_HOLDING_TAX_LOT);
751                }
752            }
753            return valid;
754    
755        }
756    
757        /**
758         * Checks that the KEMID has at least one ACTIVE Agreement set up.
759         * 
760         * @return true if it has at least one Agreement, false otherwise
761         */
762        private boolean validateAgreements() {
763            boolean valid = true;
764            boolean hasActiveRecord = false;
765    
766            if (newKemid.getKemidAgreements() == null || newKemid.getKemidAgreements().size() == 0) {
767                putFieldError(EndowPropertyConstants.KEMID_AGREEMENTS_TAB, EndowKeyConstants.KEMIDConstants.ERROR_KEMID_MUST_HAVE_AT_LEAST_ONE_ACTIVE_AGREEMENT);
768                valid = false;
769            }
770            else {
771                // Make sure that the KEMID has at least one ACTIVE Agreement
772                for (KemidAgreement kemidAgreement : newKemid.getKemidAgreements()) {
773                    if (kemidAgreement.isActive()) {
774                        hasActiveRecord = true;
775                        break;
776                    }
777                }
778    
779            }
780            if (!hasActiveRecord) {
781                putFieldError(EndowPropertyConstants.KEMID_AGREEMENTS_TAB, EndowKeyConstants.KEMIDConstants.ERROR_KEMID_MUST_HAVE_AT_LEAST_ONE_ACTIVE_AGREEMENT);
782                valid = false;
783            }
784    
785            return valid;
786        }
787    
788        /**
789         * Checks that only one Agreement has the Use Transaction Restriction From Agreement checked.
790         * 
791         * @return true if valid, false otherwise
792         */
793        private boolean validateUseTransactionRestrictionFromAgreement() {
794            boolean valid = true;
795            boolean useTransactionRestrictionFromAgreementFound = false;
796    
797            for (KemidAgreement kemidAgreement : newKemid.getKemidAgreements()) {
798                if (kemidAgreement.isUseTransactionRestrictionFromAgreement()) {
799                    if (useTransactionRestrictionFromAgreementFound) {
800                        putFieldError(EndowPropertyConstants.KEMID_AGREEMENTS_TAB, EndowKeyConstants.KEMIDConstants.ERROR_KEMID_ONLY_ONE_AGREEMENT_CAN_BR_MARKED_FOR_TRANSACTION_RESTR_USE);
801                        valid = false;
802                        break;
803                    }
804                    useTransactionRestrictionFromAgreementFound = true;
805                }
806    
807            }
808            return valid;
809        }
810    
811        /**
812         * Validates that the KEMID has at least one Source of Funds defined.
813         * 
814         * @return true if valid, false otherwise
815         */
816        private boolean validateSourceOfFunds() {
817            boolean valid = true;
818            boolean hasActiveRecord = false;
819    
820            if (newKemid.getKemidSourcesOfFunds() == null || newKemid.getKemidSourcesOfFunds().size() == 0) {
821                putFieldError(EndowPropertyConstants.KEMID_SOURCE_OF_FUNDS_TAB, EndowKeyConstants.KEMIDConstants.ERROR_KEMID_MUST_HAVE_AT_LEAST_ONE_ACTIVE_SOURCE_OF_FUNDS);
822                valid = false;
823            }
824            else {
825                // Make sure that the KEMID has at least one ACTIVE Source of Funds
826                for (KemidSourceOfFunds kemidSourceOfFunds : newKemid.getKemidSourcesOfFunds()) {
827                    if (kemidSourceOfFunds.isActive()) {
828                        hasActiveRecord = true;
829                        break;
830                    }
831                }
832            }
833            if (!hasActiveRecord) {
834                putFieldError(EndowPropertyConstants.KEMID_SOURCE_OF_FUNDS_TAB, EndowKeyConstants.KEMIDConstants.ERROR_KEMID_MUST_HAVE_AT_LEAST_ONE_ACTIVE_SOURCE_OF_FUNDS);
835                valid = false;
836            }
837    
838            return valid;
839        }
840    
841        /**
842         * Validates that the KEMID has at least one ACTIVE Benefitting Org defined.
843         * 
844         * @return true if valid, false otherwise
845         */
846        private boolean validateBenefittingOrgs() {
847            boolean valid = true;
848            boolean hasActiveRecord = false;
849    
850            if (newKemid.getKemidBenefittingOrganizations() == null || newKemid.getKemidBenefittingOrganizations().size() == 0) {
851                putFieldError(EndowPropertyConstants.KEMID_BENEFITTING_ORGS_TAB, EndowKeyConstants.KEMIDConstants.ERROR_KEMID_MUST_HAVE_AT_LEAST_ONE_ACTIVE_BENEFITTING_ORG);
852                valid = false;
853            }
854            else {
855                // Make sure that the KEMID has at least one ACTIVE Benefitting Org
856                for (KemidBenefittingOrganization kemidBenefittingOrganization : newKemid.getKemidBenefittingOrganizations()) {
857                    if (kemidBenefittingOrganization.isActive()) {
858                        hasActiveRecord = true;
859                        break;
860                    }
861                }
862                if (!hasActiveRecord) {
863                    putFieldError(EndowPropertyConstants.KEMID_BENEFITTING_ORGS_TAB, EndowKeyConstants.KEMIDConstants.ERROR_KEMID_MUST_HAVE_AT_LEAST_ONE_ACTIVE_BENEFITTING_ORG);
864                    return false;
865                }
866                // Check: the total of BENE_PCT for all records where ROW_ACTV_IND is equal to Yes must be 1(100%).
867                KualiDecimal benefittingPercentage = KualiDecimal.ZERO;
868                for (KemidBenefittingOrganization benefittingOrganization : newKemid.getKemidBenefittingOrganizations()) {
869                    if (benefittingOrganization.isActive()) {
870                        benefittingPercentage = benefittingPercentage.add(benefittingOrganization.getBenefitPrecent());
871                    }
872                }
873    
874                if (benefittingPercentage.compareTo(new KualiDecimal(1)) != 0) {
875                    putFieldError(EndowPropertyConstants.KEMID_BENEFITTING_ORGS_TAB, EndowKeyConstants.KEMIDConstants.ERROR_KEMID_ACTIVE_BENE_ORGS_PCT_SUM_MUST_BE_ONE);
876                    valid = false;
877                }
878            }
879    
880            return valid;
881        }
882    
883        /**
884         * Validates the GeneralLedgerAccounts tab. In KEMID spec, section 6.5.1.1, item 1 and 2, the rules should be updated to : 1.
885         * One and ONLY ONE ACTIVE END_KEMID_GL_LNK_T record with the IP_IND_CD field equal to I must exist for each END_KEMID_T record.
886         * 2. One and ONLY ONE ACTIVE END_KEMID_GL_LNK_T record with the IP_IND_CD field equal to P must exist for each END_KEMID_T
887         * record where the TYP_PRIN_RESTR_CD for the associated END_KEMID_T: TYP_CD is NOT equal to NA (Not Applicable) 3. If the
888         * TYP_PRIN_RESTR_CD for the associated END_KEMID_T: TYP_CD is equal to NA (Not Applicable), each END_KEMID_T record can have
889         * either zero or one INACTIVE END_KEMID_GL_LNK_T record with the IP_IND_CD field equal to P
890         * 
891         * @return true if valid, false otherwise
892         */
893        private boolean validateGeneralLedgerAccounts() {
894            boolean valid = true;
895    
896            boolean hasIncomeGL = false;
897            boolean hasPrincipalGL = false;
898            boolean hasActiveIncomeGL = false;
899            boolean hasActivePrincipalGL = false;
900    
901    
902            if (newKemid.getKemidGeneralLedgerAccounts() == null || newKemid.getKemidGeneralLedgerAccounts().size() == 0) {
903                putFieldError(EndowPropertyConstants.KEMID_GENERAL_LEDGER_ACCOUNTS_TAB, EndowKeyConstants.KEMIDConstants.ERROR_KEMID_MUST_HAVE_AT_LEAST_ONE_INCOME_GL_ACC);
904                return false;
905            }
906            else {
907                valid &= validateIncomePrincipalGLAccounts(newKemid.getKemidGeneralLedgerAccounts());
908            }
909    
910            return valid;
911    
912        }
913    
914        /**
915         * Validates that there is no more than one active entry with IP indicator I or P, that there is at least one active income GL
916         * account, if principal restriction code is NA then there is no principal GL account and if principal restriction code is not
917         * NA then there is at least one principal GL account.
918         * 
919         * @param generalLedgerAccounts
920         * @return true if valid, false otherwise
921         */
922        private boolean validateIncomePrincipalGLAccounts(List<KemidGeneralLedgerAccount> generalLedgerAccounts) {
923            boolean valid = true;
924    
925            boolean hasIncomeGL = false;
926            boolean hasPrincipalGL = false;
927            boolean hasActiveIncomeGL = false;
928            boolean hasActivePrincipalGL = false;
929    
930    
931            if (generalLedgerAccounts != null && generalLedgerAccounts.size() != 0) {
932                for (KemidGeneralLedgerAccount kemidGeneralLedgerAccount : generalLedgerAccounts) {
933                    if (kemidGeneralLedgerAccount.getIncomePrincipalIndicatorCode().equalsIgnoreCase(EndowConstants.IncomePrincipalIndicator.INCOME)) {
934                        // One and ONLY ONE END_KEMID_GL_LNK_T record with the IP_IND_CD field equal to I must exist for each
935                        // END_KEMID_T record.
936                        if (!hasIncomeGL) {
937                            hasIncomeGL = true;
938                        }
939                        else {
940                            // Error: There are more than one END_KEMID_GL_LNK_T record with the IP_IND_CD field equal to I
941                            putFieldError(EndowPropertyConstants.KEMID_GENERAL_LEDGER_ACCOUNTS_TAB, EndowKeyConstants.KEMIDConstants.ERROR_KEMID_CAN_ONLY_HAVE_ONE_INCOME_GL_ACC);
942                            return false;
943                        }
944                        if (hasIncomeGL) {
945                            hasActiveIncomeGL = kemidGeneralLedgerAccount.isActive();
946                        }
947                    }
948                    else if (kemidGeneralLedgerAccount.getIncomePrincipalIndicatorCode().equalsIgnoreCase(EndowConstants.IncomePrincipalIndicator.PRINCIPAL)) {
949                        if (!hasPrincipalGL) {
950                            hasPrincipalGL = true;
951                        }
952                        else {
953                            // Error: There is more than one END_KEMID_GL_LNK_T record with the IP_IND_CD field equal to P
954                            putFieldError(EndowPropertyConstants.KEMID_GENERAL_LEDGER_ACCOUNTS_TAB, EndowKeyConstants.KEMIDConstants.ERROR_KEMID_CAN_ONLY_HAVE_ONE_PRINCIPAL_GL_ACC);
955                            return false;
956                        }
957                        if (hasPrincipalGL) {
958                            hasActivePrincipalGL = kemidGeneralLedgerAccount.isActive();
959                        }
960                    }
961                    
962                    hasActivePrincipalGL = kemidGeneralLedgerAccount.isActive();
963                }
964    
965                if (!hasIncomeGL || !hasActiveIncomeGL) {
966                    putFieldError(EndowPropertyConstants.KEMID_GENERAL_LEDGER_ACCOUNTS_TAB, EndowKeyConstants.KEMIDConstants.ERROR_KEMID_MUST_HAVE_AT_LEAST_ONE_INCOME_GL_ACC);
967                    return false;
968                }
969    
970                if (newKemid.getPrincipalRestrictionCode() != null && newKemid.getPrincipalRestrictionCode().equalsIgnoreCase(EndowConstants.TypeRestrictionPresetValueCodes.NOT_APPLICABLE_TYPE_RESTRICTION_CODE) && hasActivePrincipalGL) {
971                    putFieldError(EndowPropertyConstants.KEMID_GENERAL_LEDGER_ACCOUNTS_TAB, EndowKeyConstants.KEMIDConstants.ERROR_KEMID_CAN_NOT_HAVE_A_PRINCIPAL_GL_ACC_IF_PRINCIPAL_RESTR_CD_IS_NA);
972                    return false;
973                }
974    
975                if (newKemid.getPrincipalRestrictionCode() != null && !newKemid.getPrincipalRestrictionCode().equalsIgnoreCase(EndowConstants.TypeRestrictionPresetValueCodes.NOT_APPLICABLE_TYPE_RESTRICTION_CODE) && !hasActivePrincipalGL) {
976                    putFieldError(EndowPropertyConstants.KEMID_GENERAL_LEDGER_ACCOUNTS_TAB, EndowKeyConstants.KEMIDConstants.ERROR_KEMID_MUST_HAVE_AT_LEAST_ONE_ACTIVE_PRINCIPAL_GL_ACC_IF_PRINCIPAL_CD_NOT_NA);
977                    return false;
978                }
979            }
980    
981            return valid;
982        }
983    
984        /**
985         * Validates the KEMID Authorizations.
986         * 
987         * @return true if valid, false otherwise
988         */
989        private boolean validateKemidAuthorizations() {
990            boolean isValid = true;
991            String errorPathPrefix = KFSConstants.MAINTENANCE_ADD_PREFIX + EndowPropertyConstants.KEMID_AUTHORIZATIONS_TAB + ".";
992            List<KemidAuthorizations> authorizations = newKemid.getKemidAuthorizations();
993    
994            // if sys param END_KEMID_ROLE_T_RECORD_REQUIRED_IND is yes the Kemid must have at least one active entry in the
995            // authorizations tab
996            String authorizationReqParamVal = SpringContext.getBean(ParameterService.class).getParameterValue(KEMID.class, EndowParameterKeyConstants.ROLE_REQUIRED_IND);
997    
998            if (KFSConstants.ParameterValues.YES.equalsIgnoreCase(authorizationReqParamVal)) {
999                // At least one active records must exist
1000                if (authorizations == null || authorizations.size() == 0) {
1001                    putFieldError(EndowPropertyConstants.KEMID_AUTHORIZATIONS_TAB, EndowKeyConstants.KEMIDConstants.ERROR_KEMID_MUST_HAVE_AT_LEAST_ONE_ACTIVE_AUTHORIZATION);
1002                    return false;
1003                }
1004                isValid &= validateKemidAuthorizationsHaveOneActiveEntry();
1005            }
1006    
1007            // check all authorizations are valid
1008            for (int i = 0; i < authorizations.size(); i++) {
1009                KemidAuthorizations authorization = (KemidAuthorizations) authorizations.get(i);
1010                isValid &= checkAuthorization(authorization, i);
1011            }
1012    
1013            return isValid;
1014        }
1015    
1016        /**
1017         * Checks if the Authorizations tab has at least one active entry.
1018         * 
1019         * @return true if it has one, false otherwise
1020         */
1021        private boolean validateKemidAuthorizationsHaveOneActiveEntry() {
1022            boolean hasActiveAuthorization = false;
1023            for (KemidAuthorizations authorization : newKemid.getKemidAuthorizations()) {
1024                if (authorization.isActive()) {
1025                    hasActiveAuthorization = true;
1026                    break;
1027                }
1028            }
1029            return hasActiveAuthorization;
1030        }
1031    
1032        /**
1033         * Validates that the role namespace is KFS-ENDOW.
1034         * 
1035         * @param authorization
1036         * @return true if valid, false otherwise
1037         */
1038        private boolean validateRoleInKFSEndowNamespace(KemidAuthorizations authorization, int index) {
1039    
1040            if (!authorization.getRole().getNamespaceCode().equalsIgnoreCase(EndowConstants.KFS_ENDOW_ROLE_NAMESPACE)) {
1041                if (index == -1) {
1042                    putFieldError(KFSConstants.MAINTENANCE_ADD_PREFIX + EndowPropertyConstants.KEMID_AUTHORIZATIONS_TAB + "." + EndowPropertyConstants.KEMID_AUTHORIZATIONS_ROLE_ID, EndowKeyConstants.KEMIDConstants.ERROR_KEMID_AUTHORIZATION_ROLE_NAMESPACE_ENDOW);
1043                }
1044                else {
1045                    putFieldError(EndowPropertyConstants.KEMID_AUTHORIZATIONS_TAB + "[" + index + "]" + "." + EndowPropertyConstants.KEMID_AUTHORIZATIONS_ROLE_ID, EndowKeyConstants.KEMIDConstants.ERROR_KEMID_AUTHORIZATION_ROLE_NAMESPACE_ENDOW);
1046                }
1047                return false;
1048            }
1049            else
1050                return true;
1051    
1052        }
1053    
1054        /**
1055         * Validates KEMID Donor Statements.
1056         * 
1057         * @return true if valid, false otherwise
1058         */
1059        private boolean validateKemidDonorStatements() {
1060            boolean isValid = true;
1061            String errorPathPrefix = KFSConstants.MAINTENANCE_ADD_PREFIX + EndowPropertyConstants.KEMID_DONOR_STATEMENTS_TAB + ".";
1062            for (KemidDonorStatement donorStatement : newKemid.getKemidDonorStatements()) {
1063                if (!validCombineWithDonorId(donorStatement)) {
1064                    isValid = false;
1065                }
1066    
1067                if (donorStatement.getTerminationDate() != null && StringUtils.isEmpty(donorStatement.getTerminationReason())) {
1068                    putFieldError(errorPathPrefix + EndowPropertyConstants.KEMID_DONOR_STATEMENT_TERMINATION_REASON, EndowKeyConstants.KEMIDConstants.ERROR_KEMID_DONOR_STMNT_TERM_RSN_CANT_BE_EMPTY_IS_TERM_DATE_ENTERED);
1069                    isValid = false;
1070                }
1071            }
1072            return isValid;
1073        }
1074    
1075        /**
1076         * Checks that the combine with donor is different from the donor.
1077         * 
1078         * @param donorStatement
1079         * @return true if valid, false otherwise
1080         */
1081        private boolean validCombineWithDonorId(KemidDonorStatement donorStatement) {
1082            String combineWithDonorId = donorStatement.getCombineWithDonorId();
1083            String errorPathPrefix = KFSConstants.MAINTENANCE_ADD_PREFIX + EndowPropertyConstants.KEMID_DONOR_STATEMENTS_TAB + ".";
1084    
1085            if (StringUtils.isNotEmpty(combineWithDonorId)) {
1086                if (combineWithDonorId.equalsIgnoreCase(donorStatement.getDonorId())) {
1087                    putFieldError(errorPathPrefix + EndowPropertyConstants.KEMID_DONOR_STATEMENT_COMBINE_WITH_DONOR_ID, EndowKeyConstants.KEMIDConstants.ERROR_KEMID_DONOR_STMNT_COMBINE_WITH_DONR_MUST_BE_DIFF_FROM_DONOR);
1088                    return false;
1089                }
1090    
1091            }
1092            return true;
1093    
1094        }
1095    
1096        /**
1097         * Validates that the KEMID has at least one Pay Instruction defined.
1098         * 
1099         * @return true if valid, false otherwise
1100         */
1101        private boolean validatePayoutInstructions() {
1102            boolean valid = true;
1103    
1104            if (newKemid.getKemidPayoutInstructions() == null || newKemid.getKemidPayoutInstructions().size() == 0) {
1105                putFieldError(EndowPropertyConstants.KEMID_PAY_INSTRUCTIONS_TAB, EndowKeyConstants.KEMIDConstants.ERROR_KEMID_MUST_HAVE_AT_LEAST_ONE_PAYOUT_INSTRUCTION);
1106                valid = false;
1107            }
1108    
1109            if (valid) {
1110                int index = 0;
1111                for (KemidPayoutInstruction payoutInstruction : newKemid.getKemidPayoutInstructions()) {
1112                    checkPayoutInstruction(payoutInstruction, index);
1113                    index++;
1114                }
1115                validatePayoutInstructionsPercentTotal();
1116            }
1117    
1118            return valid;
1119        }
1120    
1121        /**
1122         * Validates that the total of all non-terminated records is 1 (100%).
1123         * 
1124         * @return true if valid, false otherwise
1125         */
1126        private boolean validatePayoutInstructionsPercentTotal() {
1127            boolean isValid = true;
1128            DateTimeService dateTimeService = SpringContext.getBean(DateTimeService.class);
1129            Date currentDate = dateTimeService.getCurrentSqlDate();
1130            KualiDecimal total = KualiDecimal.ZERO;
1131    
1132            for (KemidPayoutInstruction payoutInstruction : newKemid.getKemidPayoutInstructions()) {
1133                if (payoutInstruction.getEndDate() == null || payoutInstruction.getEndDate().after(currentDate)) {
1134                    total = total.add(payoutInstruction.getPercentOfIncomeToPayToKemid());
1135                }
1136            }
1137            KualiDecimal one = new KualiDecimal(1);
1138            if (one.compareTo(total) != 0) {
1139                putFieldError(EndowPropertyConstants.KEMID_PAY_INSTRUCTIONS_TAB, EndowKeyConstants.KEMIDConstants.ERROR_KEMID_TOTAL_OFF_ALL_PAYOUT_RECORDS_MUST_BE_ONE);
1140                isValid = false;
1141            }
1142            return isValid;
1143        }
1144    
1145        /**
1146         * Validates the Kemid Fees.
1147         * 
1148         * @return true if valid, false otherwise
1149         */
1150        private boolean validateFees() {
1151            boolean valid = true;
1152            List<KemidFee> fees = newKemid.getKemidFees();
1153    
1154            if (fees != null && fees.size() != 0) {
1155                for (int i = 0; i < fees.size(); i++) {
1156                    KemidFee fee = fees.get(i);
1157                    if (!validateFeePercentageTotal(fee, i)) {
1158                        valid = false;
1159                    }
1160                    if (!validatePercentageOfFeeChargedToPrincipal(fee, i)) {
1161                        valid = false;
1162                    }
1163                    if (!validateKemidFeeStartDate(fee, i)) {
1164                        valid = false;
1165                    }
1166                }
1167            }
1168            return valid;
1169        }
1170    
1171        /**
1172         * Validates that the total of the Percentage of Fee Charged to Income plus Percentage Of Fee Charged to Principal cannot exceed
1173         * 1 (100%).
1174         * 
1175         * @param fee
1176         * @return true if valid, false otherwise
1177         */
1178        private boolean validateFeePercentageTotal(KemidFee fee, int index) {
1179            boolean valid = true;
1180            KualiDecimal percentage = fee.getPercentOfFeeChargedToIncome().add(fee.getPercentOfFeeChargedToPrincipal());
1181            if (percentage.isGreaterThan(new KualiDecimal(1))) {
1182                valid = false;
1183                if (index != -1) {
1184                    putFieldError(EndowPropertyConstants.KEMID_FEES_TAB + "[" + index + "]", EndowKeyConstants.KEMIDConstants.ERROR_KEMID_FEE_PCT_CHRG_FEE_SUM_MUST_NOT_BE_GREATER_THAN_ONE);
1185                }
1186                else {
1187                    putFieldError(EndowPropertyConstants.KEMID_FEES_TAB, EndowKeyConstants.KEMIDConstants.ERROR_KEMID_FEE_PCT_CHRG_FEE_SUM_MUST_NOT_BE_GREATER_THAN_ONE);
1188                }
1189            }
1190            return valid;
1191        }
1192    
1193        /**
1194         * Validates that the percentage if fee charged to principal does not exceed zero when the type restriction code is NA(Not
1195         * Available).
1196         * 
1197         * @param fee
1198         * @return true if valid, false otherwise
1199         */
1200        private boolean validatePercentageOfFeeChargedToPrincipal(KemidFee fee, int index) {
1201            boolean valid = true;
1202            if (ObjectUtils.isNotNull(newKemid.getType()) && EndowConstants.TypeRestrictionPresetValueCodes.NOT_APPLICABLE_TYPE_RESTRICTION_CODE.equalsIgnoreCase(newKemid.getPrincipalRestrictionCode())) {
1203                if (fee.getPercentOfFeeChargedToPrincipal().isGreaterThan(KualiDecimal.ZERO)) {
1204                    valid = false;
1205                    if (index >= 0) {
1206                        putFieldError(EndowPropertyConstants.KEMID_FEES_TAB + "[" + index + "]" + "." + EndowPropertyConstants.KEMID_FEE_PERCENT_OF_FEE_CHARGED_TO_PRINCIPAL, EndowKeyConstants.KEMIDConstants.ERROR_KEMID_FEE_PCT_CHRG_TO_PRIN_CANNOT_EXCEED_ZERO_IF_TYPE_RESTR_CD_NA);
1207                    }
1208                    else {
1209                        putFieldError(EndowPropertyConstants.KEMID_FEE_PERCENT_OF_FEE_CHARGED_TO_PRINCIPAL, EndowKeyConstants.KEMIDConstants.ERROR_KEMID_FEE_PCT_CHRG_TO_PRIN_CANNOT_EXCEED_ZERO_IF_TYPE_RESTR_CD_NA);
1210                    }
1211                }
1212            }
1213            return valid;
1214    
1215        }
1216    
1217        /**
1218         * Validates that the kemid fee start date is a valid value for the fee frequency.
1219         * 
1220         * @param fee
1221         * @return true if valid, false otherwise
1222         */
1223        private boolean validateKemidFeeStartDate(KemidFee fee, int index) {
1224            boolean isValid = true;
1225            ValidateDateBasedOnFrequencyCodeService validateService = SpringContext.getBean(ValidateDateBasedOnFrequencyCodeService.class);
1226    
1227            Date feeStartDate = fee.getFeeStartDate();
1228            fee.refreshReferenceObject(EndowPropertyConstants.FEE_METHOD);
1229    
1230            String frequencyCode = fee.getFeeMethod() != null ? fee.getFeeMethod().getFeeFrequencyCode() : null;
1231    
1232            if (feeStartDate != null && frequencyCode != null) {
1233                isValid = validateService.validateDateBasedOnFrequencyCode(feeStartDate, frequencyCode);
1234            }
1235    
1236            if (!isValid) {
1237                if (index == -1) {
1238                    putFieldError(KFSConstants.MAINTENANCE_ADD_PREFIX + EndowPropertyConstants.KEMID_FEES_TAB + "." + EndowPropertyConstants.KEMID_FEE_START_DATE, EndowKeyConstants.KEMIDConstants.ERROR_KEMID_FEE_START_DATE_NOT_VALID);
1239                }
1240                else {
1241                    putFieldError(EndowPropertyConstants.KEMID_FEES_TAB + "[" + index + "]" + "." + EndowPropertyConstants.KEMID_FEE_START_DATE, EndowKeyConstants.KEMIDConstants.ERROR_KEMID_FEE_START_DATE_NOT_VALID);
1242                }
1243    
1244            }
1245    
1246            return isValid;
1247        }
1248    }