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 }