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.math.BigDecimal; 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.kuali.kfs.module.endow.EndowConstants; 026 import org.kuali.kfs.module.endow.EndowKeyConstants; 027 import org.kuali.kfs.module.endow.EndowPropertyConstants; 028 import org.kuali.kfs.module.endow.businessobject.EndowmentSourceTransactionLine; 029 import org.kuali.kfs.module.endow.businessobject.EndowmentTransactionCode; 030 import org.kuali.kfs.module.endow.businessobject.EndowmentTransactionLine; 031 import org.kuali.kfs.module.endow.businessobject.EndowmentTransactionSecurity; 032 import org.kuali.kfs.module.endow.businessobject.EndowmentTransactionTaxLotLine; 033 import org.kuali.kfs.module.endow.businessobject.HoldingTaxLot; 034 import org.kuali.kfs.module.endow.businessobject.KEMID; 035 import org.kuali.kfs.module.endow.businessobject.KEMIDCurrentAvailableBalance; 036 import org.kuali.kfs.module.endow.businessobject.Security; 037 import org.kuali.kfs.module.endow.document.EndowmentSecurityDetailsDocumentBase; 038 import org.kuali.kfs.module.endow.document.EndowmentTransactionLinesDocument; 039 import org.kuali.kfs.module.endow.document.EndowmentTransactionLinesDocumentBase; 040 import org.kuali.kfs.module.endow.document.EndowmentTransactionalDocument; 041 import org.kuali.kfs.module.endow.document.SecurityTransferDocument; 042 import org.kuali.kfs.module.endow.document.service.EndowmentTransactionCodeService; 043 import org.kuali.kfs.module.endow.document.service.EndowmentTransactionDocumentService; 044 import org.kuali.kfs.module.endow.document.service.EndowmentTransactionLinesDocumentService; 045 import org.kuali.kfs.module.endow.document.service.HoldingTaxLotService; 046 import org.kuali.kfs.module.endow.document.service.KEMIDService; 047 import org.kuali.kfs.module.endow.document.validation.AddTransactionLineRule; 048 import org.kuali.kfs.module.endow.document.validation.DeleteTransactionLineRule; 049 import org.kuali.kfs.module.endow.document.validation.RefreshTransactionLineRule; 050 import org.kuali.kfs.sys.KFSKeyConstants; 051 import org.kuali.kfs.sys.context.SpringContext; 052 import org.kuali.rice.kns.document.Document; 053 import org.kuali.rice.kns.service.BusinessObjectService; 054 import org.kuali.rice.kns.service.DictionaryValidationService; 055 import org.kuali.rice.kns.util.AbstractKualiDecimal; 056 import org.kuali.rice.kns.util.GlobalVariables; 057 import org.kuali.rice.kns.util.KualiDecimal; 058 import org.kuali.rice.kns.util.ObjectUtils; 059 060 public class EndowmentTransactionLinesDocumentBaseRules extends EndowmentTransactionalDocumentBaseRule implements AddTransactionLineRule<EndowmentTransactionLinesDocument, EndowmentTransactionLine>, DeleteTransactionLineRule<EndowmentTransactionLinesDocument, EndowmentTransactionLine>, RefreshTransactionLineRule<EndowmentTransactionLinesDocument, EndowmentTransactionLine, Number> { 061 062 063 /** 064 * @see org.kuali.kfs.module.endow.document.validation.DeleteTransactionLineRule#processDeleteTransactionLineRules(org.kuali.kfs.module.endow.document.EndowmentTransactionLinesDocument, 065 * org.kuali.kfs.module.endow.businessobject.EndowmentTransactionLine) 066 */ 067 public boolean processDeleteTransactionLineRules(EndowmentTransactionLinesDocument endowmentTransactionLinesDocument, EndowmentTransactionLine endowmentTransactionLine) { 068 return true; 069 } 070 071 /** 072 * @see org.kuali.kfs.module.endow.document.validation.AddTransactionLineRule#processAddTransactionLineRules(org.kuali.kfs.module.endow.document.EndowmentTransactionLinesDocument, 073 * org.kuali.kfs.module.endow.businessobject.EndowmentTransactionLine) 074 */ 075 public boolean processAddTransactionLineRules(EndowmentTransactionLinesDocument document, EndowmentTransactionLine line) { 076 return validateTransactionLine((EndowmentTransactionLinesDocumentBase) document, line, -1); 077 } 078 079 /** 080 * @see org.kuali.kfs.module.endow.document.validation.RefreshTransactionLineRule#processRefreshTransactionLineRules(org.kuali.kfs.module.endow.document.EndowmentTransactionLinesDocument, 081 * org.kuali.kfs.module.endow.businessobject.EndowmentTransactionLine, java.lang.Number) 082 */ 083 public boolean processRefreshTransactionLineRules(EndowmentTransactionLinesDocument endowmentTransactionLinesDocument, EndowmentTransactionLine endowmentTransactionLine, Number index) { 084 return validateTransactionLine((EndowmentTransactionLinesDocumentBase) endowmentTransactionLinesDocument, endowmentTransactionLine, (Integer) index); 085 } 086 087 /** 088 * @see org.kuali.rice.kns.rules.DocumentRuleBase#processCustomRouteDocumentBusinessRules(org.kuali.rice.kns.document.Document) 089 */ 090 @Override 091 protected boolean processCustomRouteDocumentBusinessRules(Document document) { 092 boolean isValid = super.processCustomRouteDocumentBusinessRules(document); 093 isValid &= !GlobalVariables.getMessageMap().hasErrors(); 094 095 EndowmentTransactionLinesDocumentBase endowmentTransactionLinesDocumentBase = null; 096 097 if (isValid) { 098 endowmentTransactionLinesDocumentBase = (EndowmentTransactionLinesDocumentBase) document; 099 100 // validate source transaction lines 101 if (endowmentTransactionLinesDocumentBase.getSourceTransactionLines() != null) { 102 for (int i = 0; i < endowmentTransactionLinesDocumentBase.getSourceTransactionLines().size(); i++) { 103 EndowmentTransactionLine transactionLine = endowmentTransactionLinesDocumentBase.getSourceTransactionLines().get(i); 104 validateTransactionLine(endowmentTransactionLinesDocumentBase, transactionLine, i); 105 } 106 } 107 108 // validate target transaction lines 109 if (endowmentTransactionLinesDocumentBase.getTargetTransactionLines() != null) { 110 for (int i = 0; i < endowmentTransactionLinesDocumentBase.getTargetTransactionLines().size(); i++) { 111 EndowmentTransactionLine transactionLine = endowmentTransactionLinesDocumentBase.getTargetTransactionLines().get(i); 112 validateTransactionLine(endowmentTransactionLinesDocumentBase, transactionLine, i); 113 } 114 } 115 116 } 117 118 return GlobalVariables.getMessageMap().getErrorCount() == 0; 119 } 120 121 /** 122 * This method obtains Prefix for Error fields in UI. 123 * 124 * @param line 125 * @param index 126 * @return 127 */ 128 public String getErrorPrefix(EndowmentTransactionLine line, int index) { 129 String ERROR_PREFIX = null; 130 if (line instanceof EndowmentSourceTransactionLine) { 131 if (index == -1) { 132 ERROR_PREFIX = EndowPropertyConstants.SOURCE_TRANSACTION_LINE_PREFIX; 133 } 134 else { 135 ERROR_PREFIX = EndowPropertyConstants.EXISTING_SOURCE_TRANSACTION_LINE_PREFIX + "[" + index + "]."; 136 } 137 } 138 else { 139 if (index == -1) { 140 ERROR_PREFIX = EndowPropertyConstants.TARGET_TRANSACTION_LINE_PREFIX; 141 } 142 else { 143 ERROR_PREFIX = EndowPropertyConstants.EXISTING_TARGET_TRANSACTION_LINE_PREFIX + "[" + index + "]."; 144 } 145 } 146 return ERROR_PREFIX; 147 148 } 149 150 /** 151 * This method obtains security code from a document. 152 * 153 * @param endowmentTransactionLinesDocumentBase 154 * @param line 155 * @return 156 */ 157 public String getSecurityIDForValidation(EndowmentTransactionLinesDocument endowmentTransactionLinesDocumentBase, boolean isSource) { 158 EndowmentSecurityDetailsDocumentBase document = (EndowmentSecurityDetailsDocumentBase) endowmentTransactionLinesDocumentBase; 159 if (isSource) 160 return document.getSourceTransactionSecurity().getSecurityID(); 161 else 162 return document.getTargetTransactionSecurity().getSecurityID(); 163 } 164 165 /** 166 * This method obtains Registration code from a document. 167 * 168 * @param endowmentTransactionLinesDocumentBase 169 * @param line 170 * @return 171 */ 172 public String getRegistrationForValidation(EndowmentTransactionLinesDocument endowmentTransactionLinesDocumentBase, boolean isSource) { 173 EndowmentSecurityDetailsDocumentBase document = (EndowmentSecurityDetailsDocumentBase) endowmentTransactionLinesDocumentBase; 174 if (isSource) 175 return document.getSourceTransactionSecurity().getRegistrationCode(); 176 else 177 return document.getTargetTransactionSecurity().getRegistrationCode(); 178 } 179 180 /** 181 * This method obtains security from a document. 182 * 183 * @param endowmentTransactionLinesDocumentBase 184 * @param line 185 * @return 186 */ 187 public Security getSecurityForValidation(EndowmentTransactionLinesDocument endowmentTransactionLinesDocumentBase, boolean isSource) { 188 EndowmentSecurityDetailsDocumentBase document = (EndowmentSecurityDetailsDocumentBase) endowmentTransactionLinesDocumentBase; 189 if (isSource) 190 return document.getSourceTransactionSecurity().getSecurity(); 191 else 192 return document.getTargetTransactionSecurity().getSecurity(); 193 } 194 195 /** 196 * This method validates a transaction line. 197 * 198 * @param line 199 * @param index 200 * @return 201 */ 202 protected boolean validateTransactionLine(EndowmentTransactionLinesDocument endowmentTransactionLinesDocument, EndowmentTransactionLine line, int index) { 203 boolean isValid = true; 204 int originalErrorCount = GlobalVariables.getMessageMap().getErrorCount(); 205 getDictionaryValidationService().validateBusinessObject(line); 206 207 isValid &= GlobalVariables.getMessageMap().getErrorCount() == originalErrorCount; 208 209 String ERROR_PREFIX = getErrorPrefix(line, index); 210 211 if (isValid) { 212 GlobalVariables.getMessageMap().clearErrorPath(); 213 214 // General not null validation for KemID 215 SpringContext.getBean(DictionaryValidationService.class).validateAttributeRequired(line.getClass().getName(), "kemid", line.getKemid(), false, ERROR_PREFIX + EndowPropertyConstants.KEMID); 216 217 // Validate KemID 218 if (!validateKemId(line, ERROR_PREFIX)) 219 return false; 220 221 // Active Kemid 222 isValid &= isActiveKemId(line, ERROR_PREFIX); 223 224 // Validate no restriction transaction restriction 225 isValid &= validateNoTransactionRestriction(line, ERROR_PREFIX); 226 227 // Validate Income/Principal DropDown 228 SpringContext.getBean(DictionaryValidationService.class).validateAttributeRequired(line.getClass().getName(), "transactionIPIndicatorCode", line.getTransactionIPIndicatorCode(), false, ERROR_PREFIX + EndowPropertyConstants.TRANSACTION_IPINDICATOR); 229 isValid &= GlobalVariables.getMessageMap().getErrorCount() == 0 ? true : false; 230 if (!isValid) 231 return isValid; 232 233 // This error is checked in addition save rule method since the sub type is used for determining chart code. 234 if (!isSubTypeEmpty(endowmentTransactionLinesDocument)) 235 return false; 236 237 // If non-cash transactions 238 if (nonCashTransaction(endowmentTransactionLinesDocument) && hasEtranCode(endowmentTransactionLinesDocument)) { 239 // Is Etran code empty 240 if (isEndowmentTransactionCodeEmpty(line, ERROR_PREFIX)) 241 return false; 242 243 // Validate ETran code 244 if (!validateEndowmentTransactionCode(line, ERROR_PREFIX)) 245 return false; 246 247 // Validate ETran code as E or I 248 isValid &= validateEndowmentTransactionTypeCode(endowmentTransactionLinesDocument, line, ERROR_PREFIX); 249 250 // Validate if a KEMID can have a principal transaction when IP indicator is P 251 if (!canKEMIDHaveAPrincipalTransaction(line, ERROR_PREFIX)) 252 return false; 253 254 // Validate if the chart is matched between the KEMID and EtranCode 255 isValid &= validateChartMatch(line, ERROR_PREFIX); 256 257 // Set Corpus Indicator 258 line.setCorpusIndicator(SpringContext.getBean(EndowmentTransactionLinesDocumentService.class).getCorpusIndicatorValueforAnEndowmentTransactionLine(line.getKemid(), line.getEtranCode(), line.getTransactionIPIndicatorCode())); 259 } 260 261 // Refresh all references for the given KemId 262 // line.getKemidObj().refreshNonUpdateableReferences(); 263 264 265 } 266 267 return GlobalVariables.getMessageMap().getErrorCount() == 0; 268 } 269 270 /** 271 * This method checks if this is a non-cash transaction. 272 * 273 * @param endowmentTransactionLinesDocumentBase 274 * @return 275 */ 276 protected boolean nonCashTransaction(EndowmentTransactionLinesDocument endowmentTransactionLinesDocument) { 277 if (EndowConstants.TransactionSubTypeCode.NON_CASH.equalsIgnoreCase(endowmentTransactionLinesDocument.getTransactionSubTypeCode())) 278 return true; 279 else 280 return false; 281 } 282 283 /** 284 * Tells if the document has an etran code. Override this method in the BR class specific to your document to return whether the 285 * document has etran code or not. 286 * 287 * @param endowmentTransactionLinesDocument 288 * @return true by default. It should return true if the document has an etran code or false otherwise. 289 */ 290 protected boolean hasEtranCode(EndowmentTransactionLinesDocument endowmentTransactionLinesDocument) { 291 return true; 292 } 293 294 /** 295 * This method validates the KEMID code. 296 * 297 * @param tranSecurity 298 * @return 299 */ 300 protected boolean isKemIdCodeEmpty(EndowmentTransactionLine line, String prefix) { 301 if (StringUtils.isEmpty(line.getKemid())) { 302 putFieldError(prefix + EndowPropertyConstants.KEMID, EndowKeyConstants.EndowmentTransactionDocumentConstants.ERROR_TRANSACTION_LINE_KEMID_REQUIRED); 303 return true; 304 } 305 306 return false; 307 } 308 309 /** 310 * This method validates the KemId code and tries to create a KEMID object from the code. 311 * 312 * @param line 313 * @return 314 */ 315 protected boolean validateKemId(EndowmentTransactionLine line, String prefix) { 316 boolean success = true; 317 318 KEMID kemId = (KEMID) SpringContext.getBean(KEMIDService.class).getByPrimaryKey(line.getKemid()); 319 line.setKemidObj(kemId); 320 if (null == kemId) { 321 putFieldError(prefix + EndowPropertyConstants.KEMID, EndowKeyConstants.EndowmentTransactionDocumentConstants.ERROR_TRANSACTION_LINE_KEMID_INVALID); 322 success = false; 323 } 324 325 return success; 326 } 327 328 /** 329 * This method determines if the KEMID is active. 330 * 331 * @param line 332 * @return 333 */ 334 protected boolean isActiveKemId(EndowmentTransactionLine line, String prefix) { 335 if (line.getKemidObj().isClose()) { 336 putFieldError(prefix + EndowPropertyConstants.KEMID, EndowKeyConstants.EndowmentTransactionDocumentConstants.ERROR_TRANSACTION_LINE_KEMID_INACTIVE); 337 return false; 338 339 } 340 else { 341 return true; 342 } 343 } 344 345 /** 346 * This method checks if the KEMID restriction code is "NTRAN" 347 * 348 * @param line 349 * @return 350 */ 351 protected boolean validateNoTransactionRestriction(EndowmentTransactionLine line, String prefix) { 352 if (line.getKemidObj().getTransactionRestrictionCode().equalsIgnoreCase(EndowConstants.TransactionRestrictionCode.TRAN_RESTR_CD_NTRAN)) { 353 putFieldError(prefix + EndowPropertyConstants.KEMID, EndowKeyConstants.EndowmentTransactionDocumentConstants.ERROR_TRANSACTION_LINE_KEMID_NO_TRAN_CODE); 354 return false; 355 } 356 else { 357 return true; 358 } 359 360 } 361 362 /** 363 * This method checks is the Transaction amount entered is greater than Zero. 364 * 365 * @param line 366 * @return 367 */ 368 protected boolean validateTransactionAmountGreaterThanZero(EndowmentTransactionLine line, String prefix) { 369 if (line.getTransactionAmount() != null && line.getTransactionAmount().isGreaterThan(AbstractKualiDecimal.ZERO)) 370 return true; 371 else { 372 putFieldError(prefix + EndowPropertyConstants.TRANSACTION_LINE_TRANSACTION_AMOUNT, EndowKeyConstants.EndowmentTransactionDocumentConstants.ERROR_TRANSACTION_LINE_AMOUNT_GREATER_THAN_ZERO); 373 return false; 374 } 375 } 376 377 /** 378 * This method checks is the Transaction amount entered is greater than Zero. 379 * 380 * @param line 381 * @return 382 */ 383 protected boolean validateTransactionAmountLessThanZero(EndowmentTransactionLine line, String prefix) { 384 if (line.getTransactionAmount() != null && line.getTransactionAmount().isLessThan(AbstractKualiDecimal.ZERO)) 385 return true; 386 else { 387 putFieldError(prefix + EndowPropertyConstants.TRANSACTION_LINE_TRANSACTION_AMOUNT, EndowKeyConstants.EndowmentTransactionDocumentConstants.ERROR_TRANSACTION_LINE_AMOUNT_LESS_THAN_ZERO); 388 return false; 389 } 390 } 391 392 /** 393 * This method checks is the Transaction Units entered is greater than Zero. 394 * 395 * @param line 396 * @return 397 */ 398 protected boolean validateTransactionUnitsGreaterThanZero(EndowmentTransactionLine line, String prefix) { 399 if (line.getTransactionUnits() != null && line.getTransactionUnits().isGreaterThan(AbstractKualiDecimal.ZERO)) 400 return true; 401 else { 402 putFieldError(prefix + EndowPropertyConstants.TRANSACTION_LINE_TRANSACTION_UNITS, EndowKeyConstants.EndowmentTransactionDocumentConstants.ERROR_TRANSACTION_UNITS_GREATER_THAN_ZERO); 403 return false; 404 } 405 } 406 407 /** 408 * This method checks is the Transaction Units entered is greater than Zero. 409 * 410 * @param line 411 * @return 412 */ 413 protected boolean validateTransactionUnitsLessThanZero(EndowmentTransactionLine line, String prefix) { 414 if (line.getTransactionUnits() != null && line.getTransactionUnits().isLessThan(AbstractKualiDecimal.ZERO)) 415 return true; 416 else { 417 putFieldError(prefix + EndowPropertyConstants.TRANSACTION_LINE_TRANSACTION_UNITS, EndowKeyConstants.EndowmentTransactionDocumentConstants.ERROR_TRANSACTION_UNITS_LESS_THAN_ZERO); 418 return false; 419 } 420 } 421 422 /** 423 * This method checks is the Transaction Units & Amount entered are equal. 424 * 425 * @param line 426 * @param prefix 427 * @return 428 */ 429 protected boolean validateTransactionUnitsAmountEqual(EndowmentTransactionLine line, String prefix) { 430 if (line.getTransactionUnits() != null && line.getTransactionAmount() != null && line.getTransactionUnits().compareTo(line.getTransactionAmount()) == 0) 431 return true; 432 else { 433 putFieldError(prefix + EndowPropertyConstants.TRANSACTION_LINE_TRANSACTION_AMOUNT, EndowKeyConstants.EndowmentTransactionDocumentConstants.ERROR_TRANSACTION_AMOUNT_UNITS_EQUAL); 434 return false; 435 } 436 } 437 438 /** 439 * This method checks if the ETRAN code has a type code of E or I. 440 * 441 * @param line 442 * @return 443 */ 444 protected boolean validateEndowmentTransactionTypeCode(EndowmentTransactionLinesDocument endowmentTransactionLinesDocument, EndowmentTransactionLine line, String prefix) { 445 if (line.getEtranCodeObj().getEndowmentTransactionTypeCode().equalsIgnoreCase(EndowConstants.EndowmentTransactionTypeCodes.INCOME_TYPE_CODE) || line.getEtranCodeObj().getEndowmentTransactionTypeCode().equalsIgnoreCase(EndowConstants.EndowmentTransactionTypeCodes.EXPENSE_TYPE_CODE)) 446 return true; 447 else { 448 putFieldError(prefix + EndowPropertyConstants.TRANSACTION_LINE_ENDOWMENT_TRANSACTION_CODE, EndowKeyConstants.EndowmentTransactionDocumentConstants.ERROR_ENDOWMENT_TRANSACTION_TYPE_CODE_VALIDITY); 449 return false; 450 } 451 } 452 453 /** 454 * This method validates the EndowmentTransaction code. 455 * 456 * @param tranSecurity 457 * @return 458 */ 459 protected boolean isEndowmentTransactionCodeEmpty(EndowmentTransactionLine line, String prefix) { 460 if (StringUtils.isEmpty(line.getEtranCode())) { 461 putFieldError(prefix + EndowPropertyConstants.TRANSACTION_LINE_ENDOWMENT_TRANSACTION_CODE, EndowKeyConstants.EndowmentTransactionDocumentConstants.ERROR_TRANSACTION_LINE_ETRAN_REQUIRED); 462 return true; 463 } 464 465 return false; 466 } 467 468 /** 469 * This method validates the EndowmentTransaction code and tries to create a EndowmentTransactionCode object from the code. 470 * 471 * @param line 472 * @return 473 */ 474 protected boolean validateEndowmentTransactionCode(EndowmentTransactionLine line, String prefix) { 475 boolean success = true; 476 477 EndowmentTransactionCode etran = (EndowmentTransactionCode) SpringContext.getBean(EndowmentTransactionCodeService.class).getByPrimaryKey(line.getEtranCode()); 478 line.setEtranCodeObj(etran); 479 if (null == etran) { 480 putFieldError(prefix + EndowPropertyConstants.TRANSACTION_LINE_ENDOWMENT_TRANSACTION_CODE, EndowKeyConstants.EndowmentTransactionDocumentConstants.ERROR_TRANSACTION_LINE_ETRAN_INVALID); 481 success = false; 482 } 483 484 return success; 485 } 486 487 /** 488 * This method validates if a KEMID can have a principal transaction when IP indicator is equal to P. 489 * 490 * @param line 491 * @return 492 */ 493 protected boolean canKEMIDHaveAPrincipalTransaction(EndowmentTransactionLine line, String prefix) { 494 boolean canHaveTransaction = true; 495 String ipIndicatorCode = line.getTransactionIPIndicatorCode(); 496 if (EndowConstants.IncomePrincipalIndicator.PRINCIPAL.equalsIgnoreCase(ipIndicatorCode)) { 497 String kemid = line.getKemid(); 498 if (!SpringContext.getBean(EndowmentTransactionLinesDocumentService.class).canKEMIDHaveAPrincipalActivity(kemid, ipIndicatorCode)) { 499 putFieldError(prefix + EndowPropertyConstants.TRANSACTION_LINE_IP_INDICATOR_CODE, EndowKeyConstants.EndowmentTransactionDocumentConstants.ERROR_TRANSACTION_LINE_KEMID_CAN_NOT_HAVE_A_PRINCIPAL_TRANSACTION); 500 canHaveTransaction = false; 501 } 502 } 503 return canHaveTransaction; 504 } 505 506 /** 507 * This method validates if the chart is matched between GL Account in the KEMID and GL Link in the Endowment Transaction Code. 508 * If the Chart codes do not match, the Etran Code field should be highlighted. 509 * 510 * @param line 511 * @return 512 */ 513 protected boolean validateChartMatch(EndowmentTransactionLine line, String prefix) { 514 boolean isChartMatched = true; 515 String kemid = line.getKemid(); 516 String etranCode = line.getEtranCode(); 517 String ipIndicatorCode = line.getTransactionIPIndicatorCode(); 518 if (!SpringContext.getBean(EndowmentTransactionDocumentService.class).matchChartBetweenKEMIDAndETranCode(kemid, etranCode, ipIndicatorCode)) { 519 if (EndowConstants.IncomePrincipalIndicator.PRINCIPAL.equalsIgnoreCase(ipIndicatorCode)) 520 putFieldError(prefix + EndowPropertyConstants.TRANSACTION_LINE_ENDOWMENT_TRANSACTION_CODE, EndowKeyConstants.EndowmentTransactionDocumentConstants.ERROR_TRANSACTION_LINE_CHART_CODE_DOES_NOT_MATCH_FOR_PRINCIPAL); 521 else 522 putFieldError(prefix + EndowPropertyConstants.TRANSACTION_LINE_ENDOWMENT_TRANSACTION_CODE, EndowKeyConstants.EndowmentTransactionDocumentConstants.ERROR_TRANSACTION_LINE_CHART_CODE_DOES_NOT_MATCH_FOR_INCOME); 523 524 isChartMatched = false; 525 } 526 return isChartMatched; 527 } 528 529 /** 530 * Validates that the security chart and the etran code chart match. 531 * 532 * @param endowmentTransactionLinesDocument 533 * @param line 534 * @param prefix 535 * @param isSource 536 * @return true if valid, false otherwise 537 */ 538 protected boolean validateSecurityEtranChartMatch(EndowmentTransactionLinesDocument endowmentTransactionLinesDocument, EndowmentTransactionLine line, String prefix, boolean isSource) { 539 boolean isChartMatched = true; 540 Security security = getSecurityForValidation(endowmentTransactionLinesDocument, isSource); 541 String kemID = line.getKemid(); 542 String ipIndicatorCode = line.getTransactionIPIndicatorCode(); 543 if (!SpringContext.getBean(EndowmentTransactionDocumentService.class).matchChartBetweenSecurityAndETranCode(security, kemID, ipIndicatorCode)) { 544 if (EndowConstants.IncomePrincipalIndicator.PRINCIPAL.equalsIgnoreCase(ipIndicatorCode)) 545 putFieldError(prefix + EndowPropertyConstants.KEMID, EndowKeyConstants.EndowmentTransactionDocumentConstants.ERROR_TRANSACTION_LINE_SECURITY_KEMID_CHART_CODE_DOES_NOT_MATCH, EndowConstants.PRINCIPAL); 546 else 547 putFieldError(prefix + EndowPropertyConstants.KEMID, EndowKeyConstants.EndowmentTransactionDocumentConstants.ERROR_TRANSACTION_LINE_SECURITY_KEMID_CHART_CODE_DOES_NOT_MATCH, EndowConstants.INCOME); 548 549 isChartMatched = false; 550 } 551 return isChartMatched; 552 } 553 554 /** 555 * For a true endowment, when the END_TRAN_LN_T: TRAN_IP_IND_CD is equal to P, a warning message will be placed in the document 556 * transaction line notifying the viewer that the transaction will reduce the value of the endowment at the time the transaction 557 * line is added. WARNING: This transaction will reduce permanently restricted funds!. However, the transaction line would be 558 * added on successfully. 559 * 560 * @param line 561 * @return 562 */ 563 protected void checkWhetherReducePermanentlyRestrictedFund(EndowmentTransactionLine line, String prefix) { 564 String ipIndicatorCode = line.getTransactionIPIndicatorCode(); 565 String kemid = line.getKemid(); 566 if (EndowConstants.IncomePrincipalIndicator.PRINCIPAL.equalsIgnoreCase(ipIndicatorCode) && SpringContext.getBean(KEMIDService.class).isTrueEndowment(kemid)) { 567 GlobalVariables.getMessageMap().putWarning(prefix + EndowPropertyConstants.TRANSACTION_LINE_IP_INDICATOR_CODE, EndowKeyConstants.EndowmentTransactionDocumentConstants.WARNING_REDUCE_PERMANENTLY_RESTRICTED_FUNDS); 568 } 569 } 570 571 /** 572 * Upon adding the transaction line, the system will check to see if there are sufficient funds to process the transaction 573 * (END_AVAIL_CSH_T). If there are not, a warning message will be placed in the document transaction line notifying the viewer 574 * that there are not sufficient funds. -If END_TRAN_LN_T: TRAN_IP_IND_CD is equal to I verify against END_AVAIL_CSH_T: 575 * AVAIL_TOT_CSH -If END_TRAN_LN_T: TRAN_IP_IND_CD is equal to P verify against END_AVAIL_CSH_T: AVAIL_PRIN_CSH However, the 576 * transaction line would be added on successfully. 577 * 578 * @param line 579 * @return 580 */ 581 protected void checkWhetherHaveSufficientFundsForCashBasedTransaction(EndowmentTransactionLine line, String prefix) { 582 String ipIndicatorCode = line.getTransactionIPIndicatorCode(); 583 String kemid = line.getKemid(); 584 KualiDecimal amount = line.getTransactionAmount(); 585 586 Map criteria = new HashMap(); 587 criteria.put(EndowPropertyConstants.KEMID, kemid); 588 KEMIDCurrentAvailableBalance theKEMIDCurrentAvailableBalance = (KEMIDCurrentAvailableBalance) SpringContext.getBean(BusinessObjectService.class).findByPrimaryKey(KEMIDCurrentAvailableBalance.class, criteria); 589 590 if (ObjectUtils.isNotNull(theKEMIDCurrentAvailableBalance)) { 591 if (EndowConstants.IncomePrincipalIndicator.PRINCIPAL.equalsIgnoreCase(ipIndicatorCode)) { 592 if (amount.isGreaterThan(new KualiDecimal(theKEMIDCurrentAvailableBalance.getAvailablePrincipalCash()))) { 593 GlobalVariables.getMessageMap().putWarning(prefix + EndowPropertyConstants.TRANSACTION_LINE_IP_INDICATOR_CODE, EndowKeyConstants.EndowmentTransactionDocumentConstants.WARNING_NO_SUFFICIENT_FUNDS); 594 } 595 } 596 else { 597 if (amount.isGreaterThan(new KualiDecimal(theKEMIDCurrentAvailableBalance.getAvailableTotalCash()))) { 598 GlobalVariables.getMessageMap().putWarning(prefix + EndowPropertyConstants.TRANSACTION_LINE_IP_INDICATOR_CODE, EndowKeyConstants.EndowmentTransactionDocumentConstants.WARNING_NO_SUFFICIENT_FUNDS); 599 } 600 } 601 } 602 } 603 604 605 protected boolean templateMethod(EndowmentTransactionLine line) { 606 boolean success = true; 607 608 return success; 609 } 610 611 /** 612 * This methods checks to ensure for cash Tx do not have a Etran. 613 * 614 * @param endowmentTransactionLinesDocumentBase 615 * @param line 616 * @param prefix 617 * @return 618 */ 619 protected boolean checkCashTransactionEndowmentCode(EndowmentTransactionLinesDocument endowmentTransactionLinesDocument, EndowmentTransactionLine line, String prefix) { 620 // For Cash based Tx the Etran code must be empty,If Tx is Cash based, check for Etran code and if not null display Error 621 // message. 622 if (!nonCashTransaction(endowmentTransactionLinesDocument) && (!StringUtils.isEmpty(line.getEtranCode()))) { 623 // 624 putFieldError(prefix + EndowPropertyConstants.TRANSACTION_LINE_ENDOWMENT_TRANSACTION_CODE, EndowKeyConstants.EndowmentTransactionDocumentConstants.ERROR_TRANSACTION_LINE_ETRAN_BLANK); 625 return false; 626 } 627 628 return true; 629 } 630 631 /** 632 * Checks that the document has at least one transaction line. 633 * 634 * @param document 635 * @param isSource 636 * @return true if valid, false otherwise 637 */ 638 protected boolean transactionLineSizeGreaterThanZero(EndowmentTransactionLinesDocumentBase document, boolean isSource) { 639 List<EndowmentTransactionLine> transactionLineList = null; 640 if (isSource) { 641 transactionLineList = document.getSourceTransactionLines(); 642 if (transactionLineList == null || transactionLineList.size() == 0) { 643 putFieldError(EndowPropertyConstants.SOURCE_TRANSACTION_LINE_PREFIX, EndowKeyConstants.EndowmentTransactionDocumentConstants.ERROR_FROM_TRANSACTION_LINE_COUNT_INSUFFICIENT); 644 return false; 645 } 646 } 647 else { 648 transactionLineList = document.getTargetTransactionLines(); 649 if (transactionLineList == null || transactionLineList.size() == 0) { 650 putFieldError(EndowPropertyConstants.TARGET_TRANSACTION_LINE_PREFIX, EndowKeyConstants.EndowmentTransactionDocumentConstants.ERROR_TO_TRANSACTION_LINE_COUNT_INSUFFICIENT); 651 return false; 652 } 653 } 654 655 return true; 656 } 657 658 /** 659 * This method is a collection if validation performed on Registration Code. The validations are not null & valid registration 660 * code 661 * 662 * @param isValid 663 * @param liabilityIncreaseDocument 664 * @return 665 */ 666 protected boolean validateRegistration(boolean isValid, EndowmentSecurityDetailsDocumentBase document, boolean isSource) { 667 // Checks if registration code is empty 668 if (isRegistrationCodeEmpty(document, isSource)) 669 return false; 670 671 // Validate Registration code. 672 if (!validateRegistrationCode(document, isSource)) 673 return false; 674 675 // Checks if registration code is active 676 isValid &= isRegistrationCodeActive(document, isSource); 677 return isValid; 678 } 679 680 /** 681 * This method is a collection if validation performed on Security. The validations are not null, valid security,active & class 682 * code matches L 683 * 684 * @param isValid 685 * @param document 686 * @return 687 */ 688 protected boolean validateSecurity(boolean isValid, EndowmentSecurityDetailsDocumentBase document, boolean isSource) { 689 // Checks if Security Code is empty. 690 if (isSecurityCodeEmpty(document, isSource)) 691 return false; 692 693 // Validates Security Code. 694 if (!validateSecurityCode(document, isSource)) 695 return false; 696 697 // Checks if Security is Active 698 isValid &= isSecurityActive(document, isSource); 699 700 // Validates Security class code 701 isValid &= validateSecurityClassTypeCode(document, isSource, EndowConstants.ClassCodeTypes.LIABILITY); 702 return isValid; 703 } 704 705 /** 706 * This method validates that the source and target security lines are different from each other. 707 * 708 * @param document 709 * @return True if source and target security codes are different 710 */ 711 protected boolean validateNonDuplicateSecurityCodes(EndowmentSecurityDetailsDocumentBase document) { 712 713 Security sourceSecurity = getSecurityForValidation(document, true); 714 Security targetSecurity = getSecurityForValidation(document, false); 715 716 if (sourceSecurity != null && targetSecurity != null) { 717 if (sourceSecurity.getId().equalsIgnoreCase(targetSecurity.getId())) { 718 putFieldError(getEndowmentTransactionSecurityPrefix(document, false) + EndowPropertyConstants.TRANSACTION_SECURITY_ID, EndowKeyConstants.EndowmentTransactionDocumentConstants.ERROR_TRANSACTION_SECURITY_CODE_EQUAL); 719 } 720 } 721 722 return true; 723 } 724 725 /** 726 * Validates that the KEMID has sufficient units in the tax lots to perform the transaction. 727 * 728 * @param endowmentTransactionLinesDocumentBase 729 * @param line 730 * @param index 731 * @return true if valid, false otherwise 732 */ 733 public boolean validateSufficientUnits(boolean isAdd, EndowmentTransactionLinesDocument endowmentTransactionLinesDocument, EndowmentTransactionLine line, int transLineIndex, int taxLotIndex) { 734 EndowmentTransactionSecurity endowmentTransactionSecurity = getEndowmentTransactionSecurity(endowmentTransactionLinesDocument, true); 735 boolean isValid = true; 736 List<HoldingTaxLot> holdingTaxLots = new ArrayList<HoldingTaxLot>(); 737 738 if (isAdd) { 739 holdingTaxLots = SpringContext.getBean(HoldingTaxLotService.class).getAllTaxLots(line.getKemid(), endowmentTransactionSecurity.getSecurityID(), endowmentTransactionSecurity.getRegistrationCode(), line.getTransactionIPIndicatorCode()); 740 } 741 else { 742 List<EndowmentTransactionTaxLotLine> existingTransactionLines = line.getTaxLotLines(); 743 for (int i = 0; i < existingTransactionLines.size(); i++) { 744 // don't take into account the tax lot line we are now deleting 745 if (i != taxLotIndex) { 746 747 EndowmentTransactionTaxLotLine endowmentTransactionTaxLotLine = (EndowmentTransactionTaxLotLine) existingTransactionLines.get(i); 748 HoldingTaxLot holdingTaxLot = SpringContext.getBean(HoldingTaxLotService.class).getByPrimaryKey(line.getKemid(), endowmentTransactionSecurity.getSecurityID(), endowmentTransactionSecurity.getRegistrationCode(), endowmentTransactionTaxLotLine.getTransactionHoldingLotNumber(), line.getTransactionIPIndicatorCode()); 749 750 if (ObjectUtils.isNotNull(holdingTaxLot)) { 751 holdingTaxLots.add(holdingTaxLot); 752 } 753 } 754 } 755 } 756 757 BigDecimal totalTaxLotsUnits = BigDecimal.ZERO; 758 759 if (holdingTaxLots != null && holdingTaxLots.size() > 0) { 760 for (HoldingTaxLot holdingTaxLot : holdingTaxLots) { 761 totalTaxLotsUnits = totalTaxLotsUnits.add(holdingTaxLot.getUnits()); 762 } 763 } 764 765 BigDecimal lineUnits = null; 766 lineUnits = line.getTransactionUnits().bigDecimalValue(); 767 768 if (lineUnits.compareTo(totalTaxLotsUnits) == 1) { 769 isValid = false; 770 putFieldError(getErrorPrefix(line, transLineIndex) + EndowPropertyConstants.TRANSACTION_LINE_TRANSACTION_UNITS, EndowKeyConstants.EndowmentTransactionDocumentConstants.ERROR_ASSET_DECREASE_INSUFFICIENT_UNITS); 771 } 772 return isValid; 773 } 774 775 /** 776 * Validates that the tax lots for a transaction line correspond to the information in that transaction line. It might be 777 * possible that the user has changed the KEMID or Security related data without refreshing the tax lot lines. On save we need 778 * to check that the tax lot lines relate to the KEMID in the transaction lines. Take the first tax lot for the transaction line 779 * and check if it is in the holding tax lots for that KEMID. This validation is needed in documents that support tax lot lines 780 * deletion as in that case the tax lot lines are not automatically refreshed on save/submit. 781 * 782 * @param endowmentTransactionLinesDocument 783 * @param transLine 784 * @param transLineIndex 785 * @return 786 */ 787 protected boolean validateTaxLots(EndowmentTransactionLinesDocument endowmentTransactionLinesDocument, EndowmentTransactionLine transLine, int transLineIndex) { 788 boolean isValid = true; 789 790 EndowmentTransactionSecurity endowmentTransactionSecurity = getEndowmentTransactionSecurity(endowmentTransactionLinesDocument, true); 791 792 // as it might be possible that the user has changed the KEMID without refreshing the tax lot lines, on save we need to 793 // check that the tax lot lines relate to the KEMID in the transaction lines. Take the first tax lot for the transaction 794 // line and check if it is in the holding tax lots for that KEMID. 795 if (transLine.getTaxLotLines() != null && transLine.getTaxLotLines().size() > 0) { 796 EndowmentTransactionTaxLotLine transactionTaxLotLine = transLine.getTaxLotLines().get(0); 797 798 boolean isMatchingSecurity = endowmentTransactionSecurity.getSecurityID().equalsIgnoreCase(transactionTaxLotLine.getSecurityID()); 799 boolean isMatchingRegistrationCode = endowmentTransactionSecurity.getRegistrationCode().equalsIgnoreCase(transactionTaxLotLine.getRegistrationCode()); 800 boolean isMatchingKemid = transLine.getKemid().equalsIgnoreCase(transactionTaxLotLine.getKemid()); 801 boolean isMatchingIpIndicator = transLine.getTransactionIPIndicatorCode().equalsIgnoreCase(transactionTaxLotLine.getIpIndicator()); 802 803 if (!isMatchingSecurity || !isMatchingRegistrationCode || !isMatchingKemid || !isMatchingIpIndicator) { 804 isValid = false; 805 putFieldError(getErrorPrefix(transLine, transLineIndex) + EndowPropertyConstants.KEMID, EndowKeyConstants.EndowmentTransactionDocumentConstants.ERROR_TRANSACTION_LINE_TAX_LOT_DONT_CORRESPOND); 806 } 807 808 } 809 return isValid; 810 } 811 812 /** 813 * Checks that the transaction line units match the tax lot lines total number of units. 814 * 815 * @param document 816 * @param transactionLine 817 * @param index 818 * @return true if valid, false otherwise 819 */ 820 protected boolean validateTotalUnits(EndowmentTransactionalDocument document, EndowmentTransactionLine transactionLine, int index) { 821 boolean isValid = true; 822 823 BigDecimal transactionLineUnits = transactionLine.getTransactionUnits().bigDecimalValue(); 824 BigDecimal taxLotLinesTotalUnits = BigDecimal.ZERO; 825 826 if (transactionLine.getTaxLotLines() != null && transactionLine.getTaxLotLines().size() > 0) { 827 828 for (EndowmentTransactionTaxLotLine taxLotLine : transactionLine.getTaxLotLines()) { 829 taxLotLinesTotalUnits = taxLotLinesTotalUnits.add(taxLotLine.getLotUnits()); 830 } 831 } 832 833 if (transactionLine instanceof EndowmentSourceTransactionLine) { 834 taxLotLinesTotalUnits = taxLotLinesTotalUnits.negate(); 835 } 836 837 if (transactionLineUnits.compareTo(taxLotLinesTotalUnits) != 0) { 838 isValid = false; 839 840 putFieldError(getErrorPrefix(transactionLine, index) + EndowPropertyConstants.TRANSACTION_LINE_TRANSACTION_UNITS, EndowKeyConstants.EndowmentTransactionDocumentConstants.ERROR_TRANSACTION_LINE_TAX_LOT_UNITS_DONT_CORRESPOND); 841 } 842 843 return isValid; 844 } 845 846 847 /** 848 * This method Check if value of Endowment is being reduced. 849 * 850 * @param endowmentTransactionLinesDocumentBase 851 * @param line 852 * @param ERRORPREFIX 853 * @return 854 */ 855 /* 856 * protected boolean checkEndowmentValueReduction(EndowmentTransactionLinesDocument endowmentTransactionLinesDocument, 857 * EndowmentTransactionLine line, String ERRORPREFIX) { if( 858 * EndowConstants.IncomePrincipalIndicator.PRINCIPAL.equalsIgnoreCase(line.getTransactionIPIndicatorCode()) ) { 859 * line.getKemidObj().refreshNonUpdateableReferences(); line.getKemidObj().getType().refreshNonUpdateableReferences(); 860 * if(line.getKemidObj().getTypeRestrictionCodeForPrincipalRestrictionCode().getPermanentIndicator()) { 861 * GlobalVariables.getMessageMap().putWarningWithoutFullErrorPath(EndowConstants.ENDOWMENT_TRANSACTION_LINE_ERRORS, 862 * EndowKeyConstants.EndowmentTransactionDocumentConstants.WARNING_TRANSACTION_LINE_ENDOWMENT_VALUE_REDUCTION); return false; } 863 * } return true; } 864 */ 865 866 /** 867 * This method validates if the source & target units are equal. 868 * 869 * @param securityTransferDocument 870 * @return 871 */ 872 protected boolean validateSourceTargetUnitsEqual(SecurityTransferDocument securityTransferDocument) { 873 if (!securityTransferDocument.getTargetTotalUnits().equals(securityTransferDocument.getSourceTotalUnits())) { 874 GlobalVariables.getMessageMap().putErrorWithoutFullErrorPath(EndowConstants.TRANSACTION_LINE_ERRORS, EndowKeyConstants.EndowmentTransactionDocumentConstants.ERROR_TRANSACTION_LINE_SOURCE_TARGET_UNITS_EQUAL); 875 return false; 876 } 877 878 return true; 879 } 880 881 /** 882 * This method validates if the source & target units are equal. 883 * 884 * @param securityTransferDocument 885 * @return 886 */ 887 protected boolean validateSourceTargetAmountEqual(SecurityTransferDocument securityTransferDocument) { 888 if (!securityTransferDocument.getTargetTotalAmount().equals(securityTransferDocument.getSourceTotalAmount())) { 889 GlobalVariables.getMessageMap().putErrorWithoutFullErrorPath(EndowConstants.TRANSACTION_LINE_ERRORS, EndowKeyConstants.EndowmentTransactionDocumentConstants.ERROR_TRANSACTION_LINE_SOURCE_TARGET_AMOUNT_EQUAL); 890 return false; 891 } 892 893 return true; 894 } 895 896 }