mifosx-90: validation of loan and loan charges state when adding and removing loan charges and when creating, modifying loan applications.
This commit is contained in:
+5
@@ -88,6 +88,11 @@ public class CreocoreLoanRepaymentScheduleTransactionProcessor extends
|
||||
interestPortion = currentInstallment.waiveInterestComponent(transactionAmountRemaining);
|
||||
transactionAmountRemaining = transactionAmountRemaining.minus(interestPortion);
|
||||
} else {
|
||||
penaltyChargesPortion = currentInstallment.payPenaltyChargesComponent(transactionAmountRemaining);
|
||||
transactionAmountRemaining = transactionAmountRemaining.minus(penaltyChargesPortion);
|
||||
|
||||
feeChargesPortion = currentInstallment.payFeeChargesComponent(transactionAmountRemaining);
|
||||
transactionAmountRemaining = transactionAmountRemaining.minus(feeChargesPortion);
|
||||
|
||||
interestPortion = currentInstallment.payInterestComponent(transactionAmountRemaining);
|
||||
transactionAmountRemaining = transactionAmountRemaining.minus(interestPortion);
|
||||
|
||||
+12
-1
@@ -90,6 +90,12 @@ public class HeavensFamilyLoanRepaymentScheduleTransactionProcessor extends Abst
|
||||
transactionAmountRemaining = transactionAmountRemaining.minus(principalPortion);
|
||||
}
|
||||
|
||||
penaltyChargesPortion = currentInstallment.payPenaltyChargesComponent(transactionAmountRemaining);
|
||||
transactionAmountRemaining = transactionAmountRemaining.minus(penaltyChargesPortion);
|
||||
|
||||
feeChargesPortion = currentInstallment.payFeeChargesComponent(transactionAmountRemaining);
|
||||
transactionAmountRemaining = transactionAmountRemaining.minus(feeChargesPortion);
|
||||
|
||||
interestPortion = currentInstallment.payInterestComponent(transactionAmountRemaining);
|
||||
transactionAmountRemaining = transactionAmountRemaining.minus(interestPortion);
|
||||
|
||||
@@ -120,7 +126,12 @@ public class HeavensFamilyLoanRepaymentScheduleTransactionProcessor extends Abst
|
||||
interestPortion = currentInstallment.waiveInterestComponent(transactionAmountRemaining);
|
||||
transactionAmountRemaining = transactionAmountRemaining.minus(interestPortion);
|
||||
} else {
|
||||
|
||||
penaltyChargesPortion = currentInstallment.payPenaltyChargesComponent(transactionAmountRemaining);
|
||||
transactionAmountRemaining = transactionAmountRemaining.minus(penaltyChargesPortion);
|
||||
|
||||
feeChargesPortion = currentInstallment.payFeeChargesComponent(transactionAmountRemaining);
|
||||
transactionAmountRemaining = transactionAmountRemaining.minus(feeChargesPortion);
|
||||
|
||||
interestPortion = currentInstallment.payInterestComponent(transactionAmountRemaining);
|
||||
transactionAmountRemaining = transactionAmountRemaining.minus(interestPortion);
|
||||
|
||||
|
||||
@@ -261,6 +261,8 @@ public class Loan extends AbstractAuditableCustom<AppUser, Long> {
|
||||
|
||||
public void addLoanCharge(final LoanCharge loanCharge) {
|
||||
|
||||
validateLoanIsNotClosed(loanCharge);
|
||||
|
||||
if (isDisbursed() && loanCharge.isDueAtDisbursement()) {
|
||||
// Note: added this constraint to restrict adding charges to a loan after it is disbursed
|
||||
// if the loan charge payment type is 'Disbursement'.
|
||||
@@ -272,10 +274,7 @@ public class Loan extends AbstractAuditableCustom<AppUser, Long> {
|
||||
throw new LoanChargeCannotBeAddedException("loanCharge", "due.at.disbursement.and.loan.is.disbursed", defaultUserMessage, getId(), loanCharge.name());
|
||||
}
|
||||
|
||||
if (loanCharge.isSpecifiedDueDate() && !loanCharge.isDueForCollectionBetween(getDisbursementDate(), getLastRepaymentPeriodDueDate())) {
|
||||
final String defaultUserMessage = "This charge which is due at disbursement cannot be added as the loan is already disbursed.";
|
||||
throw new LoanChargeCannotBeAddedException("loanCharge", "specified.due.date.outside.range", defaultUserMessage, getDisbursementDate(), getLastRepaymentPeriodDueDate(), loanCharge.name());
|
||||
}
|
||||
validateChargeHasValidSpecifiedDateIfApplicable(loanCharge, getDisbursementDate(), getLastRepaymentPeriodDueDate());
|
||||
|
||||
loanCharge.update(this);
|
||||
this.charges.add(loanCharge);
|
||||
@@ -293,12 +292,29 @@ public class Loan extends AbstractAuditableCustom<AppUser, Long> {
|
||||
loanRepaymentScheduleTransactionProcessor.handleTransaction(allNonContraTransactionsPostDisbursement, getCurrency(), this.repaymentScheduleInstallments, this.charges);
|
||||
}
|
||||
}
|
||||
|
||||
private void validateLoanIsNotClosed(final LoanCharge loanCharge) {
|
||||
if (isClosed()) {
|
||||
final String defaultUserMessage = "This charge cannot be added as the loan is already closed.";
|
||||
throw new LoanChargeCannotBeAddedException("loanCharge", "loan.is.closed", defaultUserMessage, getId(), loanCharge.name());
|
||||
}
|
||||
}
|
||||
|
||||
private void validateChargeHasValidSpecifiedDateIfApplicable(final LoanCharge loanCharge, final LocalDate disbursementDate, final LocalDate lastRepaymentPeriodDueDate) {
|
||||
if (loanCharge.isSpecifiedDueDate() && !loanCharge.isDueForCollectionBetween(disbursementDate, lastRepaymentPeriodDueDate)) {
|
||||
final String defaultUserMessage = "This charge which is due at disbursement cannot be added as the loan is already disbursed.";
|
||||
throw new LoanChargeCannotBeAddedException("loanCharge", "specified.due.date.outside.range", defaultUserMessage, getDisbursementDate(), getLastRepaymentPeriodDueDate(), loanCharge.name());
|
||||
}
|
||||
}
|
||||
|
||||
private LocalDate getLastRepaymentPeriodDueDate() {
|
||||
return this.repaymentScheduleInstallments.get(this.repaymentScheduleInstallments.size()-1).getDueDate();
|
||||
}
|
||||
|
||||
public void removeLoanCharge(final LoanCharge loanCharge) {
|
||||
|
||||
validateLoanIsNotClosed(loanCharge);
|
||||
|
||||
boolean removed = this.charges.remove(loanCharge);
|
||||
if (removed) {
|
||||
updateTotalChargesDueAtDisbursement();
|
||||
@@ -531,6 +547,10 @@ public class Loan extends AbstractAuditableCustom<AppUser, Long> {
|
||||
"cannot.be.after.expected.disbursement.date", errorMessage,
|
||||
submittedOn, getExpectedDisbursedOnLocalDate());
|
||||
}
|
||||
|
||||
for (LoanCharge loanCharge : this.charges) {
|
||||
validateChargeHasValidSpecifiedDateIfApplicable(loanCharge, getDisbursementDate(), getLastRepaymentPeriodDueDate());
|
||||
}
|
||||
}
|
||||
|
||||
public void reject(final LocalDate rejectedOn, final LoanLifecycleStateMachine loanLifecycleStateMachine) {
|
||||
|
||||
+1
-1
@@ -25,7 +25,7 @@ public class LoanRepaymentScheduleTransactionProcessorFactory {
|
||||
}
|
||||
|
||||
if (transactionProcessingStrategy.isIndianRBIStrategy()) {
|
||||
processor = new AdhikarLoanRepaymentScheduleTransactionProcessor();
|
||||
processor = new RBILoanRepaymentScheduleTransactionProcessor();
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
+15
-3
@@ -7,7 +7,7 @@ import org.mifosng.platform.currency.domain.MonetaryCurrency;
|
||||
import org.mifosng.platform.currency.domain.Money;
|
||||
|
||||
/**
|
||||
* Adhikar style {@link LoanRepaymentScheduleTransactionProcessor}.
|
||||
* Adhikar/RBI style {@link LoanRepaymentScheduleTransactionProcessor}.
|
||||
*
|
||||
* From https://mifosforge.jira.com/browse/MIFOS-5636:
|
||||
*
|
||||
@@ -19,7 +19,7 @@ import org.mifosng.platform.currency.domain.Money;
|
||||
* 20 Payment to interest on Installment #1 (200 principal remaining)
|
||||
* 20 Payment to interest on Installment #2 (200 principal remaining)
|
||||
*/
|
||||
public class AdhikarLoanRepaymentScheduleTransactionProcessor extends AbstractLoanRepaymentScheduleTransactionProcessor {
|
||||
public class RBILoanRepaymentScheduleTransactionProcessor extends AbstractLoanRepaymentScheduleTransactionProcessor {
|
||||
|
||||
/**
|
||||
* For creocore, early is defined as any date before the installment due
|
||||
@@ -83,7 +83,13 @@ public class AdhikarLoanRepaymentScheduleTransactionProcessor extends AbstractLo
|
||||
if (
|
||||
installment.isInterestDue(currency) &&
|
||||
(installment.isOverdueOn(loanTransaction.getTransactionDate()) || installment.getInstallmentNumber().equals(currentInstallmentBasedOnTransactionDate.getInstallmentNumber()))
|
||||
) {
|
||||
) {
|
||||
penaltyChargesPortion = currentInstallment.payPenaltyChargesComponent(transactionAmountRemaining);
|
||||
transactionAmountRemaining = transactionAmountRemaining.minus(penaltyChargesPortion);
|
||||
|
||||
feeChargesPortion = currentInstallment.payFeeChargesComponent(transactionAmountRemaining);
|
||||
transactionAmountRemaining = transactionAmountRemaining.minus(feeChargesPortion);
|
||||
|
||||
Money interestPortion = installment.payInterestComponent(transactionAmountRemaining);
|
||||
transactionAmountRemaining = transactionAmountRemaining.minus(interestPortion);
|
||||
|
||||
@@ -139,6 +145,12 @@ public class AdhikarLoanRepaymentScheduleTransactionProcessor extends AbstractLo
|
||||
interestPortion = currentInstallment.waiveInterestComponent(transactionAmountRemaining);
|
||||
transactionAmountRemaining = transactionAmountRemaining.minus(interestPortion);
|
||||
} else {
|
||||
|
||||
penaltyChargesPortion = currentInstallment.payPenaltyChargesComponent(transactionAmountRemaining);
|
||||
transactionAmountRemaining = transactionAmountRemaining.minus(penaltyChargesPortion);
|
||||
|
||||
feeChargesPortion = currentInstallment.payFeeChargesComponent(transactionAmountRemaining);
|
||||
transactionAmountRemaining = transactionAmountRemaining.minus(feeChargesPortion);
|
||||
|
||||
interestPortion = currentInstallment.payInterestComponent(transactionAmountRemaining);
|
||||
transactionAmountRemaining = transactionAmountRemaining.minus(interestPortion);
|
||||
+2
-2
@@ -18,7 +18,7 @@ import org.mockito.runners.MockitoJUnitRunner;
|
||||
public class AdhikarLoanRepaymentScheduleTransactionProcessorTest {
|
||||
|
||||
// class under test
|
||||
private AdhikarLoanRepaymentScheduleTransactionProcessor processor;
|
||||
private RBILoanRepaymentScheduleTransactionProcessor processor;
|
||||
|
||||
//
|
||||
private LocalDate july2nd = new LocalDate(2012, 7, 2);
|
||||
@@ -30,7 +30,7 @@ public class AdhikarLoanRepaymentScheduleTransactionProcessorTest {
|
||||
|
||||
installments = LoanScheduleTestDataHelper.createSimpleLoanSchedule(july2nd, usDollars);
|
||||
|
||||
processor = new AdhikarLoanRepaymentScheduleTransactionProcessor();
|
||||
processor = new RBILoanRepaymentScheduleTransactionProcessor();
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
Reference in New Issue
Block a user