Merge pull request #1612 from pramodn02/MIFOSX-2390
MIFOSX-2390 : fixed prepay loan with installment charges & junit fixes
This commit is contained in:
+18
-12
@@ -546,18 +546,24 @@ public class ClientSavingsIntegrationTest {
|
|||||||
cal.set(Calendar.YEAR, (Integer) dates.get(0));
|
cal.set(Calendar.YEAR, (Integer) dates.get(0));
|
||||||
cal.set(Calendar.MONTH, (Integer) dates.get(1) - 1);
|
cal.set(Calendar.MONTH, (Integer) dates.get(1) - 1);
|
||||||
cal.set(Calendar.DAY_OF_MONTH, (Integer) dates.get(2));
|
cal.set(Calendar.DAY_OF_MONTH, (Integer) dates.get(2));
|
||||||
|
int n = 0;
|
||||||
|
Calendar current = Calendar.getInstance();
|
||||||
|
while (cal.compareTo(current) < 0) {
|
||||||
|
n++;
|
||||||
|
cal.set(Calendar.YEAR, (Integer) dates.get(0) + n);
|
||||||
|
}
|
||||||
|
cal.set(Calendar.YEAR, (Integer) dates.get(0));
|
||||||
|
cal.set(Calendar.MONTH, (Integer) dates.get(1) - 1);
|
||||||
|
cal.set(Calendar.DAY_OF_MONTH, (Integer) dates.get(2));
|
||||||
|
|
||||||
this.savingsAccountHelper.payCharge((Integer) savingsChargeForPay.get("id"), savingsId,
|
for (int i = 1; i <= n; i++) {
|
||||||
((Float) savingsChargeForPay.get("amount")).toString(), sdf.format(cal.getTime()));
|
this.savingsAccountHelper.payCharge((Integer) savingsChargeForPay.get("id"), savingsId,
|
||||||
HashMap paidCharge = this.savingsAccountHelper.getSavingsCharge(savingsId, (Integer) savingsChargeForPay.get("id"));
|
((Float) savingsChargeForPay.get("amount")).toString(), sdf.format(cal.getTime()));
|
||||||
assertEquals(savingsChargeForPay.get("amount"), paidCharge.get("amountPaid"));
|
HashMap paidCharge = this.savingsAccountHelper.getSavingsCharge(savingsId, (Integer) savingsChargeForPay.get("id"));
|
||||||
|
Float expectedValue = (Float) savingsChargeForPay.get("amount") * i;
|
||||||
// temporary fix, this test case needs to be re-factored (will fail
|
assertEquals(expectedValue, paidCharge.get("amountPaid"));
|
||||||
// again on Jan 15 2016)
|
cal.set(Calendar.YEAR, (Integer) dates.get(0) + i);
|
||||||
cal.set(Calendar.YEAR, (Integer) dates.get(0) + 1);
|
}
|
||||||
this.savingsAccountHelper.payCharge((Integer) savingsChargeForPay.get("id"), savingsId,
|
|
||||||
((Float) savingsChargeForPay.get("amount")).toString(), sdf.format(cal.getTime()));
|
|
||||||
paidCharge = this.savingsAccountHelper.getSavingsCharge(savingsId, (Integer) savingsChargeForPay.get("id"));
|
|
||||||
|
|
||||||
Integer inactivatedChargeId = (Integer) this.savingsAccountHelper.inactivateCharge(annualSavingsChargeId, savingsId,
|
Integer inactivatedChargeId = (Integer) this.savingsAccountHelper.inactivateCharge(annualSavingsChargeId, savingsId,
|
||||||
CommonConstants.RESPONSE_RESOURCE_ID);
|
CommonConstants.RESPONSE_RESOURCE_ID);
|
||||||
@@ -618,7 +624,7 @@ public class ClientSavingsIntegrationTest {
|
|||||||
|
|
||||||
this.savingsAccountHelper.payCharge((Integer) savingsChargeForPay.get("id"), savingsId,
|
this.savingsAccountHelper.payCharge((Integer) savingsChargeForPay.get("id"), savingsId,
|
||||||
((Float) savingsChargeForPay.get("amount")).toString(), sdf.format(cal.getTime()));
|
((Float) savingsChargeForPay.get("amount")).toString(), sdf.format(cal.getTime()));
|
||||||
paidCharge = this.savingsAccountHelper.getSavingsCharge(savingsId, (Integer) savingsChargeForPay.get("id"));
|
HashMap paidCharge = this.savingsAccountHelper.getSavingsCharge(savingsId, (Integer) savingsChargeForPay.get("id"));
|
||||||
assertEquals(savingsChargeForPay.get("amount"), paidCharge.get("amountPaid"));
|
assertEquals(savingsChargeForPay.get("amount"), paidCharge.get("amountPaid"));
|
||||||
List nextDueDates = (List) paidCharge.get("dueDate");
|
List nextDueDates = (List) paidCharge.get("dueDate");
|
||||||
LocalDate nextDueDate = new LocalDate((Integer) nextDueDates.get(0), (Integer) nextDueDates.get(1), (Integer) nextDueDates.get(2));
|
LocalDate nextDueDate = new LocalDate((Integer) nextDueDates.get(0), (Integer) nextDueDates.get(1), (Integer) nextDueDates.get(2));
|
||||||
|
|||||||
+4
@@ -516,6 +516,10 @@ public class GroupSavingsIntegrationTest {
|
|||||||
LocalDate expectedNextDueDate = new LocalDate((Integer) dates.get(0), (Integer) dates.get(1), (Integer) dates.get(2))
|
LocalDate expectedNextDueDate = new LocalDate((Integer) dates.get(0), (Integer) dates.get(1), (Integer) dates.get(2))
|
||||||
.plusWeeks((Integer) paidCharge.get("feeInterval"));
|
.plusWeeks((Integer) paidCharge.get("feeInterval"));
|
||||||
assertEquals(expectedNextDueDate, nextDueDate);
|
assertEquals(expectedNextDueDate, nextDueDate);
|
||||||
|
cal = Calendar.getInstance();
|
||||||
|
|
||||||
|
this.savingsAccountHelper.closeSavingsAccountAndGetBackRequiredField(savingsId, "true", null, sdf.format(cal.getTime()));
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public static Integer createSavingsProduct(final RequestSpecification requestSpec, final ResponseSpecification responseSpec,
|
public static Integer createSavingsProduct(final RequestSpecification requestSpec, final ResponseSpecification responseSpec,
|
||||||
|
|||||||
+10
@@ -302,6 +302,7 @@ public class Loan extends AbstractPersistable<Long> {
|
|||||||
// see
|
// see
|
||||||
// http://stackoverflow.com/questions/4334970/hibernate-cannot-simultaneously-fetch-multiple-bags
|
// http://stackoverflow.com/questions/4334970/hibernate-cannot-simultaneously-fetch-multiple-bags
|
||||||
@LazyCollection(LazyCollectionOption.FALSE)
|
@LazyCollection(LazyCollectionOption.FALSE)
|
||||||
|
@OrderBy(value = "installmentNumber")
|
||||||
@OneToMany(cascade = CascadeType.ALL, mappedBy = "loan", orphanRemoval = true)
|
@OneToMany(cascade = CascadeType.ALL, mappedBy = "loan", orphanRemoval = true)
|
||||||
private final List<LoanRepaymentScheduleInstallment> repaymentScheduleInstallments = new ArrayList<>();
|
private final List<LoanRepaymentScheduleInstallment> repaymentScheduleInstallments = new ArrayList<>();
|
||||||
|
|
||||||
@@ -5627,6 +5628,15 @@ public class Loan extends AbstractPersistable<Long> {
|
|||||||
}
|
}
|
||||||
|
|
||||||
public int fetchNumberOfInstallmensAfterExceptions() {
|
public int fetchNumberOfInstallmensAfterExceptions() {
|
||||||
|
if(this.repaymentScheduleInstallments.size() > 0){
|
||||||
|
int numberOfInstallments = 0;
|
||||||
|
for (final LoanRepaymentScheduleInstallment installment : this.repaymentScheduleInstallments) {
|
||||||
|
if(!installment.isRecalculatedInterestComponent()){
|
||||||
|
numberOfInstallments++;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return numberOfInstallments;
|
||||||
|
}
|
||||||
return this.repaymentScheduleDetail().getNumberOfRepayments() + adjustNumberOfRepayments();
|
return this.repaymentScheduleDetail().getNumberOfRepayments() + adjustNumberOfRepayments();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
+29
-10
@@ -304,7 +304,7 @@ public abstract class AbstractLoanScheduleGenerator implements LoanScheduleGener
|
|||||||
installment = handleRecalculationForTransactions(mc, loanApplicationTerms, holidayDetailDTO, currency, scheduleParams,
|
installment = handleRecalculationForTransactions(mc, loanApplicationTerms, holidayDetailDTO, currency, scheduleParams,
|
||||||
loanRepaymentScheduleTransactionProcessor, totalInterestChargedForFullLoanTerm, lastRestDate, scheduledDueDate,
|
loanRepaymentScheduleTransactionProcessor, totalInterestChargedForFullLoanTerm, lastRestDate, scheduledDueDate,
|
||||||
periodStartDateApplicableForInterest, applicableTransactions, currentPeriodParams,
|
periodStartDateApplicableForInterest, applicableTransactions, currentPeriodParams,
|
||||||
lastTotalOutstandingInterestPaymentDueToGrace, installment);
|
lastTotalOutstandingInterestPaymentDueToGrace, installment, loanCharges);
|
||||||
periods.add(installment);
|
periods.add(installment);
|
||||||
|
|
||||||
// Updates principal paid map with efective date for reducing
|
// Updates principal paid map with efective date for reducing
|
||||||
@@ -424,7 +424,7 @@ public abstract class AbstractLoanScheduleGenerator implements LoanScheduleGener
|
|||||||
final Money totalInterestChargedForFullLoanTerm, final LocalDate lastRestDate, final LocalDate scheduledDueDate,
|
final Money totalInterestChargedForFullLoanTerm, final LocalDate lastRestDate, final LocalDate scheduledDueDate,
|
||||||
final LocalDate periodStartDateApplicableForInterest, final Collection<RecalculationDetail> applicableTransactions,
|
final LocalDate periodStartDateApplicableForInterest, final Collection<RecalculationDetail> applicableTransactions,
|
||||||
final ScheduleCurrentPeriodParams currentPeriodParams, final Money lastTotalOutstandingInterestPaymentDueToGrace,
|
final ScheduleCurrentPeriodParams currentPeriodParams, final Money lastTotalOutstandingInterestPaymentDueToGrace,
|
||||||
final LoanScheduleModelPeriod installment) {
|
final LoanScheduleModelPeriod installment, Set<LoanCharge> loanCharges) {
|
||||||
LoanScheduleModelPeriod modifiedInstallment = installment;
|
LoanScheduleModelPeriod modifiedInstallment = installment;
|
||||||
if (scheduleParams.applyInterestRecalculation() && loanRepaymentScheduleTransactionProcessor != null) {
|
if (scheduleParams.applyInterestRecalculation() && loanRepaymentScheduleTransactionProcessor != null) {
|
||||||
Money principalProcessed = Money.zero(currency);
|
Money principalProcessed = Money.zero(currency);
|
||||||
@@ -446,7 +446,7 @@ public abstract class AbstractLoanScheduleGenerator implements LoanScheduleGener
|
|||||||
modifiedInstallment = handlePrepaymentOfLoan(mc, loanApplicationTerms, holidayDetailDTO, scheduleParams,
|
modifiedInstallment = handlePrepaymentOfLoan(mc, loanApplicationTerms, holidayDetailDTO, scheduleParams,
|
||||||
totalInterestChargedForFullLoanTerm, scheduledDueDate, periodStartDateApplicableForInterest,
|
totalInterestChargedForFullLoanTerm, scheduledDueDate, periodStartDateApplicableForInterest,
|
||||||
currentPeriodParams.getInterestCalculationGraceOnRepaymentPeriodFraction(), currentPeriodParams,
|
currentPeriodParams.getInterestCalculationGraceOnRepaymentPeriodFraction(), currentPeriodParams,
|
||||||
lastTotalOutstandingInterestPaymentDueToGrace, transactionDate, modifiedInstallment);
|
lastTotalOutstandingInterestPaymentDueToGrace, transactionDate, modifiedInstallment, loanCharges);
|
||||||
|
|
||||||
Money addToPrinciapal = Money.zero(currency);
|
Money addToPrinciapal = Money.zero(currency);
|
||||||
if (scheduleParams.getOutstandingBalance().isLessThanZero()) {
|
if (scheduleParams.getOutstandingBalance().isLessThanZero()) {
|
||||||
@@ -486,7 +486,7 @@ public abstract class AbstractLoanScheduleGenerator implements LoanScheduleGener
|
|||||||
final Money totalInterestChargedForFullLoanTerm, final LocalDate scheduledDueDate,
|
final Money totalInterestChargedForFullLoanTerm, final LocalDate scheduledDueDate,
|
||||||
LocalDate periodStartDateApplicableForInterest, final double interestCalculationGraceOnRepaymentPeriodFraction,
|
LocalDate periodStartDateApplicableForInterest, final double interestCalculationGraceOnRepaymentPeriodFraction,
|
||||||
final ScheduleCurrentPeriodParams currentPeriodParams, final Money lastTotalOutstandingInterestPaymentDueToGrace,
|
final ScheduleCurrentPeriodParams currentPeriodParams, final Money lastTotalOutstandingInterestPaymentDueToGrace,
|
||||||
final LocalDate transactionDate, final LoanScheduleModelPeriod installment) {
|
final LocalDate transactionDate, final LoanScheduleModelPeriod installment, Set<LoanCharge> loanCharges) {
|
||||||
LoanScheduleModelPeriod modifiedInstallment = installment;
|
LoanScheduleModelPeriod modifiedInstallment = installment;
|
||||||
if (!scheduleParams.getOutstandingBalance().isGreaterThan(currentPeriodParams.getInterestForThisPeriod())
|
if (!scheduleParams.getOutstandingBalance().isGreaterThan(currentPeriodParams.getInterestForThisPeriod())
|
||||||
&& !scheduledDueDate.equals(transactionDate)) {
|
&& !scheduledDueDate.equals(transactionDate)) {
|
||||||
@@ -510,20 +510,31 @@ public abstract class AbstractLoanScheduleGenerator implements LoanScheduleGener
|
|||||||
lastTotalOutstandingInterestPaymentDueToGrace, scheduleParams.getOutstandingBalanceAsPerRest(), loanApplicationTerms,
|
lastTotalOutstandingInterestPaymentDueToGrace, scheduleParams.getOutstandingBalanceAsPerRest(), loanApplicationTerms,
|
||||||
scheduleParams.getPeriodNumber(), mc, mergeVariationsToMap(scheduleParams), scheduleParams.getCompoundingMap(),
|
scheduleParams.getPeriodNumber(), mc, mergeVariationsToMap(scheduleParams), scheduleParams.getCompoundingMap(),
|
||||||
periodStartDateApplicableForInterest, calculateTill, interestRates);
|
periodStartDateApplicableForInterest, calculateTill, interestRates);
|
||||||
Money diff = currentPeriodParams.getInterestForThisPeriod().minus(interestTillDate.interest());
|
// applies charges for the period
|
||||||
|
final ScheduleCurrentPeriodParams tempPeriod = new ScheduleCurrentPeriodParams(
|
||||||
|
totalInterestChargedForFullLoanTerm.getCurrency(), interestCalculationGraceOnRepaymentPeriodFraction);
|
||||||
|
tempPeriod.setInterestForThisPeriod(interestTillDate.interest());
|
||||||
|
applyChargesForCurrentPeriod(loanCharges, totalInterestChargedForFullLoanTerm.getCurrency(), scheduleParams, calculateTill,
|
||||||
|
tempPeriod);
|
||||||
|
Money interestDiff = currentPeriodParams.getInterestForThisPeriod().minus(tempPeriod.getInterestForThisPeriod());
|
||||||
|
Money chargeDiff = currentPeriodParams.getFeeChargesForInstallment().minus(tempPeriod.getFeeChargesForInstallment());
|
||||||
|
Money penaltyDiff = currentPeriodParams.getPenaltyChargesForInstallment().minus(tempPeriod.getPenaltyChargesForInstallment());
|
||||||
|
|
||||||
|
Money diff = interestDiff.plus(chargeDiff).plus(penaltyDiff);
|
||||||
if (!scheduleParams.getOutstandingBalance().minus(diff).isGreaterThanZero()) {
|
if (!scheduleParams.getOutstandingBalance().minus(diff).isGreaterThanZero()) {
|
||||||
scheduleParams.reduceOutstandingBalance(diff);
|
scheduleParams.reduceOutstandingBalance(diff);
|
||||||
currentPeriodParams.minusInterestForThisPeriod(diff);
|
currentPeriodParams.minusInterestForThisPeriod(interestDiff);
|
||||||
|
currentPeriodParams.minusFeeChargesForInstallment(chargeDiff);
|
||||||
|
currentPeriodParams.minusPenaltyChargesForInstallment(penaltyDiff);
|
||||||
currentPeriodParams.plusPrincipalForThisPeriod(diff);
|
currentPeriodParams.plusPrincipalForThisPeriod(diff);
|
||||||
final Money totalDue = currentPeriodParams.getPrincipalForThisPeriod().plus(currentPeriodParams.getInterestForThisPeriod());
|
|
||||||
|
|
||||||
// create and replaces repayment period
|
// create and replaces repayment period
|
||||||
// from parts
|
// from parts
|
||||||
modifiedInstallment = LoanScheduleModelRepaymentPeriod.repayment(scheduleParams.getInstalmentNumber(),
|
modifiedInstallment = LoanScheduleModelRepaymentPeriod.repayment(scheduleParams.getInstalmentNumber(),
|
||||||
scheduleParams.getPeriodStartDate(), transactionDate, currentPeriodParams.getPrincipalForThisPeriod(),
|
scheduleParams.getPeriodStartDate(), transactionDate, currentPeriodParams.getPrincipalForThisPeriod(),
|
||||||
scheduleParams.getOutstandingBalance(), currentPeriodParams.getInterestForThisPeriod(),
|
scheduleParams.getOutstandingBalance(), currentPeriodParams.getInterestForThisPeriod(),
|
||||||
currentPeriodParams.getFeeChargesForInstallment(), currentPeriodParams.getPenaltyChargesForInstallment(), totalDue,
|
currentPeriodParams.getFeeChargesForInstallment(), currentPeriodParams.getPenaltyChargesForInstallment(),
|
||||||
false);
|
currentPeriodParams.fetchTotalAmountForPeriod(), false);
|
||||||
scheduleParams.setTotalOutstandingInterestPaymentDueToGrace(interestTillDate.interestPaymentDueToGrace());
|
scheduleParams.setTotalOutstandingInterestPaymentDueToGrace(interestTillDate.interestPaymentDueToGrace());
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -602,7 +613,7 @@ public abstract class AbstractLoanScheduleGenerator implements LoanScheduleGener
|
|||||||
&& scheduleParams.getLoanRepaymentScheduleTransactionProcessor()
|
&& scheduleParams.getLoanRepaymentScheduleTransactionProcessor()
|
||||||
.isInterestFirstRepaymentScheduleTransactionProcessor()) {
|
.isInterestFirstRepaymentScheduleTransactionProcessor()) {
|
||||||
List<LoanTransaction> currentTransactions = createCurrentTransactionList(detail);
|
List<LoanTransaction> currentTransactions = createCurrentTransactionList(detail);
|
||||||
if (!transactionDate.isEqual(scheduleParams.getPeriodStartDate()) || scheduleParams.getInstalmentNumber() == 1) {
|
if (!transactionDate.isEqual(scheduleParams.getPeriodStartDate()) || scheduleParams.getInstalmentNumber() == 1) {
|
||||||
|
|
||||||
int periodDays = Days.daysBetween(scheduleParams.getPeriodStartDate(), transactionDate).getDays();
|
int periodDays = Days.daysBetween(scheduleParams.getPeriodStartDate(), transactionDate).getDays();
|
||||||
// calculates period start date for interest
|
// calculates period start date for interest
|
||||||
@@ -2603,6 +2614,10 @@ public abstract class AbstractLoanScheduleGenerator implements LoanScheduleGener
|
|||||||
this.feeChargesForInstallment = feeChargesForInstallment;
|
this.feeChargesForInstallment = feeChargesForInstallment;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public void minusFeeChargesForInstallment(Money feeChargesForInstallment) {
|
||||||
|
this.feeChargesForInstallment = this.feeChargesForInstallment.minus(feeChargesForInstallment);
|
||||||
|
}
|
||||||
|
|
||||||
public Money getPenaltyChargesForInstallment() {
|
public Money getPenaltyChargesForInstallment() {
|
||||||
return this.penaltyChargesForInstallment;
|
return this.penaltyChargesForInstallment;
|
||||||
}
|
}
|
||||||
@@ -2611,6 +2626,10 @@ public abstract class AbstractLoanScheduleGenerator implements LoanScheduleGener
|
|||||||
this.penaltyChargesForInstallment = penaltyChargesForInstallment;
|
this.penaltyChargesForInstallment = penaltyChargesForInstallment;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public void minusPenaltyChargesForInstallment(Money penaltyChargesForInstallment) {
|
||||||
|
this.penaltyChargesForInstallment = this.penaltyChargesForInstallment.minus(penaltyChargesForInstallment);
|
||||||
|
}
|
||||||
|
|
||||||
public Money fetchTotalAmountForPeriod() {
|
public Money fetchTotalAmountForPeriod() {
|
||||||
return this.principalForThisPeriod.plus(interestForThisPeriod).plus(feeChargesForInstallment)
|
return this.principalForThisPeriod.plus(interestForThisPeriod).plus(feeChargesForInstallment)
|
||||||
.plus(penaltyChargesForInstallment);
|
.plus(penaltyChargesForInstallment);
|
||||||
|
|||||||
+68
-56
@@ -310,7 +310,7 @@ public class SavingsAccount extends AbstractPersistable<Long> {
|
|||||||
final Integer lockinPeriodFrequency, final SavingsPeriodFrequencyType lockinPeriodFrequencyType,
|
final Integer lockinPeriodFrequency, final SavingsPeriodFrequencyType lockinPeriodFrequencyType,
|
||||||
final boolean withdrawalFeeApplicableForTransfer, final Set<SavingsAccountCharge> savingsAccountCharges,
|
final boolean withdrawalFeeApplicableForTransfer, final Set<SavingsAccountCharge> savingsAccountCharges,
|
||||||
final boolean allowOverdraft, final BigDecimal overdraftLimit, final boolean enforceMinRequiredBalance,
|
final boolean allowOverdraft, final BigDecimal overdraftLimit, final boolean enforceMinRequiredBalance,
|
||||||
final BigDecimal minRequiredBalance, final BigDecimal nominalAnnualInterestRateOverdraft,
|
final BigDecimal minRequiredBalance, final BigDecimal nominalAnnualInterestRateOverdraft,
|
||||||
final BigDecimal minOverdraftForInterestCalculation) {
|
final BigDecimal minOverdraftForInterestCalculation) {
|
||||||
|
|
||||||
final SavingsAccountStatusType status = SavingsAccountStatusType.SUBMITTED_AND_PENDING_APPROVAL;
|
final SavingsAccountStatusType status = SavingsAccountStatusType.SUBMITTED_AND_PENDING_APPROVAL;
|
||||||
@@ -345,7 +345,7 @@ public class SavingsAccount extends AbstractPersistable<Long> {
|
|||||||
final Integer lockinPeriodFrequency, final SavingsPeriodFrequencyType lockinPeriodFrequencyType,
|
final Integer lockinPeriodFrequency, final SavingsPeriodFrequencyType lockinPeriodFrequencyType,
|
||||||
final boolean withdrawalFeeApplicableForTransfer, final Set<SavingsAccountCharge> savingsAccountCharges,
|
final boolean withdrawalFeeApplicableForTransfer, final Set<SavingsAccountCharge> savingsAccountCharges,
|
||||||
final boolean allowOverdraft, final BigDecimal overdraftLimit, final boolean enforceMinRequiredBalance,
|
final boolean allowOverdraft, final BigDecimal overdraftLimit, final boolean enforceMinRequiredBalance,
|
||||||
final BigDecimal minRequiredBalance, final BigDecimal nominalAnnualInterestRateOverdraft,
|
final BigDecimal minRequiredBalance, final BigDecimal nominalAnnualInterestRateOverdraft,
|
||||||
final BigDecimal minOverdraftForInterestCalculation) {
|
final BigDecimal minOverdraftForInterestCalculation) {
|
||||||
this.client = client;
|
this.client = client;
|
||||||
this.group = group;
|
this.group = group;
|
||||||
@@ -457,33 +457,33 @@ public class SavingsAccount extends AbstractPersistable<Long> {
|
|||||||
|
|
||||||
final SavingsAccountTransaction postingTransaction = findInterestPostingTransactionFor(interestPostingTransactionDate);
|
final SavingsAccountTransaction postingTransaction = findInterestPostingTransactionFor(interestPostingTransactionDate);
|
||||||
if (postingTransaction == null) {
|
if (postingTransaction == null) {
|
||||||
SavingsAccountTransaction newPostingTransaction;
|
SavingsAccountTransaction newPostingTransaction;
|
||||||
if(interestEarnedToBePostedForPeriod.isGreaterThanOrEqualTo(Money.zero(currency))){
|
if (interestEarnedToBePostedForPeriod.isGreaterThanOrEqualTo(Money.zero(currency))) {
|
||||||
newPostingTransaction = SavingsAccountTransaction.interestPosting(this, office(),
|
newPostingTransaction = SavingsAccountTransaction.interestPosting(this, office(), interestPostingTransactionDate,
|
||||||
interestPostingTransactionDate, interestEarnedToBePostedForPeriod);
|
interestEarnedToBePostedForPeriod);
|
||||||
}else{
|
} else {
|
||||||
newPostingTransaction = SavingsAccountTransaction.overdraftInterest(this, office(),
|
newPostingTransaction = SavingsAccountTransaction.overdraftInterest(this, office(), interestPostingTransactionDate,
|
||||||
interestPostingTransactionDate, interestEarnedToBePostedForPeriod.negated());
|
interestEarnedToBePostedForPeriod.negated());
|
||||||
}
|
}
|
||||||
this.transactions.add(newPostingTransaction);
|
this.transactions.add(newPostingTransaction);
|
||||||
recalucateDailyBalanceDetails = true;
|
recalucateDailyBalanceDetails = true;
|
||||||
} else {
|
} else {
|
||||||
boolean correctionRequired = false;
|
boolean correctionRequired = false;
|
||||||
if(postingTransaction.isInterestPostingAndNotReversed()){
|
if (postingTransaction.isInterestPostingAndNotReversed()) {
|
||||||
correctionRequired = postingTransaction.hasNotAmount(interestEarnedToBePostedForPeriod);
|
correctionRequired = postingTransaction.hasNotAmount(interestEarnedToBePostedForPeriod);
|
||||||
}else{
|
} else {
|
||||||
correctionRequired = postingTransaction.hasNotAmount(interestEarnedToBePostedForPeriod.negated());
|
correctionRequired = postingTransaction.hasNotAmount(interestEarnedToBePostedForPeriod.negated());
|
||||||
}
|
}
|
||||||
if (correctionRequired) {
|
if (correctionRequired) {
|
||||||
postingTransaction.reverse();
|
postingTransaction.reverse();
|
||||||
SavingsAccountTransaction newPostingTransaction;
|
SavingsAccountTransaction newPostingTransaction;
|
||||||
if(interestEarnedToBePostedForPeriod.isGreaterThanOrEqualTo(Money.zero(currency))){
|
if (interestEarnedToBePostedForPeriod.isGreaterThanOrEqualTo(Money.zero(currency))) {
|
||||||
newPostingTransaction = SavingsAccountTransaction.interestPosting(this, office(),
|
newPostingTransaction = SavingsAccountTransaction.interestPosting(this, office(),
|
||||||
interestPostingTransactionDate, interestEarnedToBePostedForPeriod);
|
interestPostingTransactionDate, interestEarnedToBePostedForPeriod);
|
||||||
}else{
|
} else {
|
||||||
newPostingTransaction = SavingsAccountTransaction.overdraftInterest(this, office(),
|
newPostingTransaction = SavingsAccountTransaction.overdraftInterest(this, office(),
|
||||||
interestPostingTransactionDate, interestEarnedToBePostedForPeriod.negated());
|
interestPostingTransactionDate, interestEarnedToBePostedForPeriod.negated());
|
||||||
}
|
}
|
||||||
this.transactions.add(newPostingTransaction);
|
this.transactions.add(newPostingTransaction);
|
||||||
recalucateDailyBalanceDetails = true;
|
recalucateDailyBalanceDetails = true;
|
||||||
}
|
}
|
||||||
@@ -510,7 +510,8 @@ public class SavingsAccount extends AbstractPersistable<Long> {
|
|||||||
SavingsAccountTransaction postingTransation = null;
|
SavingsAccountTransaction postingTransation = null;
|
||||||
|
|
||||||
for (final SavingsAccountTransaction transaction : this.transactions) {
|
for (final SavingsAccountTransaction transaction : this.transactions) {
|
||||||
if ((transaction.isInterestPostingAndNotReversed() || transaction.isOverdraftInterestAndNotReversed()) && transaction.occursOn(postingDate)) {
|
if ((transaction.isInterestPostingAndNotReversed() || transaction.isOverdraftInterestAndNotReversed())
|
||||||
|
&& transaction.occursOn(postingDate)) {
|
||||||
postingTransation = transaction;
|
postingTransation = transaction;
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
@@ -634,10 +635,10 @@ public class SavingsAccount extends AbstractPersistable<Long> {
|
|||||||
}
|
}
|
||||||
|
|
||||||
private BigDecimal getEffectiveOverdraftInterestRateAsFraction(MathContext mc) {
|
private BigDecimal getEffectiveOverdraftInterestRateAsFraction(MathContext mc) {
|
||||||
return this.nominalAnnualInterestRateOverdraft.divide(BigDecimal.valueOf(100l), mc);
|
return this.nominalAnnualInterestRateOverdraft.divide(BigDecimal.valueOf(100l), mc);
|
||||||
}
|
}
|
||||||
|
|
||||||
@SuppressWarnings("unused")
|
@SuppressWarnings("unused")
|
||||||
protected BigDecimal getEffectiveInterestRateAsFraction(final MathContext mc, final LocalDate upToInterestCalculationDate) {
|
protected BigDecimal getEffectiveInterestRateAsFraction(final MathContext mc, final LocalDate upToInterestCalculationDate) {
|
||||||
return this.nominalAnnualInterestRate.divide(BigDecimal.valueOf(100l), mc);
|
return this.nominalAnnualInterestRate.divide(BigDecimal.valueOf(100l), mc);
|
||||||
}
|
}
|
||||||
@@ -648,7 +649,8 @@ public class SavingsAccount extends AbstractPersistable<Long> {
|
|||||||
final List<SavingsAccountTransaction> orderedNonInterestPostingTransactions = new ArrayList<>();
|
final List<SavingsAccountTransaction> orderedNonInterestPostingTransactions = new ArrayList<>();
|
||||||
|
|
||||||
for (final SavingsAccountTransaction transaction : listOfTransactionsSorted) {
|
for (final SavingsAccountTransaction transaction : listOfTransactionsSorted) {
|
||||||
if (!(transaction.isInterestPostingAndNotReversed() || transaction.isOverdraftInterestAndNotReversed()) && transaction.isNotReversed()) {
|
if (!(transaction.isInterestPostingAndNotReversed() || transaction.isOverdraftInterestAndNotReversed())
|
||||||
|
&& transaction.isNotReversed()) {
|
||||||
orderedNonInterestPostingTransactions.add(transaction);
|
orderedNonInterestPostingTransactions.add(transaction);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -727,9 +729,8 @@ public class SavingsAccount extends AbstractPersistable<Long> {
|
|||||||
LocalDate endOfBalanceDate = interestPostingUpToDate;
|
LocalDate endOfBalanceDate = interestPostingUpToDate;
|
||||||
for (int i = accountTransactionsSorted.size() - 1; i >= 0; i--) {
|
for (int i = accountTransactionsSorted.size() - 1; i >= 0; i--) {
|
||||||
final SavingsAccountTransaction transaction = accountTransactionsSorted.get(i);
|
final SavingsAccountTransaction transaction = accountTransactionsSorted.get(i);
|
||||||
if (transaction.isNotReversed()
|
if (transaction.isNotReversed()
|
||||||
&& !(transaction.isInterestPostingAndNotReversed()
|
&& !(transaction.isInterestPostingAndNotReversed() || transaction.isOverdraftInterestAndNotReversed())) {
|
||||||
|| transaction.isOverdraftInterestAndNotReversed())) {
|
|
||||||
transaction.updateCumulativeBalanceAndDates(this.currency, endOfBalanceDate);
|
transaction.updateCumulativeBalanceAndDates(this.currency, endOfBalanceDate);
|
||||||
// this transactions transaction date is end of balance date for
|
// this transactions transaction date is end of balance date for
|
||||||
// previous transaction.
|
// previous transaction.
|
||||||
@@ -888,7 +889,8 @@ public class SavingsAccount extends AbstractPersistable<Long> {
|
|||||||
boolean transactionBeforeLastInterestPosting = false;
|
boolean transactionBeforeLastInterestPosting = false;
|
||||||
|
|
||||||
for (final SavingsAccountTransaction transaction : retreiveListOfTransactions()) {
|
for (final SavingsAccountTransaction transaction : retreiveListOfTransactions()) {
|
||||||
if ((transaction.isInterestPostingAndNotReversed() || transaction.isOverdraftInterestAndNotReversed()) && transaction.isAfter(transactionDate)) {
|
if ((transaction.isInterestPostingAndNotReversed() || transaction.isOverdraftInterestAndNotReversed())
|
||||||
|
&& transaction.isAfter(transactionDate)) {
|
||||||
transactionBeforeLastInterestPosting = true;
|
transactionBeforeLastInterestPosting = true;
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
@@ -897,7 +899,8 @@ public class SavingsAccount extends AbstractPersistable<Long> {
|
|||||||
return transactionBeforeLastInterestPosting;
|
return transactionBeforeLastInterestPosting;
|
||||||
}
|
}
|
||||||
|
|
||||||
public void validateAccountBalanceDoesNotBecomeNegative(final BigDecimal transactionAmount, final boolean isException,final List<DepositAccountOnHoldTransaction> depositAccountOnHoldTransactions) {
|
public void validateAccountBalanceDoesNotBecomeNegative(final BigDecimal transactionAmount, final boolean isException,
|
||||||
|
final List<DepositAccountOnHoldTransaction> depositAccountOnHoldTransactions) {
|
||||||
final List<SavingsAccountTransaction> transactionsSortedByDate = retreiveListOfTransactions();
|
final List<SavingsAccountTransaction> transactionsSortedByDate = retreiveListOfTransactions();
|
||||||
Money runningBalance = Money.zero(this.currency);
|
Money runningBalance = Money.zero(this.currency);
|
||||||
Money minRequiredBalance = minRequiredBalanceDerived(getCurrency());
|
Money minRequiredBalance = minRequiredBalanceDerived(getCurrency());
|
||||||
@@ -911,27 +914,28 @@ public class SavingsAccount extends AbstractPersistable<Long> {
|
|||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
final BigDecimal withdrawalFee = null;
|
final BigDecimal withdrawalFee = null;
|
||||||
|
|
||||||
/* Loop through the onHold funds and see if we need to deduct or add to minimum required balance
|
/*
|
||||||
and the point in time the transaction was made: */
|
* Loop through the onHold funds and see if we need to deduct or add
|
||||||
if(depositAccountOnHoldTransactions !=null){
|
* to minimum required balance and the point in time the transaction
|
||||||
for(final DepositAccountOnHoldTransaction onHoldTransaction: depositAccountOnHoldTransactions) {
|
* was made:
|
||||||
|
*/
|
||||||
|
if (depositAccountOnHoldTransactions != null) {
|
||||||
|
for (final DepositAccountOnHoldTransaction onHoldTransaction : depositAccountOnHoldTransactions) {
|
||||||
// Compare the balance of the on hold:
|
// Compare the balance of the on hold:
|
||||||
if((onHoldTransaction.getTransactionDate().isBefore(transaction.transactionLocalDate()) || onHoldTransaction.getTransactionDate().isEqual(transaction.transactionLocalDate()))
|
if ((onHoldTransaction.getTransactionDate().isBefore(transaction.transactionLocalDate()) || onHoldTransaction
|
||||||
|
.getTransactionDate().isEqual(transaction.transactionLocalDate()))
|
||||||
&& (lastSavingsDate == null || onHoldTransaction.getTransactionDate().isAfter(lastSavingsDate))) {
|
&& (lastSavingsDate == null || onHoldTransaction.getTransactionDate().isAfter(lastSavingsDate))) {
|
||||||
if(onHoldTransaction.getTransactionType().isHold()) {
|
if (onHoldTransaction.getTransactionType().isHold()) {
|
||||||
minRequiredBalance = minRequiredBalance.plus(onHoldTransaction.getAmountMoney(this.currency));
|
minRequiredBalance = minRequiredBalance.plus(onHoldTransaction.getAmountMoney(this.currency));
|
||||||
}else{
|
} else {
|
||||||
minRequiredBalance = minRequiredBalance.minus(onHoldTransaction.getAmountMoney(this.currency));
|
minRequiredBalance = minRequiredBalance.minus(onHoldTransaction.getAmountMoney(this.currency));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
// deal with potential minRequiredBalance and
|
// deal with potential minRequiredBalance and
|
||||||
// enforceMinRequiredBalance
|
// enforceMinRequiredBalance
|
||||||
if (!isException && transaction.canProcessBalanceCheck()) {
|
if (!isException && transaction.canProcessBalanceCheck()) {
|
||||||
@@ -943,7 +947,8 @@ public class SavingsAccount extends AbstractPersistable<Long> {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public void validateAccountBalanceDoesNotBecomeNegative(final String transactionAction,final List<DepositAccountOnHoldTransaction> depositAccountOnHoldTransactions) {
|
public void validateAccountBalanceDoesNotBecomeNegative(final String transactionAction,
|
||||||
|
final List<DepositAccountOnHoldTransaction> depositAccountOnHoldTransactions) {
|
||||||
|
|
||||||
final List<SavingsAccountTransaction> transactionsSortedByDate = retreiveListOfTransactions();
|
final List<SavingsAccountTransaction> transactionsSortedByDate = retreiveListOfTransactions();
|
||||||
Money runningBalance = Money.zero(this.currency);
|
Money runningBalance = Money.zero(this.currency);
|
||||||
@@ -956,16 +961,20 @@ public class SavingsAccount extends AbstractPersistable<Long> {
|
|||||||
runningBalance = runningBalance.minus(transaction.getAmount(this.currency));
|
runningBalance = runningBalance.minus(transaction.getAmount(this.currency));
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Loop through the onHold funds and see if we need to deduct or add to minimum required balance
|
/*
|
||||||
and the point in time the transaction was made: */
|
* Loop through the onHold funds and see if we need to deduct or add
|
||||||
if(depositAccountOnHoldTransactions !=null){
|
* to minimum required balance and the point in time the transaction
|
||||||
for(final DepositAccountOnHoldTransaction onHoldTransaction: depositAccountOnHoldTransactions) {
|
* was made:
|
||||||
|
*/
|
||||||
|
if (depositAccountOnHoldTransactions != null) {
|
||||||
|
for (final DepositAccountOnHoldTransaction onHoldTransaction : depositAccountOnHoldTransactions) {
|
||||||
// Compare the balance of the on hold:
|
// Compare the balance of the on hold:
|
||||||
if((onHoldTransaction.getTransactionDate().isBefore(transaction.transactionLocalDate()) || onHoldTransaction.getTransactionDate().isEqual(transaction.transactionLocalDate()))
|
if ((onHoldTransaction.getTransactionDate().isBefore(transaction.transactionLocalDate()) || onHoldTransaction
|
||||||
|
.getTransactionDate().isEqual(transaction.transactionLocalDate()))
|
||||||
&& (lastSavingsDate == null || onHoldTransaction.getTransactionDate().isAfter(lastSavingsDate))) {
|
&& (lastSavingsDate == null || onHoldTransaction.getTransactionDate().isAfter(lastSavingsDate))) {
|
||||||
if(onHoldTransaction.getTransactionType().isHold()) {
|
if (onHoldTransaction.getTransactionType().isHold()) {
|
||||||
minRequiredBalance = minRequiredBalance.plus(onHoldTransaction.getAmountMoney(this.currency));
|
minRequiredBalance = minRequiredBalance.plus(onHoldTransaction.getAmountMoney(this.currency));
|
||||||
}else{
|
} else {
|
||||||
minRequiredBalance = minRequiredBalance.minus(onHoldTransaction.getAmountMoney(this.currency));
|
minRequiredBalance = minRequiredBalance.minus(onHoldTransaction.getAmountMoney(this.currency));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -1172,15 +1181,19 @@ public class SavingsAccount extends AbstractPersistable<Long> {
|
|||||||
this.overdraftLimit = newValue;
|
this.overdraftLimit = newValue;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (command.isChangeInBigDecimalParameterNamedDefaultingZeroToNull(nominalAnnualInterestRateOverdraftParamName, this.nominalAnnualInterestRateOverdraft)) {
|
if (command.isChangeInBigDecimalParameterNamedDefaultingZeroToNull(nominalAnnualInterestRateOverdraftParamName,
|
||||||
final BigDecimal newValue = command.bigDecimalValueOfParameterNamedDefaultToNullIfZero(nominalAnnualInterestRateOverdraftParamName);
|
this.nominalAnnualInterestRateOverdraft)) {
|
||||||
|
final BigDecimal newValue = command
|
||||||
|
.bigDecimalValueOfParameterNamedDefaultToNullIfZero(nominalAnnualInterestRateOverdraftParamName);
|
||||||
actualChanges.put(nominalAnnualInterestRateOverdraftParamName, newValue);
|
actualChanges.put(nominalAnnualInterestRateOverdraftParamName, newValue);
|
||||||
actualChanges.put(localeParamName, localeAsInput);
|
actualChanges.put(localeParamName, localeAsInput);
|
||||||
this.nominalAnnualInterestRateOverdraft = newValue;
|
this.nominalAnnualInterestRateOverdraft = newValue;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (command.isChangeInBigDecimalParameterNamedDefaultingZeroToNull(minOverdraftForInterestCalculationParamName, this.minOverdraftForInterestCalculation)) {
|
if (command.isChangeInBigDecimalParameterNamedDefaultingZeroToNull(minOverdraftForInterestCalculationParamName,
|
||||||
final BigDecimal newValue = command.bigDecimalValueOfParameterNamedDefaultToNullIfZero(minOverdraftForInterestCalculationParamName);
|
this.minOverdraftForInterestCalculation)) {
|
||||||
|
final BigDecimal newValue = command
|
||||||
|
.bigDecimalValueOfParameterNamedDefaultToNullIfZero(minOverdraftForInterestCalculationParamName);
|
||||||
actualChanges.put(minOverdraftForInterestCalculationParamName, newValue);
|
actualChanges.put(minOverdraftForInterestCalculationParamName, newValue);
|
||||||
actualChanges.put(localeParamName, localeAsInput);
|
actualChanges.put(localeParamName, localeAsInput);
|
||||||
this.minOverdraftForInterestCalculation = newValue;
|
this.minOverdraftForInterestCalculation = newValue;
|
||||||
@@ -1208,21 +1221,20 @@ public class SavingsAccount extends AbstractPersistable<Long> {
|
|||||||
validateLockinDetails(baseDataValidator);
|
validateLockinDetails(baseDataValidator);
|
||||||
esnureOverdraftLimitsSetForOverdraftAccounts();
|
esnureOverdraftLimitsSetForOverdraftAccounts();
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* If overdrafts are allowed and the overdraft limit is not set, set the
|
* If overdrafts are allowed and the overdraft limit is not set, set the
|
||||||
* same to Zero
|
* same to Zero
|
||||||
**/
|
**/
|
||||||
private void esnureOverdraftLimitsSetForOverdraftAccounts() {
|
private void esnureOverdraftLimitsSetForOverdraftAccounts() {
|
||||||
|
|
||||||
if (this.allowOverdraft) {
|
this.overdraftLimit = this.overdraftLimit == null ? BigDecimal.ZERO : this.overdraftLimit;
|
||||||
this.overdraftLimit = this.overdraftLimit == null? BigDecimal.ZERO : this.overdraftLimit;
|
this.nominalAnnualInterestRateOverdraft = this.nominalAnnualInterestRateOverdraft == null ? BigDecimal.ZERO
|
||||||
this.nominalAnnualInterestRateOverdraft = this.nominalAnnualInterestRateOverdraft == null? BigDecimal.ZERO : this.nominalAnnualInterestRateOverdraft;
|
: this.nominalAnnualInterestRateOverdraft;
|
||||||
this.minOverdraftForInterestCalculation = this.minOverdraftForInterestCalculation == null? BigDecimal.ZERO : this.minOverdraftForInterestCalculation;
|
this.minOverdraftForInterestCalculation = this.minOverdraftForInterestCalculation == null ? BigDecimal.ZERO
|
||||||
}
|
: this.minOverdraftForInterestCalculation;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
private void validateLockinDetails(final DataValidatorBuilder baseDataValidator) {
|
private void validateLockinDetails(final DataValidatorBuilder baseDataValidator) {
|
||||||
|
|
||||||
/*
|
/*
|
||||||
|
|||||||
Reference in New Issue
Block a user