add validation for charges

This commit is contained in:
Vishwas Babu A J
2013-09-20 01:08:08 +05:30
parent 15127b747f
commit bf209819f6
2 changed files with 77 additions and 73 deletions
@@ -251,7 +251,7 @@ public class SavingsAccount extends AbstractPersistable<Long> {
@LazyCollection(LazyCollectionOption.FALSE) @LazyCollection(LazyCollectionOption.FALSE)
@OneToMany(cascade = CascadeType.ALL, mappedBy = "savingsAccount", orphanRemoval = true) @OneToMany(cascade = CascadeType.ALL, mappedBy = "savingsAccount", orphanRemoval = true)
private final List<SavingsAccountTransaction> transactions = new ArrayList<SavingsAccountTransaction>(); private final List<SavingsAccountTransaction> transactions = new ArrayList<SavingsAccountTransaction>();
@LazyCollection(LazyCollectionOption.FALSE) @LazyCollection(LazyCollectionOption.FALSE)
@OneToMany(cascade = CascadeType.ALL, mappedBy = "savingsAccount", orphanRemoval = true) @OneToMany(cascade = CascadeType.ALL, mappedBy = "savingsAccount", orphanRemoval = true)
private Set<SavingsAccountCharge> charges = new HashSet<SavingsAccountCharge>(); private Set<SavingsAccountCharge> charges = new HashSet<SavingsAccountCharge>();
@@ -275,7 +275,7 @@ public class SavingsAccount extends AbstractPersistable<Long> {
final SavingsInterestCalculationDaysInYearType interestCalculationDaysInYearType, final BigDecimal minRequiredOpeningBalance, final SavingsInterestCalculationDaysInYearType interestCalculationDaysInYearType, final BigDecimal minRequiredOpeningBalance,
final Integer lockinPeriodFrequency, final SavingsPeriodFrequencyType lockinPeriodFrequencyType, final Integer lockinPeriodFrequency, final SavingsPeriodFrequencyType lockinPeriodFrequencyType,
final BigDecimal withdrawalFeeAmount, final SavingsWithdrawalFeesType withdrawalFeeType, final BigDecimal withdrawalFeeAmount, final SavingsWithdrawalFeesType withdrawalFeeType,
final boolean withdrawalFeeApplicableForTransfer, final BigDecimal annualFeeAmount, final MonthDay annualFeeOnMonthDay, final boolean withdrawalFeeApplicableForTransfer, final BigDecimal annualFeeAmount, final MonthDay annualFeeOnMonthDay,
final Set<SavingsAccountCharge> savingsAccountCharges) { final Set<SavingsAccountCharge> savingsAccountCharges) {
final SavingsAccountStatusType status = SavingsAccountStatusType.SUBMITTED_AND_PENDING_APPROVAL; final SavingsAccountStatusType status = SavingsAccountStatusType.SUBMITTED_AND_PENDING_APPROVAL;
@@ -335,10 +335,11 @@ public class SavingsAccount extends AbstractPersistable<Long> {
if (!CollectionUtils.isEmpty(savingsAccountCharges)) { if (!CollectionUtils.isEmpty(savingsAccountCharges)) {
this.charges = associateChargesWithThisSavingsAccount(savingsAccountCharges); this.charges = associateChargesWithThisSavingsAccount(savingsAccountCharges);
//TODO:Add charges details to savings summary // TODO:Add charges details to savings summary
//this.summary = updateSummaryWithTotalFeeChargesDueAtDisbursement(deriveSumTotalOfChargesDueAtDisbursement()); // this.summary =
// updateSummaryWithTotalFeeChargesDueAtDisbursement(deriveSumTotalOfChargesDueAtDisbursement());
} }
this.summary = new SavingsAccountSummary(); this.summary = new SavingsAccountSummary();
} }
@@ -827,7 +828,7 @@ public class SavingsAccount extends AbstractPersistable<Long> {
throw new PlatformApiDataValidationException(dataValidationErrors); throw new PlatformApiDataValidationException(dataValidationErrors);
} }
validateActivityNotBeforeClientOrGroupTransferDate(SavingsEvent.SAVINGS_PAY_FEE, annualFeeTransactionDate); validateActivityNotBeforeClientOrGroupTransferDate(SavingsEvent.SAVINGS_PAY_CHARGE, annualFeeTransactionDate);
existingTransactionIds.addAll(findExistingTransactionIds()); existingTransactionIds.addAll(findExistingTransactionIds());
existingReversedTransactionIds.addAll(findExistingReversedTransactionIds()); existingReversedTransactionIds.addAll(findExistingReversedTransactionIds());
@@ -1099,8 +1100,8 @@ public class SavingsAccount extends AbstractPersistable<Long> {
this.annualFeeOnMonth = monthOfYear; this.annualFeeOnMonth = monthOfYear;
} }
} }
//charges // charges
final String chargesParamName = "charges"; final String chargesParamName = "charges";
if (command.hasParameter(chargesParamName)) { if (command.hasParameter(chargesParamName)) {
JsonArray jsonArray = command.arrayOfParameterNamed(chargesParamName); JsonArray jsonArray = command.arrayOfParameterNamed(chargesParamName);
@@ -1114,8 +1115,6 @@ public class SavingsAccount extends AbstractPersistable<Long> {
this.annualFeeOnDay = null; this.annualFeeOnDay = null;
this.annualFeeOnMonth = null; this.annualFeeOnMonth = null;
} }
validateLockinDetails(); validateLockinDetails();
validateWithdrawalFeeDetails(); validateWithdrawalFeeDetails();
@@ -1498,7 +1497,7 @@ public class SavingsAccount extends AbstractPersistable<Long> {
this.annualFeeNextDueDate = newAnnualFeeNextDueDate.toDate(); this.annualFeeNextDueDate = newAnnualFeeNextDueDate.toDate();
} }
} else if (transactionToUndo.isCharge()) { } else if (transactionToUndo.isCharge()) {
//undo charge // undo charge
final Set<SavingsAccountChargePaidBy> chargesPaidBy = transactionToUndo.getSavingsAccountChargesPaid(); final Set<SavingsAccountChargePaidBy> chargesPaidBy = transactionToUndo.getSavingsAccountChargesPaid();
for (SavingsAccountChargePaidBy savingsAccountChargePaidBy : chargesPaidBy) { for (SavingsAccountChargePaidBy savingsAccountChargePaidBy : chargesPaidBy) {
final SavingsAccountCharge chargeToUndo = savingsAccountChargePaidBy.getSavingsAccountCharge(); final SavingsAccountCharge chargeToUndo = savingsAccountChargePaidBy.getSavingsAccountCharge();
@@ -1874,33 +1873,33 @@ public class SavingsAccount extends AbstractPersistable<Long> {
public void setStatus(final Integer status) { public void setStatus(final Integer status) {
this.status = status; this.status = status;
} }
private Set<SavingsAccountCharge> associateChargesWithThisSavingsAccount(final Set<SavingsAccountCharge> savingsAccountCharges) { private Set<SavingsAccountCharge> associateChargesWithThisSavingsAccount(final Set<SavingsAccountCharge> savingsAccountCharges) {
for (final SavingsAccountCharge savingsAccountCharge : savingsAccountCharges) { for (final SavingsAccountCharge savingsAccountCharge : savingsAccountCharges) {
savingsAccountCharge.update(this); savingsAccountCharge.update(this);
} }
return savingsAccountCharges; return savingsAccountCharges;
} }
public boolean update(final Set<SavingsAccountCharge> newSavingsAccountCharges) { public boolean update(final Set<SavingsAccountCharge> newSavingsAccountCharges) {
if (newSavingsAccountCharges == null) return false; if (newSavingsAccountCharges == null) return false;
if(this.charges == null) this.charges = new HashSet<SavingsAccountCharge>(); if (this.charges == null) this.charges = new HashSet<SavingsAccountCharge>();
this.charges.clear(); this.charges.clear();
this.charges.addAll(associateChargesWithThisSavingsAccount(newSavingsAccountCharges)); this.charges.addAll(associateChargesWithThisSavingsAccount(newSavingsAccountCharges));
return true; return true;
} }
public boolean hasCurrencyCodeOf(final String matchingCurrencyCode) { public boolean hasCurrencyCodeOf(final String matchingCurrencyCode) {
//TODO AA: revisit // TODO AA: revisit
if(this.currency == null) return false; if (this.currency == null) return false;
return this.currency.getCode().equalsIgnoreCase(matchingCurrencyCode); return this.currency.getCode().equalsIgnoreCase(matchingCurrencyCode);
} }
public void removeCharge(final SavingsAccountCharge charge){ public void removeCharge(final SavingsAccountCharge charge) {
this.charges.remove(charge); this.charges.remove(charge);
} }
public void waiveCharge(final Long savingsAccountChargeId, final List<Long> existingTransactionIds, public void waiveCharge(final Long savingsAccountChargeId, final List<Long> existingTransactionIds,
final List<Long> existingReversedTransactionIds) { final List<Long> existingReversedTransactionIds) {
@@ -1912,48 +1911,49 @@ public class SavingsAccount extends AbstractPersistable<Long> {
baseDataValidator.reset().failWithCodeNoParameterAddedToErrorCode("transaction.invalid.account.is.closed"); baseDataValidator.reset().failWithCodeNoParameterAddedToErrorCode("transaction.invalid.account.is.closed");
if (!dataValidationErrors.isEmpty()) { throw new PlatformApiDataValidationException(dataValidationErrors); } if (!dataValidationErrors.isEmpty()) { throw new PlatformApiDataValidationException(dataValidationErrors); }
} }
if (isNotActive()) { if (isNotActive()) {
baseDataValidator.reset().failWithCodeNoParameterAddedToErrorCode("transaction.invalid.account.is.not.active"); baseDataValidator.reset().failWithCodeNoParameterAddedToErrorCode("transaction.invalid.account.is.not.active");
if (!dataValidationErrors.isEmpty()) { throw new PlatformApiDataValidationException(dataValidationErrors); } if (!dataValidationErrors.isEmpty()) { throw new PlatformApiDataValidationException(dataValidationErrors); }
} }
final SavingsAccountCharge savingsAccountCharge = this.getCharge(savingsAccountChargeId); final SavingsAccountCharge savingsAccountCharge = this.getCharge(savingsAccountChargeId);
// validate charge is not already paid or waived // validate charge is not already paid or waived
if(savingsAccountCharge.isWaived()){ if (savingsAccountCharge.isWaived()) {
baseDataValidator.reset().failWithCodeNoParameterAddedToErrorCode("transaction.invalid.account.charge.is.already.waived"); baseDataValidator.reset().failWithCodeNoParameterAddedToErrorCode("transaction.invalid.account.charge.is.already.waived");
if (!dataValidationErrors.isEmpty()) { throw new PlatformApiDataValidationException(dataValidationErrors); } if (!dataValidationErrors.isEmpty()) { throw new PlatformApiDataValidationException(dataValidationErrors); }
}else if(savingsAccountCharge.isPaid()){ } else if (savingsAccountCharge.isPaid()) {
baseDataValidator.reset().failWithCodeNoParameterAddedToErrorCode("transaction.invalid.account.charge.is.paid"); baseDataValidator.reset().failWithCodeNoParameterAddedToErrorCode("transaction.invalid.account.charge.is.paid");
if (!dataValidationErrors.isEmpty()) { throw new PlatformApiDataValidationException(dataValidationErrors); } if (!dataValidationErrors.isEmpty()) { throw new PlatformApiDataValidationException(dataValidationErrors); }
} }
existingTransactionIds.addAll(findExistingTransactionIds()); existingTransactionIds.addAll(findExistingTransactionIds());
existingReversedTransactionIds.addAll(findExistingReversedTransactionIds()); existingReversedTransactionIds.addAll(findExistingReversedTransactionIds());
//waive charge // waive charge
final Money amountWaived = savingsAccountCharge.waive(this.getCurrency()); final Money amountWaived = savingsAccountCharge.waive(this.getCurrency());
//TODO : AA revisit the code // TODO : AA revisit the code
/*Money feeChargesWaived = amountWaived; /*
Money penaltyChargesWaived = Money.zero(this.getCurrency()); * Money feeChargesWaived = amountWaived; Money penaltyChargesWaived =
if (savingsAccountCharge.isPenaltyCharge()) { * Money.zero(this.getCurrency()); if
penaltyChargesWaived = amountWaived; * (savingsAccountCharge.isPenaltyCharge()) { penaltyChargesWaived =
feeChargesWaived = Money.zero(this.getCurrency()); * amountWaived; feeChargesWaived = Money.zero(this.getCurrency()); }
}*/ */
//persist an entry in transaction details // persist an entry in transaction details
SavingsAccountTransaction chargeTransaction = SavingsAccountTransaction.charge(this, this.office(), savingsAccountCharge.getDueLocalDate(), amountWaived); SavingsAccountTransaction chargeTransaction = SavingsAccountTransaction.charge(this, this.office(),
savingsAccountCharge.getDueLocalDate(), amountWaived);
this.transactions.add(chargeTransaction); this.transactions.add(chargeTransaction);
this.summary.updateSummary(this.currency, this.savingsAccountTransactionSummaryWrapper, this.transactions); this.summary.updateSummary(this.currency, this.savingsAccountTransactionSummaryWrapper, this.transactions);
final MathContext mc = MathContext.DECIMAL64; final MathContext mc = MathContext.DECIMAL64;
calculateInterestUsing(mc, savingsAccountCharge.getDueLocalDate()); calculateInterestUsing(mc, savingsAccountCharge.getDueLocalDate());
} }
public void addCharge(final DateTimeFormatter formatter, final SavingsAccountCharge savingsAccountCharge, final Charge chargeDefinition){ public void addCharge(final DateTimeFormatter formatter, final SavingsAccountCharge savingsAccountCharge, final Charge chargeDefinition) {
final List<ApiParameterError> dataValidationErrors = new ArrayList<ApiParameterError>(); final List<ApiParameterError> dataValidationErrors = new ArrayList<ApiParameterError>();
final DataValidatorBuilder baseDataValidator = new DataValidatorBuilder(dataValidationErrors) final DataValidatorBuilder baseDataValidator = new DataValidatorBuilder(dataValidationErrors)
.resource(SAVINGS_ACCOUNT_RESOURCE_NAME + "dueDate"); .resource(SAVINGS_ACCOUNT_RESOURCE_NAME + "dueDate");
@@ -1962,26 +1962,29 @@ public class SavingsAccount extends AbstractPersistable<Long> {
baseDataValidator.reset().failWithCodeNoParameterAddedToErrorCode("transaction.invalid.account.is.closed"); baseDataValidator.reset().failWithCodeNoParameterAddedToErrorCode("transaction.invalid.account.is.closed");
if (!dataValidationErrors.isEmpty()) { throw new PlatformApiDataValidationException(dataValidationErrors); } if (!dataValidationErrors.isEmpty()) { throw new PlatformApiDataValidationException(dataValidationErrors); }
} }
if (isNotActive()) { if (isNotActive()) {
baseDataValidator.reset().failWithCodeNoParameterAddedToErrorCode("transaction.invalid.account.is.not.active"); baseDataValidator.reset().failWithCodeNoParameterAddedToErrorCode("transaction.invalid.account.is.not.active");
if (!dataValidationErrors.isEmpty()) { throw new PlatformApiDataValidationException(dataValidationErrors); } if (!dataValidationErrors.isEmpty()) { throw new PlatformApiDataValidationException(dataValidationErrors); }
} }
if (!this.hasCurrencyCodeOf(chargeDefinition.getCurrencyCode())) { if (!this.hasCurrencyCodeOf(chargeDefinition.getCurrencyCode())) {
baseDataValidator.reset().failWithCodeNoParameterAddedToErrorCode("transaction.invalid.account.currency.and.charge.currency.not.same"); baseDataValidator.reset().failWithCodeNoParameterAddedToErrorCode(
"transaction.invalid.account.currency.and.charge.currency.not.same");
if (!dataValidationErrors.isEmpty()) { throw new PlatformApiDataValidationException(dataValidationErrors); } if (!dataValidationErrors.isEmpty()) { throw new PlatformApiDataValidationException(dataValidationErrors); }
} }
final LocalDate chargeDueDate = savingsAccountCharge.getDueLocalDate(); final LocalDate chargeDueDate = savingsAccountCharge.getDueLocalDate();
if (chargeDueDate != null && chargeDueDate.isBefore(getActivationLocalDate())) { if (chargeDueDate != null && chargeDueDate.isBefore(getActivationLocalDate())) {
baseDataValidator.reset().parameter("dueDate").value(getActivationLocalDate().toString(formatter)) baseDataValidator.reset().parameter("dueDate").value(getActivationLocalDate().toString(formatter))
.failWithCodeNoParameterAddedToErrorCode("before.activationDate"); .failWithCodeNoParameterAddedToErrorCode("before.activationDate");
throw new PlatformApiDataValidationException(dataValidationErrors); throw new PlatformApiDataValidationException(dataValidationErrors);
} }
//add new charge to savings account validateActivityNotBeforeClientOrGroupTransferDate(SavingsEvent.SAVINGS_APPLY_CHARGE, chargeDueDate);
// add new charge to savings account
getCharges().add(savingsAccountCharge); getCharges().add(savingsAccountCharge);
} }
@@ -1997,37 +2000,40 @@ public class SavingsAccount extends AbstractPersistable<Long> {
baseDataValidator.reset().failWithCodeNoParameterAddedToErrorCode("transaction.invalid.account.is.closed"); baseDataValidator.reset().failWithCodeNoParameterAddedToErrorCode("transaction.invalid.account.is.closed");
if (!dataValidationErrors.isEmpty()) { throw new PlatformApiDataValidationException(dataValidationErrors); } if (!dataValidationErrors.isEmpty()) { throw new PlatformApiDataValidationException(dataValidationErrors); }
} }
if (isNotActive()) { if (isNotActive()) {
baseDataValidator.reset().failWithCodeNoParameterAddedToErrorCode("transaction.invalid.account.is.not.active"); baseDataValidator.reset().failWithCodeNoParameterAddedToErrorCode("transaction.invalid.account.is.not.active");
if (!dataValidationErrors.isEmpty()) { throw new PlatformApiDataValidationException(dataValidationErrors); } if (!dataValidationErrors.isEmpty()) { throw new PlatformApiDataValidationException(dataValidationErrors); }
} }
final SavingsAccountCharge savingsAccountCharge = this.getCharge(savingsAccountChargeId); final SavingsAccountCharge savingsAccountCharge = this.getCharge(savingsAccountChargeId);
// validate charge is not already paid or waived // validate charge is not already paid or waived
if(savingsAccountCharge.isWaived()){ if (savingsAccountCharge.isWaived()) {
baseDataValidator.reset().failWithCodeNoParameterAddedToErrorCode("transaction.invalid.account.charge.is.already.waived"); baseDataValidator.reset().failWithCodeNoParameterAddedToErrorCode("transaction.invalid.account.charge.is.already.waived");
if (!dataValidationErrors.isEmpty()) { throw new PlatformApiDataValidationException(dataValidationErrors); } if (!dataValidationErrors.isEmpty()) { throw new PlatformApiDataValidationException(dataValidationErrors); }
}else if(savingsAccountCharge.isPaid()){ } else if (savingsAccountCharge.isPaid()) {
baseDataValidator.reset().failWithCodeNoParameterAddedToErrorCode("transaction.invalid.account.charge.is.paid"); baseDataValidator.reset().failWithCodeNoParameterAddedToErrorCode("transaction.invalid.account.charge.is.paid");
if (!dataValidationErrors.isEmpty()) { throw new PlatformApiDataValidationException(dataValidationErrors); } if (!dataValidationErrors.isEmpty()) { throw new PlatformApiDataValidationException(dataValidationErrors); }
} }
existingTransactionIds.addAll(findExistingTransactionIds()); existingTransactionIds.addAll(findExistingTransactionIds());
existingReversedTransactionIds.addAll(findExistingReversedTransactionIds()); existingReversedTransactionIds.addAll(findExistingReversedTransactionIds());
final Money chargePaid = savingsAccountCharge.pay(this.getCurrency(), amountPaid); final Money chargePaid = savingsAccountCharge.pay(this.getCurrency(), amountPaid);
// If null reset to current date
final LocalDate transactionDate = (savingsAccountCharge.getDueLocalDate() == null) ? DateUtils.getLocalDateOfTenant() final LocalDate transactionDate = (savingsAccountCharge.getDueLocalDate() == null) ? DateUtils.getLocalDateOfTenant()
: savingsAccountCharge.getDueLocalDate();//If null reset to current date : savingsAccountCharge.getDueLocalDate();
//persist an entry in transaction details
// persist an entry in transaction details
SavingsAccountTransaction chargeTransaction = SavingsAccountTransaction.charge(this, this.office(), transactionDate, chargePaid); SavingsAccountTransaction chargeTransaction = SavingsAccountTransaction.charge(this, this.office(), transactionDate, chargePaid);
final SavingsAccountChargePaidBy chargePaidBy = SavingsAccountChargePaidBy.instance(chargeTransaction, savingsAccountCharge, amountPaid); final SavingsAccountChargePaidBy chargePaidBy = SavingsAccountChargePaidBy.instance(chargeTransaction, savingsAccountCharge,
amountPaid);
chargeTransaction.getSavingsAccountChargesPaid().add(chargePaidBy); chargeTransaction.getSavingsAccountChargesPaid().add(chargePaidBy);
this.transactions.add(chargeTransaction); this.transactions.add(chargeTransaction);
final MathContext mc = MathContext.DECIMAL64; final MathContext mc = MathContext.DECIMAL64;
if (isBeforeLastPostingPeriod(savingsAccountCharge.getDueLocalDate())) { if (isBeforeLastPostingPeriod(savingsAccountCharge.getDueLocalDate())) {
final LocalDate today = DateUtils.getLocalDateOfTenant(); final LocalDate today = DateUtils.getLocalDateOfTenant();
@@ -2036,31 +2042,28 @@ public class SavingsAccount extends AbstractPersistable<Long> {
final LocalDate today = DateUtils.getLocalDateOfTenant(); final LocalDate today = DateUtils.getLocalDateOfTenant();
calculateInterestUsing(mc, today); calculateInterestUsing(mc, today);
} }
this.summary.updateSummary(this.currency, this.savingsAccountTransactionSummaryWrapper, this.transactions); this.summary.updateSummary(this.currency, this.savingsAccountTransactionSummaryWrapper, this.transactions);
validateAccountBalanceDoesNotBecomeNegative(SavingsApiConstants.payChargeTransactionAction); validateAccountBalanceDoesNotBecomeNegative(SavingsApiConstants.payChargeTransactionAction);
} }
private SavingsAccountCharge getCharge(Long savingsAccountChargeId) { private SavingsAccountCharge getCharge(Long savingsAccountChargeId) {
SavingsAccountCharge charge = null; SavingsAccountCharge charge = null;
for (SavingsAccountCharge existingCharge : this.charges) { for (SavingsAccountCharge existingCharge : this.charges) {
if(existingCharge.getId().equals(savingsAccountChargeId)) { if (existingCharge.getId().equals(savingsAccountChargeId)) {
charge = existingCharge; charge = existingCharge;
break; break;
} }
} }
if(charge == null){ if (charge == null) { throw new SavingsAccountChargeNotFoundException(savingsAccountChargeId, getId()); }
throw new SavingsAccountChargeNotFoundException(savingsAccountChargeId, getId());
}
return charge; return charge;
} }
private Set<SavingsAccountCharge> getCharges(){ private Set<SavingsAccountCharge> getCharges() {
return (this.charges == null) ? new HashSet<SavingsAccountCharge>() : this.charges; return (this.charges == null) ? new HashSet<SavingsAccountCharge>() : this.charges;
} }
} }
@@ -20,8 +20,9 @@ public enum SavingsEvent {
SAVINGS_POST_INTEREST("interest.post"), // SAVINGS_POST_INTEREST("interest.post"), //
SAVINGS_UNDO_TRANSACTION("transaction.undo"), // SAVINGS_UNDO_TRANSACTION("transaction.undo"), //
SAVINGS_ADJUST_TRANSACTION("transaction.adjust"), // SAVINGS_ADJUST_TRANSACTION("transaction.adjust"), //
SAVINGS_APPLY_FEE("fee.apply"), // SAVINGS_APPLY_CHARGE("charge.apply"), //
SAVINGS_PAY_FEE("fee.pay"), // SAVINGS_WAIVE_CHARGE("charge.waive"), //
SAVINGS_PAY_CHARGE("charge.pay"), //
SAVINGS_CLOSE_ACCOUNT("account.close"); SAVINGS_CLOSE_ACCOUNT("account.close");
private final String value; private final String value;