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 }