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 }