diff --git a/mifosng-provider/src/main/java/org/mifosng/platform/loan/domain/CreocoreLoanRepaymentScheduleTransactionProcessor.java b/mifosng-provider/src/main/java/org/mifosng/platform/loan/domain/CreocoreLoanRepaymentScheduleTransactionProcessor.java index 013236be9..7cbfbe329 100644 --- a/mifosng-provider/src/main/java/org/mifosng/platform/loan/domain/CreocoreLoanRepaymentScheduleTransactionProcessor.java +++ b/mifosng-provider/src/main/java/org/mifosng/platform/loan/domain/CreocoreLoanRepaymentScheduleTransactionProcessor.java @@ -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); diff --git a/mifosng-provider/src/main/java/org/mifosng/platform/loan/domain/HeavensFamilyLoanRepaymentScheduleTransactionProcessor.java b/mifosng-provider/src/main/java/org/mifosng/platform/loan/domain/HeavensFamilyLoanRepaymentScheduleTransactionProcessor.java index 0bf509ac5..8d753fd18 100644 --- a/mifosng-provider/src/main/java/org/mifosng/platform/loan/domain/HeavensFamilyLoanRepaymentScheduleTransactionProcessor.java +++ b/mifosng-provider/src/main/java/org/mifosng/platform/loan/domain/HeavensFamilyLoanRepaymentScheduleTransactionProcessor.java @@ -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); diff --git a/mifosng-provider/src/main/java/org/mifosng/platform/loan/domain/Loan.java b/mifosng-provider/src/main/java/org/mifosng/platform/loan/domain/Loan.java index 7cd8ec71d..b5c4d5b66 100644 --- a/mifosng-provider/src/main/java/org/mifosng/platform/loan/domain/Loan.java +++ b/mifosng-provider/src/main/java/org/mifosng/platform/loan/domain/Loan.java @@ -261,6 +261,8 @@ public class Loan extends AbstractAuditableCustom { 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 { 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 { 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 { "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) { diff --git a/mifosng-provider/src/main/java/org/mifosng/platform/loan/domain/LoanRepaymentScheduleTransactionProcessorFactory.java b/mifosng-provider/src/main/java/org/mifosng/platform/loan/domain/LoanRepaymentScheduleTransactionProcessorFactory.java index b9000f34e..011b3aedb 100644 --- a/mifosng-provider/src/main/java/org/mifosng/platform/loan/domain/LoanRepaymentScheduleTransactionProcessorFactory.java +++ b/mifosng-provider/src/main/java/org/mifosng/platform/loan/domain/LoanRepaymentScheduleTransactionProcessorFactory.java @@ -25,7 +25,7 @@ public class LoanRepaymentScheduleTransactionProcessorFactory { } if (transactionProcessingStrategy.isIndianRBIStrategy()) { - processor = new AdhikarLoanRepaymentScheduleTransactionProcessor(); + processor = new RBILoanRepaymentScheduleTransactionProcessor(); } } diff --git a/mifosng-provider/src/main/java/org/mifosng/platform/loan/domain/AdhikarLoanRepaymentScheduleTransactionProcessor.java b/mifosng-provider/src/main/java/org/mifosng/platform/loan/domain/RBILoanRepaymentScheduleTransactionProcessor.java similarity index 87% rename from mifosng-provider/src/main/java/org/mifosng/platform/loan/domain/AdhikarLoanRepaymentScheduleTransactionProcessor.java rename to mifosng-provider/src/main/java/org/mifosng/platform/loan/domain/RBILoanRepaymentScheduleTransactionProcessor.java index 521d993d3..6422eb217 100644 --- a/mifosng-provider/src/main/java/org/mifosng/platform/loan/domain/AdhikarLoanRepaymentScheduleTransactionProcessor.java +++ b/mifosng-provider/src/main/java/org/mifosng/platform/loan/domain/RBILoanRepaymentScheduleTransactionProcessor.java @@ -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); diff --git a/mifosng-provider/src/test/java/org/mifosng/platform/loan/domain/AdhikarLoanRepaymentScheduleTransactionProcessorTest.java b/mifosng-provider/src/test/java/org/mifosng/platform/loan/domain/AdhikarLoanRepaymentScheduleTransactionProcessorTest.java index 7f782f1ae..97877de42 100644 --- a/mifosng-provider/src/test/java/org/mifosng/platform/loan/domain/AdhikarLoanRepaymentScheduleTransactionProcessorTest.java +++ b/mifosng-provider/src/test/java/org/mifosng/platform/loan/domain/AdhikarLoanRepaymentScheduleTransactionProcessorTest.java @@ -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(); } /**