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.List;
020
021 import org.apache.commons.lang.StringUtils;
022 import org.kuali.kfs.module.endow.EndowConstants;
023 import org.kuali.kfs.module.endow.EndowKeyConstants;
024 import org.kuali.kfs.module.endow.EndowPropertyConstants;
025 import org.kuali.kfs.module.endow.businessobject.ClassCode;
026 import org.kuali.kfs.module.endow.businessobject.EndowmentTransactionCode;
027 import org.kuali.kfs.module.endow.businessobject.FeeClassCode;
028 import org.kuali.kfs.module.endow.businessobject.FeeEndowmentTransactionCode;
029 import org.kuali.kfs.module.endow.businessobject.FeeMethod;
030 import org.kuali.kfs.module.endow.businessobject.FeePaymentType;
031 import org.kuali.kfs.module.endow.businessobject.FeeSecurity;
032 import org.kuali.kfs.module.endow.businessobject.FeeTransaction;
033 import org.kuali.kfs.module.endow.businessobject.Security;
034 import org.kuali.kfs.module.endow.document.service.ClassCodeService;
035 import org.kuali.kfs.module.endow.document.service.EndowmentTransactionCodeService;
036 import org.kuali.kfs.module.endow.document.service.FeeMethodService;
037 import org.kuali.kfs.module.endow.document.service.SecurityService;
038 import org.kuali.kfs.sys.context.SpringContext;
039 import org.kuali.rice.kns.bo.PersistableBusinessObject;
040 import org.kuali.rice.kns.document.Document;
041 import org.kuali.rice.kns.document.MaintenanceDocument;
042 import org.kuali.rice.kns.maintenance.rules.MaintenanceDocumentRuleBase;
043 import org.kuali.rice.kns.rule.event.ApproveDocumentEvent;
044 import org.kuali.rice.kns.util.GlobalVariables;
045 import org.kuali.rice.kns.util.KNSConstants;
046 import org.kuali.rice.kns.util.KualiDecimal;
047 import org.kuali.rice.kns.util.MessageMap;
048 import org.kuali.rice.kns.util.ObjectUtils;
049
050 public class FeeMethodRule extends MaintenanceDocumentRuleBase {
051
052 /**
053 * @see org.kuali.rice.kns.maintenance.rules.MaintenanceDocumentRule#processRouteDocument(org.kuali.rice.kns.document.Document)
054 */
055 @Override
056 public boolean processRouteDocument(Document document) {
057 boolean isValid = true;
058 isValid &= super.processRouteDocument(document);
059 MessageMap errorMap = GlobalVariables.getMessageMap();
060 isValid &= errorMap.hasNoErrors();
061
062 if (!isValid) {
063 return isValid;
064 }
065
066 isValid &= validationRulesPassedForFeeMethod(document);
067
068 return isValid;
069 }
070
071 /**
072 * @see org.kuali.rice.kns.maintenance.rules.MaintenanceDocumentRule#processApproveDocument(ApproveDocumentEvent)
073 */
074 @Override
075 public boolean processApproveDocument(ApproveDocumentEvent approveEvent) {
076 boolean isValid = true;
077 isValid &= super.processApproveDocument(approveEvent);
078 MessageMap errorMap = GlobalVariables.getMessageMap();
079 isValid &= errorMap.hasNoErrors();
080
081 if (!isValid) {
082 return isValid;
083 }
084
085 Document document = (Document) approveEvent.getDocument();
086 isValid &= validationRulesPassedForFeeMethod(document);
087
088 return isValid;
089 }
090
091 /**
092 * This method will validate the custom business rules for fee method
093 *
094 * @param feeMethod
095 * @return true if rules are passed else return false
096 */
097 private boolean validationRulesPassedForFeeMethod(Document document) {
098 boolean rulesPassed = true;
099
100 MaintenanceDocument maintenanceDocument = (MaintenanceDocument) document;
101 FeeMethod feeMethod = (FeeMethod) maintenanceDocument.getNewMaintainableObject().getBusinessObject();
102
103 rulesPassed &= checkFeeTransactionTypeCodeValue(feeMethod); // rule #2
104 rulesPassed &= recordExistsInFeeTransactionType(feeMethod); // rule #3
105 rulesPassed &= recordExistsInFeeEndowmentTransactionType(feeMethod); // rule #4
106 rulesPassed &= checkFeeBalanceTypeCodeValue(feeMethod); // rule #5
107 rulesPassed &= recordExistsInFeeClassCode(feeMethod); // rule #6
108 rulesPassed &= recordExistsInFeeSecurity(feeMethod); // rule #7
109 rulesPassed &= checkFeePaymentTypeCodeValue(feeMethod); // rule #8
110 rulesPassed &= recordExistsInFeePaymentType(feeMethod); // rule #9
111 rulesPassed &= checkRateDefinitionAndFeeBalanceTypes(feeMethod); // rule #12 and rule#14
112 rulesPassed &= recordExistsInEndowmentTransactionCode(feeMethod); // rule #12 and rule#14
113 rulesPassed &= checkCorpusToMarketTolerance(feeMethod); // rule #16
114 rulesPassed &= checkFeeRateAndBreakpointAmounts(feeMethod); // rule #17, rule #18, rule #19
115 rulesPassed &= validFeeTransactionTypeEntered(feeMethod); // rule #20
116 rulesPassed &= checkFrequencyCodeNotChangedIfFeeMethodUsedOnAnyKemid(document);
117 rulesPassed &= validFeeExpenseETranCodeEntered(feeMethod); //new rule added by Norm. Per KULENDOW-564
118
119 return rulesPassed;
120 }
121
122 /**
123 * This method will check that if Fee By Transaction Type or Fee By ETran Code or both set to Y and Fee Type is set to T.
124 *
125 * @param feeMethod
126 * @return true if Fee By Transaction Type field or Fee By ETran Code field or both set to Y AND fee type code is T else return
127 * false
128 */
129 private boolean checkFeeTransactionTypeCodeValue(FeeMethod feeMethod) {
130 boolean isValidTransactionCode = true;
131
132 if (feeMethod.getFeeByTransactionType() || feeMethod.getFeeByETranCode()) {
133 if (ObjectUtils.isNotNull(feeMethod.getFeeTypeCode()) && !EndowConstants.FeeMethod.FEE_TYPE_CODE_VALUE_FOR_TRANSACTIONS.equalsIgnoreCase(feeMethod.getFeeTypeCode())) {
134 putFieldError(EndowPropertyConstants.FEE_TYPE_CODE, EndowKeyConstants.FeeMethodConstants.ERROR_INVALID_FEE_TYPE_CODE_FOR_TRANSACTIONS_ENTERED);
135 return false;
136 }
137 }
138
139 return isValidTransactionCode;
140 }
141
142 /**
143 * This method will check that if Fee By Class Code or Fee By Security or both set to Yes and Fee Type is set to B.
144 *
145 * @param feeMethod
146 * @return true if Fee By Transaction Type field or Fee By ETran Code field or both set to Y AND fee type code is B else return
147 * false
148 */
149 private boolean checkFeeBalanceTypeCodeValue(FeeMethod feeMethod) {
150 boolean isValidTransactionCode = true;
151
152 if (feeMethod.getFeeByClassCode() || feeMethod.getFeeBySecurityCode()) {
153 if (ObjectUtils.isNotNull(feeMethod.getFeeTypeCode()) && !EndowConstants.FeeMethod.FEE_TYPE_CODE_VALUE_FOR_BALANCES.equalsIgnoreCase(feeMethod.getFeeTypeCode())) {
154 putFieldError(EndowPropertyConstants.FEE_TYPE_CODE, EndowKeyConstants.FeeMethodConstants.ERROR_INVALID_FEE_TYPE_CODE_FOR_BALANCE_ENTERED);
155 return false;
156 }
157 }
158
159 return isValidTransactionCode;
160 }
161
162 /**
163 * This method will check that if Fee Type is set to value P then fee base code should be I
164 *
165 * @param feeMethod
166 * @return true if Fee Type is P and Fee Base code is I else return false
167 */
168 private boolean checkFeePaymentTypeCodeValue(FeeMethod feeMethod) {
169 boolean isValidBaseCode = true;
170
171 if (ObjectUtils.isNotNull(feeMethod.getFeeTypeCode()) && EndowConstants.FeeMethod.FEE_TYPE_CODE_VALUE_FOR_PAYMENTS.equalsIgnoreCase(feeMethod.getFeeTypeCode())) {
172 if (!EndowConstants.FeeMethod.FEE_BASE_CD_VALUE.equalsIgnoreCase(feeMethod.getFeeBaseCode())) {
173 putFieldError(EndowPropertyConstants.FEE_BASE_CODE, EndowKeyConstants.FeeMethodConstants.ERROR_INVALID_FEE_BASE_CODE_FOR_PAYMENTS_ENTERED);
174 return false;
175 }
176 }
177
178 return isValidBaseCode;
179 }
180
181 /**
182 * This method will check if at least one record exists in Fee Transaction Type collection with INCL checked on when Fee
183 * Transaction Type Code is checked on
184 *
185 * @param feeMethod
186 * @return true if Fee Transaction Type code checked on and at least one record with INCL flag is checked on else return false
187 */
188 private boolean recordExistsInFeeTransactionType(FeeMethod feeMethod) {
189 boolean recordExists = false;
190
191 List<FeeTransaction> feeTransactions = (List<FeeTransaction>) feeMethod.getFeeTransactions();
192
193 for (FeeTransaction feeTransactionsRecord : feeTransactions) {
194 if (feeTransactionsRecord.getInclude()) {
195 recordExists = true;
196 break;
197 }
198 }
199
200 if (feeMethod.getFeeByTransactionType()) {
201 if (!recordExists) {
202 putFieldError(EndowPropertyConstants.FEE_BY_TRANSACTION_TYPE_CODE, EndowKeyConstants.FeeMethodConstants.ERROR_NO_RECORDS_WITH_YES_IN_FEE_TRANSACTION_TYPE);
203 return false;
204 }
205 }
206 //However, If Fee Transaction Type code is not checked, there can be no records in END_FEE_TRAN_DOC_TYP_T with the field INCL set to Yes
207 else {
208 if (recordExists) {
209 putFieldError(EndowPropertyConstants.FEE_BY_TRANSACTION_TYPE_CODE, EndowKeyConstants.FeeMethodConstants.ERROR_RECORDS_WITH_YES_IN_FEE_TRANSACTION_TYPE);
210 return false;
211 }
212 }
213
214 return true;
215 }
216
217 /**
218 * This method will check if at least one record exists in Fee Class Codes collection with INCL checked on when Fee Class code
219 * is checked on.
220 *
221 * @param feeMethod
222 * @return true if Fee Class code is checked on and at least one record with INCL flag is checked on else return false
223 */
224 private boolean recordExistsInFeeClassCode(FeeMethod feeMethod) {
225 boolean recordExists = false;
226
227 List<FeeClassCode> feeClassCodes = (List<FeeClassCode>) feeMethod.getFeeClassCodes();
228
229 for (FeeClassCode feeClassCodeRecord : feeClassCodes) {
230 if (feeClassCodeRecord.getInclude()) {
231 recordExists = true;
232 break;
233 }
234 }
235
236 if (feeMethod.getFeeByClassCode()) {
237 if (!recordExists) {
238 putFieldError(EndowPropertyConstants.FEE_BY_CLASS_CODE, EndowKeyConstants.FeeMethodConstants.ERROR_NO_RECORDS_WITH_YES_IN_FEE_CLASS_CODE);
239 return false;
240 }
241 }
242 else {
243 if (recordExists) {
244 putFieldError(EndowPropertyConstants.FEE_BY_CLASS_CODE, EndowKeyConstants.FeeMethodConstants.ERROR_RECORDS_WITH_YES_IN_FEE_CLASS_CODE);
245 return false;
246 }
247 }
248
249 return true;
250 }
251
252 /**
253 * This method will check if at least one record exists in Fee Endowment Transaction Codes collection with INCL checked on when
254 * Fee Endowment Transaction Code is checked on.
255 *
256 * @param feeMethod
257 * @return true if Fee EndowmentTransaction Type is checked on and at least one record with INCL flag is checked on else return
258 * false
259 */
260 private boolean recordExistsInFeeEndowmentTransactionType(FeeMethod feeMethod) {
261 boolean recordExists = false;
262
263 List<FeeEndowmentTransactionCode> feeEndowmentTransactionCodes = (List<FeeEndowmentTransactionCode>) feeMethod.getFeeEndowmentTransactionCodes();
264
265 for (FeeEndowmentTransactionCode feeEndowmentTransactionCodesRecord : feeEndowmentTransactionCodes) {
266 if (feeEndowmentTransactionCodesRecord.getInclude()) {
267 recordExists = true;
268 break;
269 }
270 }
271
272 if (feeMethod.getFeeByETranCode()) {
273 if (!recordExists) {
274 putFieldError(EndowPropertyConstants.FEE_BY_ENDOWMENT_TRANSACTION_TYPE_CODE, EndowKeyConstants.FeeMethodConstants.ERROR_NO_RECORDS_WITH_YES_IN_FEE_ENDOWMENT_TRANSACTION_CODE);
275 return false;
276 }
277 }
278 //However, If etran code is not checked, there can be no records in etrancode table with the field INCL set to Yes
279 else {
280 if (recordExists) {
281 putFieldError(EndowPropertyConstants.FEE_BY_ENDOWMENT_TRANSACTION_TYPE_CODE, EndowKeyConstants.FeeMethodConstants.ERROR_RECORDS_WITH_YES_IN_FEE_ENDOWMENT_TRANSACTION_CODE);
282 return false;
283 }
284 }
285
286 return true;
287 }
288
289 /**
290 * This method will check if at least one record exists in Fee Security collection with INCL checked on when Fee Class Code is
291 * checked on.
292 *
293 * @param feeMethod
294 * @return true if Fee Security Code is checked on and at least one record with INCL flag is checked on else return false
295 */
296 private boolean recordExistsInFeeSecurity(FeeMethod feeMethod) {
297 boolean recordExists = false;
298 List<FeeSecurity> feeSecurity = (List<FeeSecurity>) feeMethod.getFeeSecurity();
299
300 for (FeeSecurity feeSecurityRecord : feeSecurity) {
301 if (feeSecurityRecord.getInclude()) {
302 recordExists = true;
303 break;
304 }
305 }
306
307 if (feeMethod.getFeeBySecurityCode()) {
308 if (!recordExists) {
309 putFieldError(EndowPropertyConstants.FEE_BY_SECURITY_CODE, EndowKeyConstants.FeeMethodConstants.ERROR_NO_RECORDS_WITH_YES_IN_FEE_SECURITY_CODE);
310 return false;
311 }
312 }
313 else {
314 if (recordExists) {
315 putFieldError(EndowPropertyConstants.FEE_BY_ENDOWMENT_TRANSACTION_TYPE_CODE, EndowKeyConstants.FeeMethodConstants.ERROR_RECORDS_WITH_YES_IN_FEE_SECURITY_CODE);
316 return false;
317 }
318 }
319
320 return true;
321 }
322
323 /**
324 * This method will check if at least one record exists in Fee Payment Type collection with INCL checked on when Fee Type Code
325 * is checked on.
326 *
327 * @param feeMethod
328 * @return true if at least one record with INCL flag is checked on else return false
329 */
330 private boolean recordExistsInFeePaymentType(FeeMethod feeMethod) {
331 boolean recordExists = true;
332
333 if (ObjectUtils.isNotNull(feeMethod.getFeeTypeCode()) && EndowConstants.FeeMethod.FEE_TYPE_CODE_VALUE_FOR_PAYMENTS.equalsIgnoreCase(feeMethod.getFeeTypeCode())) {
334 recordExists = false;
335 List<FeePaymentType> feePaymentTypes = (List<FeePaymentType>) feeMethod.getFeePaymentTypes();
336
337 for (FeePaymentType feePaymentTypeRecord : feePaymentTypes) {
338 if (feePaymentTypeRecord.getInclude()) {
339 recordExists = true;
340 break;
341 }
342 }
343
344 if (!recordExists) {
345 putFieldError(EndowPropertyConstants.FEE_BASE_CODE, EndowKeyConstants.FeeMethodConstants.ERROR_NO_RECORDS_WITH_YES_IN_FEE_PAYMENT_TYPE);
346 }
347 }
348
349 return recordExists;
350 }
351
352 /**
353 * This method will check rate definition and fee balance types based on fee type code
354 *
355 * @param feeMethod
356 * @return true if ((rate definition is C AND fee type code is B AND fee balances types are AU or CU and/or MU) or (rate
357 * definition is V AND fee type code is B AND fee balances types are AMV or CMV and/or MMV)) else return false
358 */
359 private boolean checkRateDefinitionAndFeeBalanceTypes(FeeMethod feeMethod) {
360 boolean isValid = true;
361
362 String feeRateDefinitionCode = feeMethod.getFeeRateDefinitionCode();
363
364 if (ObjectUtils.isNotNull(feeRateDefinitionCode)) {
365 // if rate definition is C and type fee code is B
366 if (EndowConstants.FeeMethod.FEE_RATE_DEFINITION_CODE_FOR_COUNT.equalsIgnoreCase(feeRateDefinitionCode) && EndowConstants.FeeMethod.FEE_TYPE_CODE_VALUE_FOR_BALANCES.equalsIgnoreCase(feeMethod.getFeeTypeCode())) {
367 String feeBalanceTypeCode = feeMethod.getFeeBalanceTypeCode();
368
369 if (!EndowConstants.FeeBalanceTypes.FEE_BALANCE_TYPE_VALUE_FOR_AVERAGE_UNITS.equalsIgnoreCase(feeBalanceTypeCode) && !EndowConstants.FeeBalanceTypes.FEE_BALANCE_TYPE_VALUE_FOR_CURRENT_UNITS.equalsIgnoreCase(feeBalanceTypeCode) && !EndowConstants.FeeBalanceTypes.FEE_BALANCE_TYPE_VALUE_FOR_MONTH_END_UNITS.equalsIgnoreCase(feeBalanceTypeCode)) {
370 putFieldError(EndowPropertyConstants.FEE_BALANCE_TYPES_CODE, EndowKeyConstants.FeeMethodConstants.ERROR_INVALID_FEE_BALANCE_TYPE_CODE_WHEN_COUNT_ENTERED);
371 return false;
372 }
373 }
374
375 // if rate definition is V and type fee code is B
376 if (EndowConstants.FeeMethod.FEE_RATE_DEFINITION_CODE_FOR_VALUE.equalsIgnoreCase(feeRateDefinitionCode) && EndowConstants.FeeMethod.FEE_TYPE_CODE_VALUE_FOR_BALANCES.equalsIgnoreCase(feeMethod.getFeeTypeCode())) {
377 String feeBalanceTypeCode = feeMethod.getFeeBalanceTypeCode();
378
379 if (!EndowConstants.FeeBalanceTypes.FEE_BALANCE_TYPE_VALUE_FOR_AVERAGE_MARKET_VALUE.equalsIgnoreCase(feeBalanceTypeCode) && !EndowConstants.FeeBalanceTypes.FEE_BALANCE_TYPE_VALUE_FOR_CURRENT_MARKET_VALUE.equalsIgnoreCase(feeBalanceTypeCode) && !EndowConstants.FeeBalanceTypes.FEE_BALANCE_TYPE_VALUE_FOR_MONTH_END_MARKET_VALUE.equalsIgnoreCase(feeBalanceTypeCode)) {
380 putFieldError(EndowPropertyConstants.FEE_BALANCE_TYPES_CODE, EndowKeyConstants.FeeMethodConstants.ERROR_INVALID_FEE_BALANCE_TYPE_CODE_WHEN_VALUE_ENTERED);
381 return false;
382 }
383 }
384 }
385
386 return isValid;
387 }
388
389 /**
390 * This method will check if record exists in Endowment Transaction Code table
391 *
392 * @param feeMethod feeMethod object
393 * @return true if Fee Endowment Transaction code exists else return false
394 */
395 private boolean recordExistsInEndowmentTransactionCode(FeeMethod feeMethod) {
396 boolean recordExists = true;
397
398 String endowmentTransactionCode = feeMethod.getFeeExpenseETranCode();
399
400 EndowmentTransactionCodeService endowmentTransactionCodeService = SpringContext.getBean(EndowmentTransactionCodeService.class);
401 EndowmentTransactionCode endowmentTransaction = endowmentTransactionCodeService.getByPrimaryKey(endowmentTransactionCode.toUpperCase());
402
403 if (ObjectUtils.isNull(endowmentTransaction)) {
404 putFieldError(EndowPropertyConstants.FEE_ENDOWMENT_TRANSACTION_TYPE_CODE_ATTRIBUTE, EndowKeyConstants.FeeMethodConstants.ERROR_NO_RECORD_IN_ENDOWMENT_TRANSACTION_CODE);
405 return false;
406 }
407
408 return recordExists;
409 }
410
411 /**
412 * This method will check that if corpus to market tolerance is 0 or > 1
413 *
414 * @param feeMethod
415 * @return true if corpus to market tolerance is 0 (default) or > 1.00 else return false
416 */
417 private boolean checkCorpusToMarketTolerance(FeeMethod feeMethod) {
418 boolean isValid = true;
419
420 if (ObjectUtils.isNotNull(feeMethod.getCorpusPctTolerance())) {
421 KualiDecimal corputPctToTolerance = feeMethod.getCorpusPctTolerance();
422 if (corputPctToTolerance.isLessThan(KualiDecimal.ZERO)) {
423 putFieldError(EndowPropertyConstants.CORPUS_TO_PCT_TOLERANCE, EndowKeyConstants.FeeMethodConstants.ERROR_CORPUS_PCT_TO_TOLERANCE_NEGATIVE);
424 return false;
425 }
426 if (!corputPctToTolerance.isZero() && !corputPctToTolerance.isGreaterThan(new KualiDecimal("1.0"))) {
427 putFieldError(EndowPropertyConstants.CORPUS_TO_PCT_TOLERANCE, EndowKeyConstants.FeeMethodConstants.ERROR_CORPUS_PCT_TO_TOLERANCE_MUST_BE_GREATER_THAN_ONE);
428 return false;
429 }
430 }
431
432 return isValid;
433 }
434
435 /**
436 * This method will check the fee rate and fee rate breakpoints
437 *
438 * @param feeMethod
439 * @return true fee rate and fee rate breakpoints pass the validations else return false
440 */
441 private boolean checkFeeRateAndBreakpointAmounts(FeeMethod feeMethod) {
442 boolean isValid = true;
443
444 // no negative values for first, second, and third rate fields
445 if (feeMethod.getFirstFeeRate().compareTo(BigDecimal.ZERO) == -1) {
446 putFieldError(EndowPropertyConstants.FIRST_FEE_RATE, EndowKeyConstants.FeeMethodConstants.ERROR_FIRST_FEE_RATE_CAN_NOT_BE_NEGATIVE);
447 return false;
448 }
449 if (feeMethod.getSecondFeeRate().compareTo(BigDecimal.ZERO) == -1) {
450 putFieldError(EndowPropertyConstants.SECOND_FEE_RATE, EndowKeyConstants.FeeMethodConstants.ERROR_SECOND_FEE_RATE_CAN_NOT_BE_NEGATIVE);
451 return false;
452 }
453
454 if (feeMethod.getThirdFeeRate().compareTo(BigDecimal.ZERO) == -1) {
455 putFieldError(EndowPropertyConstants.THIRD_FEE_RATE, EndowKeyConstants.FeeMethodConstants.ERROR_THIRD_FEE_RATE_CAN_NOT_BE_NEGATIVE);
456 return false;
457 }
458
459 // no negative values for first, second fee breakpoint values.
460 if (feeMethod.getFirstFeeBreakpoint().isLessThan(KualiDecimal.ZERO)) {
461 putFieldError(EndowPropertyConstants.FIRST_FEE_BREAK_POINT, EndowKeyConstants.FeeMethodConstants.ERROR_FIRST_FEE_BREAK_POINT_MUST_BE_GREATER_THAN_OR_ZERO);
462 return false;
463 }
464
465 if (feeMethod.getSecondFeeBreakpoint().isLessThan(KualiDecimal.ZERO)) {
466 putFieldError(EndowPropertyConstants.SECOND_FEE_BREAK_POINT, EndowKeyConstants.FeeMethodConstants.ERROR_SECOND_FEE_BREAK_POINT_MUST_BE_GREATER_THAN_OR_ZERO);
467 return false;
468 }
469
470 if (feeMethod.getFirstFeeBreakpoint().isLessThan(EndowConstants.FeeMethod.FEE_RATE_DEFAULT_VALUE) && feeMethod.getSecondFeeRate().compareTo(BigDecimal.ZERO) == 0) {
471 putFieldError(EndowPropertyConstants.SECOND_FEE_RATE, EndowKeyConstants.FeeMethodConstants.ERROR_SECOND_FEE_RATE_MUST_BE_GREATER_THAN_OR_ZERO);
472 return false;
473 }
474
475 if (feeMethod.getSecondFeeRate().compareTo(BigDecimal.ZERO) == 1 && feeMethod.getFirstFeeBreakpoint().isGreaterEqual(feeMethod.getSecondFeeBreakpoint())) {
476 putFieldError(EndowPropertyConstants.FIRST_FEE_BREAK_POINT, EndowKeyConstants.FeeMethodConstants.ERROR_FIRST_FEE_BREAK_POINT_MUST_BE_LESS_THAN_SECOND_FEE_BREAK_POINT);
477 return false;
478 }
479
480 if (feeMethod.getThirdFeeRate().compareTo(BigDecimal.ZERO) == 1 && feeMethod.getSecondFeeBreakpoint().isGreaterEqual(EndowConstants.FeeMethod.FEE_RATE_DEFAULT_VALUE)) {
481 putFieldError(EndowPropertyConstants.SECOND_FEE_BREAK_POINT, EndowKeyConstants.FeeMethodConstants.ERROR_SECOND_FEE_BREAK_POINT_MUST_BE_LESS_THAN_MAX_FEE_BREAK_POINT);
482 return false;
483 }
484
485 if (feeMethod.getSecondFeeBreakpoint().isLessThan(EndowConstants.FeeMethod.FEE_RATE_DEFAULT_VALUE) && (feeMethod.getThirdFeeRate().compareTo(BigDecimal.ZERO) == 0)) {
486 putFieldError(EndowPropertyConstants.THIRD_FEE_RATE, EndowKeyConstants.FeeMethodConstants.ERROR_THIRD_FEE_RATE_MUST_BE_GREATER_THAN_ZERO);
487 return false;
488 }
489
490 return isValid;
491 }
492
493 /**
494 * @see org.kuali.rice.kns.maintenance.rules.MaintenanceDocumentRuleBase#processAddCollectionLineBusinessRules(org.kuali.rice.kns.document.MaintenanceDocument,
495 * java.lang.String, org.kuali.rice.kns.bo.PersistableBusinessObject)
496 */
497 @Override
498 public boolean processAddCollectionLineBusinessRules(MaintenanceDocument document, String collectionName, PersistableBusinessObject bo) {
499 boolean isValid = true;
500 isValid &= super.processCustomAddCollectionLineBusinessRules(document, collectionName, bo);
501 MessageMap errorMap = GlobalVariables.getMessageMap();
502 isValid &= errorMap.hasNoErrors();
503
504 if (!isValid) {
505 return isValid;
506 }
507
508 FeeMethod feeMethod = (FeeMethod) document.getNewMaintainableObject().getBusinessObject();
509
510 // process add line for feeClassCodes collection
511 if (collectionName.equalsIgnoreCase(EndowPropertyConstants.FEE_CLASS_CODES_COLLECTION_NAME)) {
512 FeeClassCode feeClassCode = (FeeClassCode) bo;
513 bo.refreshReferenceObject(EndowPropertyConstants.FEE_CLASS_CODE_REF);
514
515 if (isEmptyFeeClassCode(bo)) {
516 return false;
517 }
518 if (duplicateFeeClassCodeEntered(feeMethod, bo)) {
519 return false;
520 }
521 if (!validateFeeClassCode(bo)) {
522 isValid = false;
523 }
524 }
525
526 // process add line for feeSecurity collection
527 if (collectionName.equalsIgnoreCase(EndowPropertyConstants.FEE_SECURITY_COLLECTION_NAME)) {
528 FeeSecurity feeSecurity = (FeeSecurity) bo;
529 bo.refreshReferenceObject(EndowPropertyConstants.FEE_SECURITY_REF);
530
531 if (isEmptyFeeSecurityCode(bo)) {
532 return false;
533 }
534 if (duplicateFeeSecurityCodeEntered(feeMethod, bo)) {
535 return false;
536 }
537 if (!validateFeeSecurityCode(bo)) {
538 isValid = false;
539 }
540 }
541
542 // process add line for feeTransaction collection
543 if (collectionName.equalsIgnoreCase(EndowPropertyConstants.FEE_TRANSACTION_TYPE_COLLECTION_NAME)) {
544 FeeTransaction feeTransaction = (FeeTransaction) bo;
545 // bo.refreshReferenceObject(EndowPropertyConstants.FEE_TRANSACTION_ARCHIVE_REF);
546
547 if (isEmptyFeeTransactionDocumentTypeName(bo)) {
548 return false;
549 }
550 if (duplicateFeeTransactionDocumentTypeName(feeMethod, bo)) {
551 return false;
552 }
553 }
554
555 // process add line for feeEndowmentTransaction collection
556 if (collectionName.equalsIgnoreCase(EndowPropertyConstants.FEE_ENDOWMENT_TRANSACTION_CODE_COLLECTION_NAME)) {
557 FeeEndowmentTransactionCode feeEndowmentTransactionCode = (FeeEndowmentTransactionCode) bo;
558 bo.refreshReferenceObject(EndowPropertyConstants.FEE_ENDOWMENT_TRANSACTION_CODE_REF);
559
560 if (isEmptyFeeEndowmentTransactionCode(bo)) {
561 return false;
562 }
563 if (duplicateFeeEndowmentTransactionCode(feeMethod, bo)) {
564 return false;
565 }
566 if (!validateFeeEndowmentTransactionCode(bo)) {
567 isValid = false;
568 }
569 }
570
571 // process add line for feePaymentType collection
572 if (collectionName.equalsIgnoreCase(EndowPropertyConstants.FEE_PAYMENT_TYPE_COLLECTION_NAME)) {
573 if (isEmptyFeePaymentTypeCode(bo)) {
574 return false;
575 }
576 if (duplicateFeePaymentTypeCode(feeMethod, bo)) {
577 return false;
578 }
579 }
580
581 return isValid;
582 }
583
584 /**
585 * This method checks to make sure that fee class code is not empty
586 *
587 * @param feeClassCode The object feeClassCode
588 * @return isValid is true if fee class code is empty else return false
589 */
590 private boolean isEmptyFeeClassCode(PersistableBusinessObject bo) {
591 boolean isValid = false;
592
593 FeeClassCode feeClass = (FeeClassCode) bo;
594
595 String feeClassCode = feeClass.getFeeClassCode();
596 if (ObjectUtils.isNull(feeClassCode)) {
597 putFieldError(EndowPropertyConstants.FEE_CLASS_CODE_ATTRIBUTE, EndowKeyConstants.FeeMethodConstants.ERROR_BLANK_FEE_CLASS_CODE_ENTERED);
598 return true;
599 }
600
601 return isValid;
602 }
603
604 /**
605 * This method checks to make sure that fee class code exists in ClassCode
606 *
607 * @param feeClassCode The object feeClassCode
608 * @return isValid is true if fee class code exists in the database else return false
609 */
610 private boolean validateFeeClassCode(PersistableBusinessObject bo) {
611 boolean isValid = true;
612
613 FeeClassCode feeClass = (FeeClassCode) bo;
614 String feeClassCode = feeClass.getFeeClassCode();
615
616 ClassCodeService classCodeService = SpringContext.getBean(ClassCodeService.class);
617 ClassCode classCode = classCodeService.getByPrimaryKey(feeClassCode);
618
619 if (ObjectUtils.isNull(classCode)) {
620 putFieldError(EndowPropertyConstants.FEE_CLASS_CODE_ATTRIBUTE, EndowKeyConstants.FeeMethodConstants.ERROR_INVALID_FEE_CLASS_CODE_ENTERED);
621 return false;
622 }
623
624 return isValid;
625 }
626
627 /**
628 * This method checks to make sure that fee class code is not a duplicate in the collection list Compare the entered fee class
629 * code on the line to the fee class codes in the list to make sure it is not a duplicate.
630 *
631 * @param feeMethod, bo
632 * @return isDuplicate is true if fee class code is in the list already else return false
633 */
634 private boolean duplicateFeeClassCodeEntered(FeeMethod feeMethod, PersistableBusinessObject bo) {
635 boolean isDuplicate = false;
636
637 FeeClassCode feeClass = (FeeClassCode) bo;
638 String feeClassCode = feeClass.getFeeClassCode();
639
640 List<FeeClassCode> feeClassCodes = (List<FeeClassCode>) feeMethod.getFeeClassCodes();
641
642 for (FeeClassCode feeClassCodeRecord : feeClassCodes) {
643 if (feeClassCodeRecord.getFeeClassCode().equalsIgnoreCase(feeClassCode)) {
644 isDuplicate = true;
645 putFieldError(EndowPropertyConstants.FEE_CLASS_CODE_ATTRIBUTE, EndowKeyConstants.FeeMethodConstants.ERROR_DUPLICATE_FEE_CLASS_CODE_ENTERED);
646 }
647 }
648
649 return isDuplicate;
650 }
651
652 /**
653 * This method checks to make sure that fee security code is not empty
654 *
655 * @param bo
656 * @return isValid is true if fee security code is empty else return false
657 */
658 private boolean isEmptyFeeSecurityCode(PersistableBusinessObject bo) {
659 boolean isValid = false;
660
661 FeeSecurity feeSecurity = (FeeSecurity) bo;
662
663 String feeSecurityCode = feeSecurity.getSecurityCode();
664 if (ObjectUtils.isNull(feeSecurityCode)) {
665 putFieldError(EndowPropertyConstants.FEE_SECURITY_CODE_ATTRIBUTE, EndowKeyConstants.FeeMethodConstants.ERROR_BLANK_FEE_SECURITY_CODE_ENTERED);
666 return true;
667 }
668
669 return isValid;
670 }
671
672 /**
673 * This method checks to make sure that fee security code exists in Security
674 *
675 * @param bo The bo to be mapped into feeSecurity
676 * @return isValid is true if fee security code is in the database else return false
677 */
678 private boolean validateFeeSecurityCode(PersistableBusinessObject bo) {
679 boolean isValid = true;
680
681 FeeSecurity feeSecurity = (FeeSecurity) bo;
682 String securityCode = feeSecurity.getSecurityCode();
683
684 SecurityService securityService = SpringContext.getBean(SecurityService.class);
685 Security security = securityService.getByPrimaryKey(securityCode);
686
687 if (ObjectUtils.isNull(security)) {
688 putFieldError(EndowPropertyConstants.FEE_SECURITY_CODE_ATTRIBUTE, EndowKeyConstants.FeeMethodConstants.ERROR_INVALID_FEE_SECURITY_CODE_ENTERED);
689 return false;
690 }
691
692 return isValid;
693 }
694
695 /**
696 * This method checks to make sure that fee security code is not a duplicate in the collection list Compare the entered fee
697 * security code on the line to the fee security codes in the list to make sure it is not a duplicate.
698 *
699 * @param feeMethod, bo
700 * @return isDuplicate is true if fee security code in the list else return false
701 */
702 private boolean duplicateFeeSecurityCodeEntered(FeeMethod feeMethod, PersistableBusinessObject bo) {
703 boolean isDuplicate = false;
704
705 FeeSecurity feeSecurityCode = (FeeSecurity) bo;
706 String securityCode = feeSecurityCode.getSecurityCode();
707
708 List<FeeSecurity> feeSecurity = (List<FeeSecurity>) feeMethod.getFeeSecurity();
709
710 for (FeeSecurity feeSecurityRecord : feeSecurity) {
711 if (feeSecurityRecord.getSecurityCode().equalsIgnoreCase(securityCode)) {
712 isDuplicate = true;
713 putFieldError(EndowPropertyConstants.FEE_SECURITY_CODE_ATTRIBUTE, EndowKeyConstants.FeeMethodConstants.ERROR_DUPLICATE_FEE_SECURITY_CODE_ENTERED);
714 }
715 }
716
717 return isDuplicate;
718 }
719
720 /**
721 * This method checks to make sure that fee transaction type code is not empty
722 *
723 * @param bo bo to be mapped into feeTransaction
724 * @return isValid is true if fee transaction document name is empty else return false
725 */
726 private boolean isEmptyFeeTransactionDocumentTypeName(PersistableBusinessObject bo) {
727 boolean isValid = false;
728
729 FeeTransaction feeTransaction = (FeeTransaction) bo;
730 String feeTransactionTypeName = feeTransaction.getDocumentTypeName();
731
732 if (ObjectUtils.isNull(feeTransactionTypeName)) {
733 putFieldError(EndowPropertyConstants.FEE_TRANSACTION_DOCUMENT_TYPE_NAME_ATTRIBUTE, EndowKeyConstants.FeeMethodConstants.ERROR_BLANK_DOCUMENT_TYPE_NAME_ENTERED);
734 return true;
735 }
736
737 return isValid;
738 }
739
740 /**
741 * This method checks to make sure that fee class code is not a duplicate in the collection list Compare the entered fee
742 * transaction type code on the line to the fee transaction type codes in the list to make sure it is not a duplicate
743 *
744 * @param feeMethod, bo
745 * @return isDuplicate is true if fee transaction document type name is already in the list else return false
746 */
747 private boolean duplicateFeeTransactionDocumentTypeName(FeeMethod feeMethod, PersistableBusinessObject bo) {
748 boolean isDuplicate = false;
749
750 FeeTransaction feeTransaction = (FeeTransaction) bo;
751 String feeTransactionDocumentTypeName = feeTransaction.getDocumentTypeName();
752
753 List<FeeTransaction> feeTransactions = (List<FeeTransaction>) feeMethod.getFeeTransactions();
754
755 for (FeeTransaction feeTransactionsRecord : feeTransactions) {
756 if (feeTransactionsRecord.getDocumentTypeName().equalsIgnoreCase(feeTransactionDocumentTypeName)) {
757 isDuplicate = true;
758 putFieldError(EndowPropertyConstants.FEE_TRANSACTION_DOCUMENT_TYPE_NAME_ATTRIBUTE, EndowKeyConstants.FeeMethodConstants.ERROR_DUPLICATE_TRANSACTION_TYPE_NAME_ENTERED);
759 }
760 }
761
762 return isDuplicate;
763 }
764
765 /**
766 * This method checks to make sure that fee endowment transaction code is not empty
767 *
768 * @param bo bo will be mapped to feeEndowmentTransactionCode
769 * @return isValid is true if fee endowment transaction code is empty else return false
770 */
771 private boolean isEmptyFeeEndowmentTransactionCode(PersistableBusinessObject bo) {
772 boolean isValid = false;
773
774 FeeEndowmentTransactionCode feeEndowmentTransactionCode = (FeeEndowmentTransactionCode) bo;
775 String feeEndowmentCode = feeEndowmentTransactionCode.getEndowmentTransactionCode();
776
777 if (ObjectUtils.isNull(feeEndowmentCode)) {
778 putFieldError(EndowPropertyConstants.FEE_ENDOWMENT_TRANSACTION_TYPE_CODE_ATTRIBUTE, EndowKeyConstants.FeeMethodConstants.ERROR_BLANK_ENDOWMENT_TRANSACTION_CODE_ENTERED);
779 return true;
780 }
781
782 return isValid;
783 }
784
785 /**
786 * This method checks to make sure that fee endowment transaction code exists in Endowment Transaction Code
787 *
788 * @param bo bo to be mapped into feeEndowmentTransactionCode
789 * @return isValid is true if fee endowment transaction code is in the database else return false
790 */
791 private boolean validateFeeEndowmentTransactionCode(PersistableBusinessObject bo) {
792 boolean isValid = true;
793
794 FeeEndowmentTransactionCode feeEndowmentTransactionCode = (FeeEndowmentTransactionCode) bo;
795 String feeEndowmentCode = feeEndowmentTransactionCode.getEndowmentTransactionCode();
796
797 EndowmentTransactionCodeService endowmentTransactionCodeService = SpringContext.getBean(EndowmentTransactionCodeService.class);
798 EndowmentTransactionCode endowmentTransactionCode = endowmentTransactionCodeService.getByPrimaryKey(feeEndowmentCode);
799
800 if (ObjectUtils.isNull(endowmentTransactionCode)) {
801 putFieldError(EndowPropertyConstants.FEE_ENDOWMENT_TRANSACTION_TYPE_CODE_ATTRIBUTE, EndowKeyConstants.FeeMethodConstants.ERROR_INVALID_ENDOWMENT_TRANSACTION_CODE_ENTERED);
802 return false;
803 }
804
805 return isValid;
806 }
807
808 /**
809 * This method checks to make sure that fee endowment transaction code is not a duplicate in the collection list Compare the
810 * entered fee endowment transaction code on the line to the fee endowment transaction codes in the list to make sure it is not
811 * a duplicate.
812 *
813 * @param feeMethod, bo
814 * @return isDuplicate is true if fee endowment transaction code in the list else return false
815 */
816 private boolean duplicateFeeEndowmentTransactionCode(FeeMethod feeMethod, PersistableBusinessObject bo) {
817 boolean isDuplicate = false;
818
819 FeeEndowmentTransactionCode feeEndowmentTransactionCode = (FeeEndowmentTransactionCode) bo;
820 String feeEndowmentCode = feeEndowmentTransactionCode.getEndowmentTransactionCode();
821
822 List<FeeEndowmentTransactionCode> feeEndowmentTransactionCodes = (List<FeeEndowmentTransactionCode>) feeMethod.getFeeEndowmentTransactionCodes();
823
824 for (FeeEndowmentTransactionCode feeEndowmentTransactionCodesRecord : feeEndowmentTransactionCodes) {
825 if (feeEndowmentTransactionCodesRecord.getEndowmentTransactionCode().equalsIgnoreCase(feeEndowmentCode)) {
826 isDuplicate = true;
827 putFieldError(EndowPropertyConstants.FEE_ENDOWMENT_TRANSACTION_TYPE_CODE_ATTRIBUTE, EndowKeyConstants.FeeMethodConstants.ERROR_DUPLICATE_ENDOWMENT_TRANSACTION_CODE_ENTERED);
828 }
829 }
830
831 return isDuplicate;
832 }
833
834 /**
835 * This method checks to make sure that fee payment type code is not empty
836 *
837 * @param bo bo to be mapped into feePaymentTypeCode
838 * @return isValid is true if fee payment type code is empty else return false
839 */
840 private boolean isEmptyFeePaymentTypeCode(PersistableBusinessObject bo) {
841 boolean isValid = false;
842
843 FeePaymentType feePaymentType = (FeePaymentType) bo;
844 String feePaymentTypeCode = feePaymentType.getPaymentTypeCode();
845
846 if (ObjectUtils.isNull(feePaymentTypeCode)) {
847 putFieldError(EndowPropertyConstants.FEE_PAYMENT_TYPE_CODE, EndowKeyConstants.FeeMethodConstants.ERROR_BLANK_PAYMENT_TYPE_CODE_ENTERED);
848 return true;
849 }
850
851 return isValid;
852 }
853
854 /**
855 * This method checks to make sure that fee payment type code is not a duplicate in the collection list Compare the entered fee
856 * payment type code on the line to the fee payment type codes in the list to make sure it is not a duplicate.
857 *
858 * @param feeMethod, bo
859 * @return isDuplicate is true if fee payment type code in the list else return false
860 */
861 private boolean duplicateFeePaymentTypeCode(FeeMethod feeMethod, PersistableBusinessObject bo) {
862 boolean isDuplicate = false;
863
864 FeePaymentType feePaymentType = (FeePaymentType) bo;
865 String feePaymentTypeCode = feePaymentType.getPaymentTypeCode();
866
867 List<FeePaymentType> feePaymentTypes = (List<FeePaymentType>) feeMethod.getFeePaymentTypes();
868
869 for (FeePaymentType feePaymentTypesRecord : feePaymentTypes) {
870 if (feePaymentTypesRecord.getPaymentTypeCode().equalsIgnoreCase(feePaymentTypeCode)) {
871 isDuplicate = true;
872 putFieldError(EndowPropertyConstants.FEE_PAYMENT_TYPE_CODE, EndowKeyConstants.FeeMethodConstants.ERROR_DUPLICATE_PAYMENT_TYPE_CODE_ENTERED);
873 }
874 }
875
876 return isDuplicate;
877 }
878
879 /**
880 * Check that the frequency code on the Fee Method did not change if the Fee Method is used on at least one KEMID.
881 *
882 * @param document
883 * @return true if valid, false otherwise
884 */
885 private boolean checkFrequencyCodeNotChangedIfFeeMethodUsedOnAnyKemid(Document document) {
886 MaintenanceDocument maintenanceDocument = (MaintenanceDocument) document;
887 boolean isValid = true;
888
889 if (KNSConstants.MAINTENANCE_EDIT_ACTION.equals(maintenanceDocument.getNewMaintainableObject().getMaintenanceAction())) {
890 FeeMethod newFeeMethod = (FeeMethod) maintenanceDocument.getNewMaintainableObject().getBusinessObject();
891 FeeMethod oldFeeMethod = (FeeMethod) maintenanceDocument.getOldMaintainableObject().getBusinessObject();
892 String feeMethodCode = newFeeMethod.getCode();
893
894 if (!StringUtils.equalsIgnoreCase(newFeeMethod.getFeeFrequencyCode(), oldFeeMethod.getFeeFrequencyCode())) {
895 FeeMethodService feeMethodService = SpringContext.getBean(FeeMethodService.class);
896 if (feeMethodService.isFeeMethodUsedOnAnyKemid(feeMethodCode)) {
897 putFieldError(EndowPropertyConstants.FEE_METHOD_FREQUENCY_CODE, EndowKeyConstants.FeeMethodConstants.ERROR_FEE_MTHD_FREQ_CD_CANNOT_BE_CHANGED_IF_FEE_USED_ON_ANY_KEMID);
898 isValid = false;
899 }
900 }
901 }
902
903 return isValid;
904 }
905
906 /**
907 * This method will check if Fee Transaction Type collection does not have type as EHVA
908 *
909 * @param feeMethod
910 * @return true if Fee Transaction Type code is not EHVA else return false
911 */
912 private boolean validFeeTransactionTypeEntered(FeeMethod feeMethod) {
913 boolean valid = true;
914
915 if (feeMethod.getFeeByTransactionType()) {
916 valid = true;
917 List<FeeTransaction> feeTransactions = (List<FeeTransaction>) feeMethod.getFeeTransactions();
918
919 for (FeeTransaction feeTransactionsRecord : feeTransactions) {
920 if (feeTransactionsRecord.getDocumentTypeName().equals(EndowConstants.FeeMethod.ENDOWMENT_HISTORY_VALUE_ADJUSTMENT)) {
921 valid = false;
922 break;
923 }
924 }
925 if (!valid) {
926 putFieldError(EndowPropertyConstants.FEE_TRANSACTION_DOCUMENT_TYPE_NAME_ATTRIBUTE, EndowKeyConstants.FeeMethodConstants.ERROR_INVALID_TRANSACTION_DOCUMENT_TYPE_CODE_ENTERED);
927 }
928 }
929
930 return valid;
931 }
932
933 /**
934 * Check to see if fee method etran code has a valiD expense etran code type = E
935 */
936 private boolean validFeeExpenseETranCodeEntered(FeeMethod feeMethod) {
937 boolean valid = true;
938
939 if (!EndowConstants.EndowmentTransactionTypeCodes.EXPENSE_TYPE_CODE.equalsIgnoreCase(feeMethod.getEndowmentTransactionCode().getEndowmentTransactionTypeCode())) {
940 valid = false;
941 putFieldError(EndowPropertyConstants.FEE_EXPENSE_ENDOWMENT_TRANSACTION_CODE, EndowKeyConstants.FeeMethodConstants.ERROR_INVALID_TRANSACTION_TYPE_CODE_FOR_EXPENSE_ETRANCODE);
942 }
943
944 return valid;
945 }
946 }