MIFOSX-2227 : added mapping between Loan transaction and repayment schedule
This commit is contained in:
+44
-2
@@ -7,6 +7,7 @@ package org.mifosplatform.portfolio.loanaccount.domain;
|
||||
|
||||
import java.math.BigDecimal;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Collection;
|
||||
import java.util.Date;
|
||||
import java.util.HashSet;
|
||||
import java.util.LinkedHashMap;
|
||||
@@ -119,6 +120,11 @@ public final class LoanTransaction extends AbstractPersistable<Long> {
|
||||
@Column(name = "manually_adjusted_or_reversed", nullable = false)
|
||||
private boolean manuallyAdjustedOrReversed;
|
||||
|
||||
@LazyCollection(LazyCollectionOption.FALSE)
|
||||
@OneToMany(cascade = CascadeType.ALL, orphanRemoval = true)
|
||||
@JoinColumn(name = "loan_transaction_id", referencedColumnName= "id" , nullable = false)
|
||||
private Set<LoanTransactionToRepaymentScheduleMapping> loanTransactionToRepaymentScheduleMappings = new HashSet<>();
|
||||
|
||||
protected LoanTransaction() {
|
||||
this.loan = null;
|
||||
this.dateOf = null;
|
||||
@@ -640,9 +646,9 @@ public final class LoanTransaction extends AbstractPersistable<Long> {
|
||||
private LocalDate getCreatedDate() {
|
||||
return new LocalDate(this.createdDate);
|
||||
}
|
||||
|
||||
|
||||
public LocalDateTime getCreatedDateTime() {
|
||||
return new LocalDateTime(this.createdDate);
|
||||
return new LocalDateTime(this.createdDate);
|
||||
}
|
||||
|
||||
public boolean isLastTransaction(final LoanTransaction loanTransaction) {
|
||||
@@ -662,4 +668,40 @@ public final class LoanTransaction extends AbstractPersistable<Long> {
|
||||
}
|
||||
return isLatest;
|
||||
}
|
||||
|
||||
public void updateLoanTransactionToRepaymentScheduleMappings(final Collection<LoanTransactionToRepaymentScheduleMapping> mappings) {
|
||||
Collection<LoanTransactionToRepaymentScheduleMapping> retainMappings = new ArrayList<>();
|
||||
for (LoanTransactionToRepaymentScheduleMapping updatedrepaymentScheduleMapping : mappings) {
|
||||
updateMapingDetail(retainMappings, updatedrepaymentScheduleMapping);
|
||||
}
|
||||
this.loanTransactionToRepaymentScheduleMappings.retainAll(retainMappings);
|
||||
}
|
||||
|
||||
private boolean updateMapingDetail(final Collection<LoanTransactionToRepaymentScheduleMapping> retainMappings,
|
||||
final LoanTransactionToRepaymentScheduleMapping updatedrepaymentScheduleMapping) {
|
||||
boolean isMappingUpdated = false;
|
||||
for (LoanTransactionToRepaymentScheduleMapping repaymentScheduleMapping : this.loanTransactionToRepaymentScheduleMappings) {
|
||||
if (updatedrepaymentScheduleMapping.getLoanRepaymentScheduleInstallment().getId() != null
|
||||
&& repaymentScheduleMapping.getLoanRepaymentScheduleInstallment().getDueDate()
|
||||
.equals(updatedrepaymentScheduleMapping.getLoanRepaymentScheduleInstallment().getDueDate())) {
|
||||
repaymentScheduleMapping.setComponents(updatedrepaymentScheduleMapping.getPrincipalPortion(),
|
||||
updatedrepaymentScheduleMapping.getInterestPortion(), updatedrepaymentScheduleMapping.getFeeChargesPortion(),
|
||||
updatedrepaymentScheduleMapping.getPenaltyChargesPortion());
|
||||
isMappingUpdated = true;
|
||||
retainMappings.add(repaymentScheduleMapping);
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (!isMappingUpdated) {
|
||||
this.loanTransactionToRepaymentScheduleMappings.add(updatedrepaymentScheduleMapping);
|
||||
retainMappings.add(updatedrepaymentScheduleMapping);
|
||||
}
|
||||
return isMappingUpdated;
|
||||
}
|
||||
|
||||
|
||||
public Set<LoanTransactionToRepaymentScheduleMapping> getLoanTransactionToRepaymentScheduleMappings() {
|
||||
return this.loanTransactionToRepaymentScheduleMappings;
|
||||
}
|
||||
|
||||
}
|
||||
+145
@@ -0,0 +1,145 @@
|
||||
/**
|
||||
* This Source Code Form is subject to the terms of the Mozilla Public
|
||||
* License, v. 2.0. If a copy of the MPL was not distributed with this file,
|
||||
* You can obtain one at http://mozilla.org/MPL/2.0/.
|
||||
*/
|
||||
package org.mifosplatform.portfolio.loanaccount.domain;
|
||||
|
||||
import java.math.BigDecimal;
|
||||
|
||||
import javax.persistence.CascadeType;
|
||||
import javax.persistence.Column;
|
||||
import javax.persistence.Entity;
|
||||
import javax.persistence.JoinColumn;
|
||||
import javax.persistence.ManyToOne;
|
||||
import javax.persistence.Table;
|
||||
|
||||
import org.mifosplatform.organisation.monetary.domain.MonetaryCurrency;
|
||||
import org.mifosplatform.organisation.monetary.domain.Money;
|
||||
import org.springframework.data.jpa.domain.AbstractPersistable;
|
||||
|
||||
@Entity
|
||||
@Table(name = "m_loan_transaction_repayment_schedule_mapping")
|
||||
public class LoanTransactionToRepaymentScheduleMapping extends AbstractPersistable<Long> {
|
||||
|
||||
@ManyToOne(optional = false, cascade = CascadeType.PERSIST)
|
||||
@JoinColumn(name = "loan_repayment_schedule_id", nullable = false)
|
||||
private LoanRepaymentScheduleInstallment installment;
|
||||
|
||||
@Column(name = "principal_portion_derived", scale = 6, precision = 19, nullable = true)
|
||||
private BigDecimal principalPortion;
|
||||
|
||||
@Column(name = "interest_portion_derived", scale = 6, precision = 19, nullable = true)
|
||||
private BigDecimal interestPortion;
|
||||
|
||||
@Column(name = "fee_charges_portion_derived", scale = 6, precision = 19, nullable = true)
|
||||
private BigDecimal feeChargesPortion;
|
||||
|
||||
@Column(name = "penalty_charges_portion_derived", scale = 6, precision = 19, nullable = true)
|
||||
private BigDecimal penaltyChargesPortion;
|
||||
|
||||
@Column(name = "amount", scale = 6, precision = 19)
|
||||
private BigDecimal amount;
|
||||
|
||||
protected LoanTransactionToRepaymentScheduleMapping() {
|
||||
|
||||
}
|
||||
|
||||
private LoanTransactionToRepaymentScheduleMapping(final LoanRepaymentScheduleInstallment installment,
|
||||
final BigDecimal principalPortion, final BigDecimal interestPortion, final BigDecimal feeChargesPortion,
|
||||
final BigDecimal penaltyChargesPortion, final BigDecimal amount) {
|
||||
this.installment = installment;
|
||||
this.principalPortion = principalPortion;
|
||||
this.interestPortion = interestPortion;
|
||||
this.feeChargesPortion = feeChargesPortion;
|
||||
this.penaltyChargesPortion = penaltyChargesPortion;
|
||||
this.amount = amount;
|
||||
}
|
||||
|
||||
public static LoanTransactionToRepaymentScheduleMapping createFrom(final LoanRepaymentScheduleInstallment installment,
|
||||
final Money principalPortion, final Money interestPortion, final Money feeChargesPortion, final Money penaltyChargesPortion) {
|
||||
return new LoanTransactionToRepaymentScheduleMapping(installment, defaultToNullIfZero(principalPortion),
|
||||
defaultToNullIfZero(interestPortion), defaultToNullIfZero(feeChargesPortion), defaultToNullIfZero(penaltyChargesPortion),
|
||||
defaultToNullIfZero(principalPortion.plus(interestPortion).plus(feeChargesPortion).plus(penaltyChargesPortion)));
|
||||
}
|
||||
|
||||
private static BigDecimal defaultToNullIfZero(final Money value) {
|
||||
BigDecimal result = value.getAmount();
|
||||
if (value.isZero()) {
|
||||
result = null;
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
private BigDecimal defaultToZeroIfNull(final BigDecimal value) {
|
||||
BigDecimal result = value;
|
||||
if (value == null) {
|
||||
result = BigDecimal.ZERO;
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
public LoanRepaymentScheduleInstallment getLoanRepaymentScheduleInstallment() {
|
||||
return this.installment;
|
||||
}
|
||||
|
||||
public void updateComponents(final Money principal, final Money interest, final Money feeCharges, final Money penaltyCharges) {
|
||||
final MonetaryCurrency currency = principal.getCurrency();
|
||||
this.principalPortion = defaultToNullIfZero(getPrincipalPortion(currency).plus(principal));
|
||||
this.interestPortion = defaultToNullIfZero(getInterestPortion(currency).plus(interest));
|
||||
updateChargesComponents(feeCharges, penaltyCharges);
|
||||
updateAmount();
|
||||
}
|
||||
|
||||
private void updateAmount() {
|
||||
this.amount = defaultToZeroIfNull(getPrincipalPortion()).add(defaultToZeroIfNull(getInterestPortion()))
|
||||
.add(defaultToZeroIfNull(getFeeChargesPortion())).add(defaultToZeroIfNull(getPenaltyChargesPortion()));
|
||||
}
|
||||
|
||||
public void setComponents(final BigDecimal principal, final BigDecimal interest, final BigDecimal feeCharges,
|
||||
final BigDecimal penaltyCharges) {
|
||||
this.principalPortion = principal;
|
||||
this.interestPortion = interest;
|
||||
this.feeChargesPortion = feeCharges;
|
||||
this.penaltyChargesPortion = penaltyCharges;
|
||||
updateAmount();
|
||||
}
|
||||
|
||||
private void updateChargesComponents(final Money feeCharges, final Money penaltyCharges) {
|
||||
final MonetaryCurrency currency = feeCharges.getCurrency();
|
||||
this.feeChargesPortion = defaultToNullIfZero(getFeeChargesPortion(currency).plus(feeCharges));
|
||||
this.penaltyChargesPortion = defaultToNullIfZero(getPenaltyChargesPortion(currency).plus(penaltyCharges));
|
||||
}
|
||||
|
||||
public Money getPrincipalPortion(final MonetaryCurrency currency) {
|
||||
return Money.of(currency, this.principalPortion);
|
||||
}
|
||||
|
||||
public Money getInterestPortion(final MonetaryCurrency currency) {
|
||||
return Money.of(currency, this.interestPortion);
|
||||
}
|
||||
|
||||
public Money getFeeChargesPortion(final MonetaryCurrency currency) {
|
||||
return Money.of(currency, this.feeChargesPortion);
|
||||
}
|
||||
|
||||
public Money getPenaltyChargesPortion(final MonetaryCurrency currency) {
|
||||
return Money.of(currency, this.penaltyChargesPortion);
|
||||
}
|
||||
|
||||
public BigDecimal getPrincipalPortion() {
|
||||
return this.principalPortion;
|
||||
}
|
||||
|
||||
public BigDecimal getInterestPortion() {
|
||||
return this.interestPortion;
|
||||
}
|
||||
|
||||
public BigDecimal getFeeChargesPortion() {
|
||||
return this.feeChargesPortion;
|
||||
}
|
||||
|
||||
public BigDecimal getPenaltyChargesPortion() {
|
||||
return this.penaltyChargesPortion;
|
||||
}
|
||||
}
|
||||
+32
-12
@@ -24,6 +24,7 @@ import org.mifosplatform.portfolio.loanaccount.domain.LoanInstallmentCharge;
|
||||
import org.mifosplatform.portfolio.loanaccount.domain.LoanRepaymentScheduleInstallment;
|
||||
import org.mifosplatform.portfolio.loanaccount.domain.LoanRepaymentScheduleProcessingWrapper;
|
||||
import org.mifosplatform.portfolio.loanaccount.domain.LoanTransaction;
|
||||
import org.mifosplatform.portfolio.loanaccount.domain.LoanTransactionToRepaymentScheduleMapping;
|
||||
import org.mifosplatform.portfolio.loanaccount.domain.LoanTransactionType;
|
||||
import org.mifosplatform.portfolio.loanaccount.domain.transactionprocessor.impl.CreocoreLoanRepaymentScheduleTransactionProcessor;
|
||||
import org.mifosplatform.portfolio.loanaccount.domain.transactionprocessor.impl.HeavensFamilyLoanRepaymentScheduleTransactionProcessor;
|
||||
@@ -170,7 +171,9 @@ public abstract class AbstractLoanRepaymentScheduleTransactionProcessor implemen
|
||||
* reverse the original transaction and update
|
||||
* changedTransactionDetail accordingly
|
||||
**/
|
||||
if (!LoanTransaction.transactionAmountsMatch(currency, loanTransaction, newLoanTransaction)) {
|
||||
if (LoanTransaction.transactionAmountsMatch(currency, loanTransaction, newLoanTransaction)) {
|
||||
loanTransaction.updateLoanTransactionToRepaymentScheduleMappings(newLoanTransaction.getLoanTransactionToRepaymentScheduleMappings());
|
||||
} else{
|
||||
loanTransaction.reverse();
|
||||
loanTransaction.updateExternalId(null);
|
||||
changedTransactionDetail.getNewTransactionMappings().put(loanTransaction.getId(), newLoanTransaction);
|
||||
@@ -267,6 +270,7 @@ public abstract class AbstractLoanRepaymentScheduleTransactionProcessor implemen
|
||||
if (amountToProcess != null) {
|
||||
transactionAmountUnprocessed = amountToProcess;
|
||||
}
|
||||
List<LoanTransactionToRepaymentScheduleMapping> transactionMappings = new ArrayList<>();
|
||||
|
||||
for (final LoanRepaymentScheduleInstallment currentInstallment : installments) {
|
||||
if (transactionAmountUnprocessed.isGreaterThanZero()) {
|
||||
@@ -277,23 +281,24 @@ public abstract class AbstractLoanRepaymentScheduleTransactionProcessor implemen
|
||||
// current installment?
|
||||
if (isTransactionInAdvanceOfInstallment(installmentIndex, installments, transactionDate, transactionAmountUnprocessed)) {
|
||||
transactionAmountUnprocessed = handleTransactionThatIsPaymentInAdvanceOfInstallment(currentInstallment,
|
||||
installments, loanTransaction, transactionDate, transactionAmountUnprocessed);
|
||||
installments, loanTransaction, transactionDate, transactionAmountUnprocessed, transactionMappings);
|
||||
} else if (isTransactionALateRepaymentOnInstallment(installmentIndex, installments,
|
||||
loanTransaction.getTransactionDate())) {
|
||||
// does this result in a late payment of existing
|
||||
// installment?
|
||||
transactionAmountUnprocessed = handleTransactionThatIsALateRepaymentOfInstallment(currentInstallment, installments,
|
||||
loanTransaction, transactionAmountUnprocessed);
|
||||
loanTransaction, transactionAmountUnprocessed, transactionMappings);
|
||||
} else {
|
||||
// standard transaction
|
||||
transactionAmountUnprocessed = handleTransactionThatIsOnTimePaymentOfInstallment(currentInstallment,
|
||||
loanTransaction, transactionAmountUnprocessed);
|
||||
loanTransaction, transactionAmountUnprocessed, transactionMappings);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
installmentIndex++;
|
||||
}
|
||||
loanTransaction.updateLoanTransactionToRepaymentScheduleMappings(transactionMappings);
|
||||
return transactionAmountUnprocessed;
|
||||
}
|
||||
|
||||
@@ -327,7 +332,7 @@ public abstract class AbstractLoanRepaymentScheduleTransactionProcessor implemen
|
||||
if (loanTransaction.isChargePayment()) {
|
||||
feeAmount = feeCharges;
|
||||
}
|
||||
if(unpaidCharge == null) break ; //All are trache charges
|
||||
if (unpaidCharge == null) break; // All are trache charges
|
||||
final Money amountPaidTowardsCharge = unpaidCharge.updatePaidAmountBy(amountRemaining, installmentNumber, feeAmount);
|
||||
if (!amountPaidTowardsCharge.isZero()) {
|
||||
Set<LoanChargePaidBy> chargesPaidBies = loanTransaction.getLoanChargesPaid();
|
||||
@@ -421,10 +426,13 @@ public abstract class AbstractLoanRepaymentScheduleTransactionProcessor implemen
|
||||
|
||||
/**
|
||||
* For late repayments, how should components of installment be paid off
|
||||
*
|
||||
* @param transactionMappings
|
||||
* TODO
|
||||
*/
|
||||
protected abstract Money handleTransactionThatIsALateRepaymentOfInstallment(final LoanRepaymentScheduleInstallment currentInstallment,
|
||||
final List<LoanRepaymentScheduleInstallment> installments, final LoanTransaction loanTransaction,
|
||||
final Money transactionAmountUnprocessed);
|
||||
final Money transactionAmountUnprocessed, final List<LoanTransactionToRepaymentScheduleMapping> transactionMappings);
|
||||
|
||||
/**
|
||||
* This method is responsible for checking if the current transaction is 'an
|
||||
@@ -444,16 +452,24 @@ public abstract class AbstractLoanRepaymentScheduleTransactionProcessor implemen
|
||||
|
||||
/**
|
||||
* For early/'in advance' repayments.
|
||||
*
|
||||
* @param transactionMappings
|
||||
* TODO
|
||||
*/
|
||||
protected abstract Money handleTransactionThatIsPaymentInAdvanceOfInstallment(
|
||||
final LoanRepaymentScheduleInstallment currentInstallment, final List<LoanRepaymentScheduleInstallment> installments,
|
||||
final LoanTransaction loanTransaction, final LocalDate transactionDate, final Money paymentInAdvance);
|
||||
final LoanTransaction loanTransaction, final LocalDate transactionDate, final Money paymentInAdvance,
|
||||
final List<LoanTransactionToRepaymentScheduleMapping> transactionMappings);
|
||||
|
||||
/**
|
||||
* For normal on-time repayments.
|
||||
*
|
||||
* @param transactionMappings
|
||||
* TODO
|
||||
*/
|
||||
protected abstract Money handleTransactionThatIsOnTimePaymentOfInstallment(final LoanRepaymentScheduleInstallment currentInstallment,
|
||||
final LoanTransaction loanTransaction, final Money transactionAmountUnprocessed);
|
||||
final LoanTransaction loanTransaction, final Money transactionAmountUnprocessed,
|
||||
final List<LoanTransactionToRepaymentScheduleMapping> transactionMappings);
|
||||
|
||||
/**
|
||||
* Invoked when a transaction results in an over-payment of the full loan.
|
||||
@@ -489,7 +505,7 @@ public abstract class AbstractLoanRepaymentScheduleTransactionProcessor implemen
|
||||
public void handleRefund(LoanTransaction loanTransaction, MonetaryCurrency currency,
|
||||
List<LoanRepaymentScheduleInstallment> installments, final Set<LoanCharge> charges) {
|
||||
// TODO Auto-generated method stub
|
||||
|
||||
List<LoanTransactionToRepaymentScheduleMapping> transactionMappings = new ArrayList<>();
|
||||
final Comparator<LoanRepaymentScheduleInstallment> byDate = new Comparator<LoanRepaymentScheduleInstallment>() {
|
||||
|
||||
@Override
|
||||
@@ -506,7 +522,7 @@ public abstract class AbstractLoanRepaymentScheduleTransactionProcessor implemen
|
||||
|
||||
if (outstanding.isLessThan(due)) {
|
||||
transactionAmountUnprocessed = handleRefundTransactionPaymentOfInstallment(currentInstallment, loanTransaction,
|
||||
transactionAmountUnprocessed);
|
||||
transactionAmountUnprocessed, transactionMappings);
|
||||
|
||||
}
|
||||
|
||||
@@ -527,7 +543,7 @@ public abstract class AbstractLoanRepaymentScheduleTransactionProcessor implemen
|
||||
if (penaltyCharges.isGreaterThanZero()) {
|
||||
undoChargesPaidAmountBy(loanTransaction, penaltyCharges, loanPenalties, installmentNumber);
|
||||
}
|
||||
|
||||
loanTransaction.updateLoanTransactionToRepaymentScheduleMappings(transactionMappings);
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -537,9 +553,13 @@ public abstract class AbstractLoanRepaymentScheduleTransactionProcessor implemen
|
||||
* Undoes principal, interest, fees and charges of this transaction based on
|
||||
* the repayment strategy
|
||||
*
|
||||
* @param transactionMappings
|
||||
* TODO
|
||||
*
|
||||
*/
|
||||
protected abstract Money handleRefundTransactionPaymentOfInstallment(final LoanRepaymentScheduleInstallment currentInstallment,
|
||||
final LoanTransaction loanTransaction, final Money transactionAmountUnprocessed);
|
||||
final LoanTransaction loanTransaction, final Money transactionAmountUnprocessed,
|
||||
final List<LoanTransactionToRepaymentScheduleMapping> transactionMappings);
|
||||
|
||||
private void undoChargesPaidAmountBy(final LoanTransaction loanTransaction, final Money feeCharges, final Set<LoanCharge> charges,
|
||||
final Integer installmentNumber) {
|
||||
|
||||
+32
-21
@@ -12,6 +12,7 @@ import org.mifosplatform.organisation.monetary.domain.MonetaryCurrency;
|
||||
import org.mifosplatform.organisation.monetary.domain.Money;
|
||||
import org.mifosplatform.portfolio.loanaccount.domain.LoanRepaymentScheduleInstallment;
|
||||
import org.mifosplatform.portfolio.loanaccount.domain.LoanTransaction;
|
||||
import org.mifosplatform.portfolio.loanaccount.domain.LoanTransactionToRepaymentScheduleMapping;
|
||||
import org.mifosplatform.portfolio.loanaccount.domain.transactionprocessor.AbstractLoanRepaymentScheduleTransactionProcessor;
|
||||
import org.mifosplatform.portfolio.loanaccount.domain.transactionprocessor.LoanRepaymentScheduleTransactionProcessor;
|
||||
|
||||
@@ -52,9 +53,10 @@ public class CreocoreLoanRepaymentScheduleTransactionProcessor extends AbstractL
|
||||
@Override
|
||||
protected Money handleTransactionThatIsPaymentInAdvanceOfInstallment(final LoanRepaymentScheduleInstallment currentInstallment,
|
||||
final List<LoanRepaymentScheduleInstallment> installments, final LoanTransaction loanTransaction,
|
||||
final LocalDate transactionDate, final Money paymentInAdvance) {
|
||||
final LocalDate transactionDate, final Money paymentInAdvance,
|
||||
final List<LoanTransactionToRepaymentScheduleMapping> transactionMappings) {
|
||||
|
||||
return handleTransactionThatIsOnTimePaymentOfInstallment(currentInstallment, loanTransaction, paymentInAdvance);
|
||||
return handleTransactionThatIsOnTimePaymentOfInstallment(currentInstallment, loanTransaction, paymentInAdvance, transactionMappings);
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -65,9 +67,10 @@ public class CreocoreLoanRepaymentScheduleTransactionProcessor extends AbstractL
|
||||
@Override
|
||||
protected Money handleTransactionThatIsALateRepaymentOfInstallment(final LoanRepaymentScheduleInstallment currentInstallment,
|
||||
final List<LoanRepaymentScheduleInstallment> installments, final LoanTransaction loanTransaction,
|
||||
final Money transactionAmountUnprocessed) {
|
||||
final Money transactionAmountUnprocessed, final List<LoanTransactionToRepaymentScheduleMapping> transactionMappings) {
|
||||
|
||||
return handleTransactionThatIsOnTimePaymentOfInstallment(currentInstallment, loanTransaction, transactionAmountUnprocessed);
|
||||
return handleTransactionThatIsOnTimePaymentOfInstallment(currentInstallment, loanTransaction, transactionAmountUnprocessed,
|
||||
transactionMappings);
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -75,7 +78,8 @@ public class CreocoreLoanRepaymentScheduleTransactionProcessor extends AbstractL
|
||||
*/
|
||||
@Override
|
||||
protected Money handleTransactionThatIsOnTimePaymentOfInstallment(final LoanRepaymentScheduleInstallment currentInstallment,
|
||||
final LoanTransaction loanTransaction, final Money transactionAmountUnprocessed) {
|
||||
final LoanTransaction loanTransaction, final Money transactionAmountUnprocessed,
|
||||
final List<LoanTransactionToRepaymentScheduleMapping> transactionMappings) {
|
||||
|
||||
final LocalDate transactionDate = loanTransaction.getTransactionDate();
|
||||
final MonetaryCurrency currency = transactionAmountUnprocessed.getCurrency();
|
||||
@@ -119,7 +123,10 @@ public class CreocoreLoanRepaymentScheduleTransactionProcessor extends AbstractL
|
||||
principalPortion = currentInstallment.payPrincipalComponent(transactionDate, transactionAmountRemaining);
|
||||
transactionAmountRemaining = transactionAmountRemaining.minus(principalPortion);
|
||||
}
|
||||
|
||||
if (principalPortion.plus(interestPortion).plus(feeChargesPortion).plus(penaltyChargesPortion).isGreaterThanZero()) {
|
||||
transactionMappings.add(LoanTransactionToRepaymentScheduleMapping.createFrom(currentInstallment, principalPortion,
|
||||
interestPortion, feeChargesPortion, penaltyChargesPortion));
|
||||
}
|
||||
loanTransaction.updateComponents(principalPortion, interestPortion, feeChargesPortion, penaltyChargesPortion);
|
||||
return transactionAmountRemaining;
|
||||
}
|
||||
@@ -129,10 +136,11 @@ public class CreocoreLoanRepaymentScheduleTransactionProcessor extends AbstractL
|
||||
protected void onLoanOverpayment(final LoanTransaction loanTransaction, final Money loanOverPaymentAmount) {
|
||||
// dont do anything for with loan over-payment
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
protected Money handleRefundTransactionPaymentOfInstallment(final LoanRepaymentScheduleInstallment currentInstallment,
|
||||
final LoanTransaction loanTransaction, final Money transactionAmountUnprocessed) {
|
||||
final LoanTransaction loanTransaction, final Money transactionAmountUnprocessed,
|
||||
List<LoanTransactionToRepaymentScheduleMapping> transactionMappings) {
|
||||
|
||||
final LocalDate transactionDate = loanTransaction.getTransactionDate();
|
||||
Money transactionAmountRemaining = transactionAmountUnprocessed;
|
||||
@@ -140,26 +148,29 @@ public class CreocoreLoanRepaymentScheduleTransactionProcessor extends AbstractL
|
||||
Money interestPortion = Money.zero(transactionAmountRemaining.getCurrency());
|
||||
Money feeChargesPortion = Money.zero(transactionAmountRemaining.getCurrency());
|
||||
Money penaltyChargesPortion = Money.zero(transactionAmountRemaining.getCurrency());
|
||||
|
||||
|
||||
principalPortion = currentInstallment.unpayPrincipalComponent(transactionDate, transactionAmountRemaining);
|
||||
transactionAmountRemaining = transactionAmountRemaining.minus(principalPortion);
|
||||
|
||||
if(transactionAmountRemaining.isGreaterThanZero()) {
|
||||
interestPortion = currentInstallment.unpayInterestComponent(transactionDate, transactionAmountRemaining);
|
||||
|
||||
if (transactionAmountRemaining.isGreaterThanZero()) {
|
||||
interestPortion = currentInstallment.unpayInterestComponent(transactionDate, transactionAmountRemaining);
|
||||
transactionAmountRemaining = transactionAmountRemaining.minus(interestPortion);
|
||||
}
|
||||
|
||||
if(transactionAmountRemaining.isGreaterThanZero()) {
|
||||
feeChargesPortion = currentInstallment.unpayFeeChargesComponent(transactionDate, transactionAmountRemaining);
|
||||
transactionAmountRemaining = transactionAmountRemaining.minus(feeChargesPortion);
|
||||
|
||||
if (transactionAmountRemaining.isGreaterThanZero()) {
|
||||
feeChargesPortion = currentInstallment.unpayFeeChargesComponent(transactionDate, transactionAmountRemaining);
|
||||
transactionAmountRemaining = transactionAmountRemaining.minus(feeChargesPortion);
|
||||
}
|
||||
|
||||
if(transactionAmountRemaining.isGreaterThanZero()) {
|
||||
penaltyChargesPortion = currentInstallment.unpayPenaltyChargesComponent(transactionDate, transactionAmountRemaining);
|
||||
transactionAmountRemaining = transactionAmountRemaining.minus(penaltyChargesPortion);
|
||||
|
||||
if (transactionAmountRemaining.isGreaterThanZero()) {
|
||||
penaltyChargesPortion = currentInstallment.unpayPenaltyChargesComponent(transactionDate, transactionAmountRemaining);
|
||||
transactionAmountRemaining = transactionAmountRemaining.minus(penaltyChargesPortion);
|
||||
}
|
||||
loanTransaction.updateComponents(principalPortion, interestPortion, feeChargesPortion, penaltyChargesPortion);
|
||||
|
||||
if (principalPortion.plus(interestPortion).plus(feeChargesPortion).plus(penaltyChargesPortion).isGreaterThanZero()) {
|
||||
transactionMappings.add(LoanTransactionToRepaymentScheduleMapping.createFrom(currentInstallment, principalPortion,
|
||||
interestPortion, feeChargesPortion, penaltyChargesPortion));
|
||||
}
|
||||
return transactionAmountRemaining;
|
||||
}
|
||||
}
|
||||
+22
-8
@@ -12,6 +12,7 @@ import org.mifosplatform.organisation.monetary.domain.MonetaryCurrency;
|
||||
import org.mifosplatform.organisation.monetary.domain.Money;
|
||||
import org.mifosplatform.portfolio.loanaccount.domain.LoanRepaymentScheduleInstallment;
|
||||
import org.mifosplatform.portfolio.loanaccount.domain.LoanTransaction;
|
||||
import org.mifosplatform.portfolio.loanaccount.domain.LoanTransactionToRepaymentScheduleMapping;
|
||||
import org.mifosplatform.portfolio.loanaccount.domain.transactionprocessor.AbstractLoanRepaymentScheduleTransactionProcessor;
|
||||
import org.mifosplatform.portfolio.loanaccount.domain.transactionprocessor.LoanRepaymentScheduleTransactionProcessor;
|
||||
|
||||
@@ -29,7 +30,8 @@ public class EarlyPaymentLoanRepaymentScheduleTransactionProcessor extends Abstr
|
||||
@Override
|
||||
protected Money handleTransactionThatIsPaymentInAdvanceOfInstallment(final LoanRepaymentScheduleInstallment currentInstallment,
|
||||
final List<LoanRepaymentScheduleInstallment> installments, final LoanTransaction loanTransaction,
|
||||
final LocalDate transactionDate, final Money paymentInAdvance) {
|
||||
final LocalDate transactionDate, final Money paymentInAdvance,
|
||||
final List<LoanTransactionToRepaymentScheduleMapping> transactionMappings) {
|
||||
|
||||
final MonetaryCurrency currency = paymentInAdvance.getCurrency();
|
||||
Money transactionAmountRemaining = paymentInAdvance;
|
||||
@@ -69,7 +71,10 @@ public class EarlyPaymentLoanRepaymentScheduleTransactionProcessor extends Abstr
|
||||
|
||||
loanTransaction.updateComponents(principalPortion, interestPortion, feeChargesPortion, penaltyChargesPortion);
|
||||
}
|
||||
|
||||
if (principalPortion.plus(interestPortion).plus(feeChargesPortion).plus(penaltyChargesPortion).isGreaterThanZero()) {
|
||||
transactionMappings.add(LoanTransactionToRepaymentScheduleMapping.createFrom(currentInstallment, principalPortion,
|
||||
interestPortion, feeChargesPortion, penaltyChargesPortion));
|
||||
}
|
||||
return transactionAmountRemaining;
|
||||
|
||||
}
|
||||
@@ -82,9 +87,10 @@ public class EarlyPaymentLoanRepaymentScheduleTransactionProcessor extends Abstr
|
||||
@Override
|
||||
protected Money handleTransactionThatIsALateRepaymentOfInstallment(final LoanRepaymentScheduleInstallment currentInstallment,
|
||||
final List<LoanRepaymentScheduleInstallment> installments, final LoanTransaction loanTransaction,
|
||||
final Money transactionAmountUnprocessed) {
|
||||
final Money transactionAmountUnprocessed, List<LoanTransactionToRepaymentScheduleMapping> transactionMappings) {
|
||||
|
||||
return handleTransactionThatIsOnTimePaymentOfInstallment(currentInstallment, loanTransaction, transactionAmountUnprocessed);
|
||||
return handleTransactionThatIsOnTimePaymentOfInstallment(currentInstallment, loanTransaction, transactionAmountUnprocessed,
|
||||
transactionMappings);
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -92,7 +98,8 @@ public class EarlyPaymentLoanRepaymentScheduleTransactionProcessor extends Abstr
|
||||
*/
|
||||
@Override
|
||||
protected Money handleTransactionThatIsOnTimePaymentOfInstallment(final LoanRepaymentScheduleInstallment currentInstallment,
|
||||
final LoanTransaction loanTransaction, final Money transactionAmountUnprocessed) {
|
||||
final LoanTransaction loanTransaction, final Money transactionAmountUnprocessed,
|
||||
final List<LoanTransactionToRepaymentScheduleMapping> transactionMappings) {
|
||||
|
||||
final LocalDate transactionDate = loanTransaction.getTransactionDate();
|
||||
final MonetaryCurrency currency = transactionAmountUnprocessed.getCurrency();
|
||||
@@ -134,13 +141,17 @@ public class EarlyPaymentLoanRepaymentScheduleTransactionProcessor extends Abstr
|
||||
|
||||
loanTransaction.updateComponents(principalPortion, interestPortion, feeChargesPortion, penaltyChargesPortion);
|
||||
}
|
||||
|
||||
if (principalPortion.plus(interestPortion).plus(feeChargesPortion).plus(penaltyChargesPortion).isGreaterThanZero()) {
|
||||
transactionMappings.add(LoanTransactionToRepaymentScheduleMapping.createFrom(currentInstallment, principalPortion,
|
||||
interestPortion, feeChargesPortion, penaltyChargesPortion));
|
||||
}
|
||||
return transactionAmountRemaining;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected Money handleRefundTransactionPaymentOfInstallment(final LoanRepaymentScheduleInstallment currentInstallment,
|
||||
final LoanTransaction loanTransaction, final Money transactionAmountUnprocessed) {
|
||||
final LoanTransaction loanTransaction, final Money transactionAmountUnprocessed,
|
||||
List<LoanTransactionToRepaymentScheduleMapping> transactionMappings) {
|
||||
|
||||
final LocalDate transactionDate = loanTransaction.getTransactionDate();
|
||||
// final MonetaryCurrency currency =
|
||||
@@ -172,7 +183,10 @@ public class EarlyPaymentLoanRepaymentScheduleTransactionProcessor extends Abstr
|
||||
}
|
||||
|
||||
loanTransaction.updateComponents(principalPortion, interestPortion, feeChargesPortion, penaltyChargesPortion);
|
||||
|
||||
if (principalPortion.plus(interestPortion).plus(feeChargesPortion).plus(penaltyChargesPortion).isGreaterThanZero()) {
|
||||
transactionMappings.add(LoanTransactionToRepaymentScheduleMapping.createFrom(currentInstallment, principalPortion,
|
||||
interestPortion, feeChargesPortion, penaltyChargesPortion));
|
||||
}
|
||||
return transactionAmountRemaining;
|
||||
}
|
||||
|
||||
|
||||
+23
-7
@@ -12,6 +12,7 @@ import org.mifosplatform.organisation.monetary.domain.MonetaryCurrency;
|
||||
import org.mifosplatform.organisation.monetary.domain.Money;
|
||||
import org.mifosplatform.portfolio.loanaccount.domain.LoanRepaymentScheduleInstallment;
|
||||
import org.mifosplatform.portfolio.loanaccount.domain.LoanTransaction;
|
||||
import org.mifosplatform.portfolio.loanaccount.domain.LoanTransactionToRepaymentScheduleMapping;
|
||||
import org.mifosplatform.portfolio.loanaccount.domain.transactionprocessor.AbstractLoanRepaymentScheduleTransactionProcessor;
|
||||
import org.mifosplatform.portfolio.loanaccount.domain.transactionprocessor.LoanRepaymentScheduleTransactionProcessor;
|
||||
|
||||
@@ -38,9 +39,10 @@ public class HeavensFamilyLoanRepaymentScheduleTransactionProcessor extends Abst
|
||||
@Override
|
||||
protected Money handleTransactionThatIsALateRepaymentOfInstallment(final LoanRepaymentScheduleInstallment currentInstallment,
|
||||
final List<LoanRepaymentScheduleInstallment> installments, final LoanTransaction loanTransaction,
|
||||
final Money transactionAmountUnprocessed) {
|
||||
final Money transactionAmountUnprocessed, List<LoanTransactionToRepaymentScheduleMapping> transactionMappings) {
|
||||
|
||||
return handleTransactionThatIsOnTimePaymentOfInstallment(currentInstallment, loanTransaction, transactionAmountUnprocessed);
|
||||
return handleTransactionThatIsOnTimePaymentOfInstallment(currentInstallment, loanTransaction, transactionAmountUnprocessed,
|
||||
transactionMappings);
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -69,7 +71,8 @@ public class HeavensFamilyLoanRepaymentScheduleTransactionProcessor extends Abst
|
||||
@Override
|
||||
protected Money handleTransactionThatIsPaymentInAdvanceOfInstallment(final LoanRepaymentScheduleInstallment currentInstallment,
|
||||
final List<LoanRepaymentScheduleInstallment> installments, final LoanTransaction loanTransaction,
|
||||
final LocalDate transactionDate, final Money paymentInAdvance) {
|
||||
final LocalDate transactionDate, final Money paymentInAdvance,
|
||||
final List<LoanTransactionToRepaymentScheduleMapping> transactionMappings) {
|
||||
|
||||
final MonetaryCurrency currency = paymentInAdvance.getCurrency();
|
||||
Money transactionAmountRemaining = paymentInAdvance;
|
||||
@@ -120,6 +123,10 @@ public class HeavensFamilyLoanRepaymentScheduleTransactionProcessor extends Abst
|
||||
}
|
||||
|
||||
loanTransaction.updateComponents(principalPortion, interestPortion, feeChargesPortion, penaltyChargesPortion);
|
||||
if (principalPortion.plus(interestPortion).plus(feeChargesPortion).plus(penaltyChargesPortion).isGreaterThanZero()) {
|
||||
transactionMappings.add(LoanTransactionToRepaymentScheduleMapping.createFrom(currentInstallment, principalPortion,
|
||||
interestPortion, feeChargesPortion, penaltyChargesPortion));
|
||||
}
|
||||
return transactionAmountRemaining;
|
||||
}
|
||||
|
||||
@@ -128,7 +135,8 @@ public class HeavensFamilyLoanRepaymentScheduleTransactionProcessor extends Abst
|
||||
*/
|
||||
@Override
|
||||
protected Money handleTransactionThatIsOnTimePaymentOfInstallment(final LoanRepaymentScheduleInstallment currentInstallment,
|
||||
final LoanTransaction loanTransaction, final Money transactionAmountUnprocessed) {
|
||||
final LoanTransaction loanTransaction, final Money transactionAmountUnprocessed,
|
||||
List<LoanTransactionToRepaymentScheduleMapping> transactionMappings) {
|
||||
|
||||
final LocalDate transactionDate = loanTransaction.getTransactionDate();
|
||||
final MonetaryCurrency currency = transactionAmountUnprocessed.getCurrency();
|
||||
@@ -176,15 +184,20 @@ public class HeavensFamilyLoanRepaymentScheduleTransactionProcessor extends Abst
|
||||
}
|
||||
|
||||
loanTransaction.updateComponents(principalPortion, interestPortion, feeChargesPortion, penaltyChargesPortion);
|
||||
if (principalPortion.plus(interestPortion).plus(feeChargesPortion).plus(penaltyChargesPortion).isGreaterThanZero()) {
|
||||
transactionMappings.add(LoanTransactionToRepaymentScheduleMapping.createFrom(currentInstallment, principalPortion,
|
||||
interestPortion, feeChargesPortion, penaltyChargesPortion));
|
||||
}
|
||||
return transactionAmountRemaining;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void onLoanOverpayment(final LoanTransaction loanTransaction, final Money loanOverPaymentAmount) {}
|
||||
|
||||
|
||||
@Override
|
||||
protected Money handleRefundTransactionPaymentOfInstallment(final LoanRepaymentScheduleInstallment currentInstallment,
|
||||
final LoanTransaction loanTransaction, final Money transactionAmountUnprocessed) {
|
||||
final LoanTransaction loanTransaction, final Money transactionAmountUnprocessed,
|
||||
List<LoanTransactionToRepaymentScheduleMapping> transactionMappings) {
|
||||
|
||||
final LocalDate transactionDate = loanTransaction.getTransactionDate();
|
||||
final MonetaryCurrency currency = transactionAmountUnprocessed.getCurrency();
|
||||
@@ -215,7 +228,10 @@ public class HeavensFamilyLoanRepaymentScheduleTransactionProcessor extends Abst
|
||||
}
|
||||
|
||||
loanTransaction.updateComponents(principalPortion, interestPortion, feeChargesPortion, penaltyChargesPortion);
|
||||
|
||||
if (principalPortion.plus(interestPortion).plus(feeChargesPortion).plus(penaltyChargesPortion).isGreaterThanZero()) {
|
||||
transactionMappings.add(LoanTransactionToRepaymentScheduleMapping.createFrom(currentInstallment, principalPortion,
|
||||
interestPortion, feeChargesPortion, penaltyChargesPortion));
|
||||
}
|
||||
return transactionAmountRemaining;
|
||||
}
|
||||
}
|
||||
+20
-9
@@ -12,6 +12,7 @@ import org.mifosplatform.organisation.monetary.domain.MonetaryCurrency;
|
||||
import org.mifosplatform.organisation.monetary.domain.Money;
|
||||
import org.mifosplatform.portfolio.loanaccount.domain.LoanRepaymentScheduleInstallment;
|
||||
import org.mifosplatform.portfolio.loanaccount.domain.LoanTransaction;
|
||||
import org.mifosplatform.portfolio.loanaccount.domain.LoanTransactionToRepaymentScheduleMapping;
|
||||
import org.mifosplatform.portfolio.loanaccount.domain.transactionprocessor.AbstractLoanRepaymentScheduleTransactionProcessor;
|
||||
import org.mifosplatform.portfolio.loanaccount.domain.transactionprocessor.LoanRepaymentScheduleTransactionProcessor;
|
||||
|
||||
@@ -30,9 +31,10 @@ public class InterestPrincipalPenaltyFeesOrderLoanRepaymentScheduleTransactionPr
|
||||
@Override
|
||||
protected Money handleTransactionThatIsPaymentInAdvanceOfInstallment(final LoanRepaymentScheduleInstallment currentInstallment,
|
||||
final List<LoanRepaymentScheduleInstallment> installments, final LoanTransaction loanTransaction,
|
||||
final LocalDate transactionDate, final Money paymentInAdvance) {
|
||||
final LocalDate transactionDate, final Money paymentInAdvance,
|
||||
List<LoanTransactionToRepaymentScheduleMapping> transactionMappings) {
|
||||
|
||||
return handleTransactionThatIsOnTimePaymentOfInstallment(currentInstallment, loanTransaction, paymentInAdvance);
|
||||
return handleTransactionThatIsOnTimePaymentOfInstallment(currentInstallment, loanTransaction, paymentInAdvance, transactionMappings);
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -43,9 +45,10 @@ public class InterestPrincipalPenaltyFeesOrderLoanRepaymentScheduleTransactionPr
|
||||
@Override
|
||||
protected Money handleTransactionThatIsALateRepaymentOfInstallment(final LoanRepaymentScheduleInstallment currentInstallment,
|
||||
final List<LoanRepaymentScheduleInstallment> installments, final LoanTransaction loanTransaction,
|
||||
final Money transactionAmountUnprocessed) {
|
||||
final Money transactionAmountUnprocessed, List<LoanTransactionToRepaymentScheduleMapping> transactionMappings) {
|
||||
|
||||
return handleTransactionThatIsOnTimePaymentOfInstallment(currentInstallment, loanTransaction, transactionAmountUnprocessed);
|
||||
return handleTransactionThatIsOnTimePaymentOfInstallment(currentInstallment, loanTransaction, transactionAmountUnprocessed,
|
||||
transactionMappings);
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -53,7 +56,8 @@ public class InterestPrincipalPenaltyFeesOrderLoanRepaymentScheduleTransactionPr
|
||||
*/
|
||||
@Override
|
||||
protected Money handleTransactionThatIsOnTimePaymentOfInstallment(final LoanRepaymentScheduleInstallment currentInstallment,
|
||||
final LoanTransaction loanTransaction, final Money transactionAmountUnprocessed) {
|
||||
final LoanTransaction loanTransaction, final Money transactionAmountUnprocessed,
|
||||
List<LoanTransactionToRepaymentScheduleMapping> transactionMappings) {
|
||||
|
||||
final LocalDate transactionDate = loanTransaction.getTransactionDate();
|
||||
final MonetaryCurrency currency = transactionAmountUnprocessed.getCurrency();
|
||||
@@ -101,13 +105,17 @@ public class InterestPrincipalPenaltyFeesOrderLoanRepaymentScheduleTransactionPr
|
||||
|
||||
loanTransaction.updateComponents(principalPortion, interestPortion, feeChargesPortion, penaltyChargesPortion);
|
||||
}
|
||||
|
||||
if (principalPortion.plus(interestPortion).plus(feeChargesPortion).plus(penaltyChargesPortion).isGreaterThanZero()) {
|
||||
transactionMappings.add(LoanTransactionToRepaymentScheduleMapping.createFrom(currentInstallment, principalPortion,
|
||||
interestPortion, feeChargesPortion, penaltyChargesPortion));
|
||||
}
|
||||
return transactionAmountRemaining;
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
protected Money handleRefundTransactionPaymentOfInstallment(final LoanRepaymentScheduleInstallment currentInstallment,
|
||||
final LoanTransaction loanTransaction, final Money transactionAmountUnprocessed) {
|
||||
final LoanTransaction loanTransaction, final Money transactionAmountUnprocessed,
|
||||
List<LoanTransactionToRepaymentScheduleMapping> transactionMappings) {
|
||||
|
||||
final LocalDate transactionDate = loanTransaction.getTransactionDate();
|
||||
Money transactionAmountRemaining = transactionAmountUnprocessed;
|
||||
@@ -137,7 +145,10 @@ public class InterestPrincipalPenaltyFeesOrderLoanRepaymentScheduleTransactionPr
|
||||
}
|
||||
|
||||
loanTransaction.updateComponents(principalPortion, interestPortion, feeChargesPortion, penaltyChargesPortion);
|
||||
|
||||
if (principalPortion.plus(interestPortion).plus(feeChargesPortion).plus(penaltyChargesPortion).isGreaterThanZero()) {
|
||||
transactionMappings.add(LoanTransactionToRepaymentScheduleMapping.createFrom(currentInstallment, principalPortion,
|
||||
interestPortion, feeChargesPortion, penaltyChargesPortion));
|
||||
}
|
||||
return transactionAmountRemaining;
|
||||
}
|
||||
}
|
||||
+20
-9
@@ -12,6 +12,7 @@ import org.mifosplatform.organisation.monetary.domain.MonetaryCurrency;
|
||||
import org.mifosplatform.organisation.monetary.domain.Money;
|
||||
import org.mifosplatform.portfolio.loanaccount.domain.LoanRepaymentScheduleInstallment;
|
||||
import org.mifosplatform.portfolio.loanaccount.domain.LoanTransaction;
|
||||
import org.mifosplatform.portfolio.loanaccount.domain.LoanTransactionToRepaymentScheduleMapping;
|
||||
import org.mifosplatform.portfolio.loanaccount.domain.transactionprocessor.AbstractLoanRepaymentScheduleTransactionProcessor;
|
||||
import org.mifosplatform.portfolio.loanaccount.domain.transactionprocessor.LoanRepaymentScheduleTransactionProcessor;
|
||||
|
||||
@@ -45,9 +46,10 @@ public class MifosStyleLoanRepaymentScheduleTransactionProcessor extends Abstrac
|
||||
@Override
|
||||
protected Money handleTransactionThatIsPaymentInAdvanceOfInstallment(final LoanRepaymentScheduleInstallment currentInstallment,
|
||||
final List<LoanRepaymentScheduleInstallment> installments, final LoanTransaction loanTransaction,
|
||||
final LocalDate transactionDate, final Money paymentInAdvance) {
|
||||
final LocalDate transactionDate, final Money paymentInAdvance,
|
||||
List<LoanTransactionToRepaymentScheduleMapping> transactionMappings) {
|
||||
|
||||
return handleTransactionThatIsOnTimePaymentOfInstallment(currentInstallment, loanTransaction, paymentInAdvance);
|
||||
return handleTransactionThatIsOnTimePaymentOfInstallment(currentInstallment, loanTransaction, paymentInAdvance, transactionMappings);
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -57,9 +59,10 @@ public class MifosStyleLoanRepaymentScheduleTransactionProcessor extends Abstrac
|
||||
@Override
|
||||
protected Money handleTransactionThatIsALateRepaymentOfInstallment(final LoanRepaymentScheduleInstallment currentInstallment,
|
||||
final List<LoanRepaymentScheduleInstallment> installments, final LoanTransaction loanTransaction,
|
||||
final Money transactionAmountUnprocessed) {
|
||||
final Money transactionAmountUnprocessed, List<LoanTransactionToRepaymentScheduleMapping> transactionMappings) {
|
||||
|
||||
return handleTransactionThatIsOnTimePaymentOfInstallment(currentInstallment, loanTransaction, transactionAmountUnprocessed);
|
||||
return handleTransactionThatIsOnTimePaymentOfInstallment(currentInstallment, loanTransaction, transactionAmountUnprocessed,
|
||||
transactionMappings);
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -67,7 +70,8 @@ public class MifosStyleLoanRepaymentScheduleTransactionProcessor extends Abstrac
|
||||
*/
|
||||
@Override
|
||||
protected Money handleTransactionThatIsOnTimePaymentOfInstallment(final LoanRepaymentScheduleInstallment currentInstallment,
|
||||
final LoanTransaction loanTransaction, final Money transactionAmountUnprocessed) {
|
||||
final LoanTransaction loanTransaction, final Money transactionAmountUnprocessed,
|
||||
List<LoanTransactionToRepaymentScheduleMapping> transactionMappings) {
|
||||
|
||||
final LocalDate transactionDate = loanTransaction.getTransactionDate();
|
||||
final MonetaryCurrency currency = transactionAmountUnprocessed.getCurrency();
|
||||
@@ -115,7 +119,10 @@ public class MifosStyleLoanRepaymentScheduleTransactionProcessor extends Abstrac
|
||||
|
||||
loanTransaction.updateComponents(principalPortion, interestPortion, feeChargesPortion, penaltyChargesPortion);
|
||||
}
|
||||
|
||||
if (principalPortion.plus(interestPortion).plus(feeChargesPortion).plus(penaltyChargesPortion).isGreaterThanZero()) {
|
||||
transactionMappings.add(LoanTransactionToRepaymentScheduleMapping.createFrom(currentInstallment, principalPortion,
|
||||
interestPortion, feeChargesPortion, penaltyChargesPortion));
|
||||
}
|
||||
return transactionAmountRemaining;
|
||||
}
|
||||
|
||||
@@ -123,10 +130,11 @@ public class MifosStyleLoanRepaymentScheduleTransactionProcessor extends Abstrac
|
||||
protected void onLoanOverpayment(final LoanTransaction loanTransaction, final Money loanOverPaymentAmount) {
|
||||
// TODO - KW - dont do anything with loan over-payment for now
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
protected Money handleRefundTransactionPaymentOfInstallment(final LoanRepaymentScheduleInstallment currentInstallment,
|
||||
final LoanTransaction loanTransaction, final Money transactionAmountUnprocessed) {
|
||||
final LoanTransaction loanTransaction, final Money transactionAmountUnprocessed,
|
||||
List<LoanTransactionToRepaymentScheduleMapping> transactionMappings) {
|
||||
|
||||
final LocalDate transactionDate = loanTransaction.getTransactionDate();
|
||||
final MonetaryCurrency currency = transactionAmountUnprocessed.getCurrency();
|
||||
@@ -154,7 +162,10 @@ public class MifosStyleLoanRepaymentScheduleTransactionProcessor extends Abstrac
|
||||
transactionAmountRemaining = transactionAmountRemaining.minus(penaltyChargesPortion);
|
||||
}
|
||||
loanTransaction.updateComponents(principalPortion, interestPortion, feeChargesPortion, penaltyChargesPortion);
|
||||
|
||||
if (principalPortion.plus(interestPortion).plus(feeChargesPortion).plus(penaltyChargesPortion).isGreaterThanZero()) {
|
||||
transactionMappings.add(LoanTransactionToRepaymentScheduleMapping.createFrom(currentInstallment, principalPortion,
|
||||
interestPortion, feeChargesPortion, penaltyChargesPortion));
|
||||
}
|
||||
return transactionAmountRemaining;
|
||||
}
|
||||
}
|
||||
+22
-9
@@ -12,6 +12,7 @@ import org.mifosplatform.organisation.monetary.domain.MonetaryCurrency;
|
||||
import org.mifosplatform.organisation.monetary.domain.Money;
|
||||
import org.mifosplatform.portfolio.loanaccount.domain.LoanRepaymentScheduleInstallment;
|
||||
import org.mifosplatform.portfolio.loanaccount.domain.LoanTransaction;
|
||||
import org.mifosplatform.portfolio.loanaccount.domain.LoanTransactionToRepaymentScheduleMapping;
|
||||
import org.mifosplatform.portfolio.loanaccount.domain.transactionprocessor.AbstractLoanRepaymentScheduleTransactionProcessor;
|
||||
import org.mifosplatform.portfolio.loanaccount.domain.transactionprocessor.LoanRepaymentScheduleTransactionProcessor;
|
||||
|
||||
@@ -30,9 +31,10 @@ public class PrincipalInterestPenaltyFeesOrderLoanRepaymentScheduleTransactionPr
|
||||
@Override
|
||||
protected Money handleTransactionThatIsPaymentInAdvanceOfInstallment(final LoanRepaymentScheduleInstallment currentInstallment,
|
||||
final List<LoanRepaymentScheduleInstallment> installments, final LoanTransaction loanTransaction,
|
||||
final LocalDate transactionDate, final Money paymentInAdvance) {
|
||||
final LocalDate transactionDate, final Money paymentInAdvance,
|
||||
List<LoanTransactionToRepaymentScheduleMapping> transactionMappings) {
|
||||
|
||||
return handleTransactionThatIsOnTimePaymentOfInstallment(currentInstallment, loanTransaction, paymentInAdvance);
|
||||
return handleTransactionThatIsOnTimePaymentOfInstallment(currentInstallment, loanTransaction, paymentInAdvance, transactionMappings);
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -43,9 +45,10 @@ public class PrincipalInterestPenaltyFeesOrderLoanRepaymentScheduleTransactionPr
|
||||
@Override
|
||||
protected Money handleTransactionThatIsALateRepaymentOfInstallment(final LoanRepaymentScheduleInstallment currentInstallment,
|
||||
final List<LoanRepaymentScheduleInstallment> installments, final LoanTransaction loanTransaction,
|
||||
final Money transactionAmountUnprocessed) {
|
||||
final Money transactionAmountUnprocessed, List<LoanTransactionToRepaymentScheduleMapping> transactionMappings) {
|
||||
|
||||
return handleTransactionThatIsOnTimePaymentOfInstallment(currentInstallment, loanTransaction, transactionAmountUnprocessed);
|
||||
return handleTransactionThatIsOnTimePaymentOfInstallment(currentInstallment, loanTransaction, transactionAmountUnprocessed,
|
||||
transactionMappings);
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -53,7 +56,8 @@ public class PrincipalInterestPenaltyFeesOrderLoanRepaymentScheduleTransactionPr
|
||||
*/
|
||||
@Override
|
||||
protected Money handleTransactionThatIsOnTimePaymentOfInstallment(final LoanRepaymentScheduleInstallment currentInstallment,
|
||||
final LoanTransaction loanTransaction, final Money transactionAmountUnprocessed) {
|
||||
final LoanTransaction loanTransaction, final Money transactionAmountUnprocessed,
|
||||
List<LoanTransactionToRepaymentScheduleMapping> transactionMappings) {
|
||||
|
||||
final LocalDate transactionDate = loanTransaction.getTransactionDate();
|
||||
final MonetaryCurrency currency = transactionAmountUnprocessed.getCurrency();
|
||||
@@ -101,16 +105,22 @@ public class PrincipalInterestPenaltyFeesOrderLoanRepaymentScheduleTransactionPr
|
||||
|
||||
loanTransaction.updateComponents(principalPortion, interestPortion, feeChargesPortion, penaltyChargesPortion);
|
||||
}
|
||||
if (principalPortion.plus(interestPortion).plus(feeChargesPortion).plus(penaltyChargesPortion).isGreaterThanZero()) {
|
||||
transactionMappings.add(LoanTransactionToRepaymentScheduleMapping.createFrom(currentInstallment, principalPortion,
|
||||
interestPortion, feeChargesPortion, penaltyChargesPortion));
|
||||
}
|
||||
|
||||
return transactionAmountRemaining;
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
protected Money handleRefundTransactionPaymentOfInstallment(final LoanRepaymentScheduleInstallment currentInstallment,
|
||||
final LoanTransaction loanTransaction, final Money transactionAmountUnprocessed) {
|
||||
final LoanTransaction loanTransaction, final Money transactionAmountUnprocessed,
|
||||
List<LoanTransactionToRepaymentScheduleMapping> transactionMappings) {
|
||||
|
||||
final LocalDate transactionDate = loanTransaction.getTransactionDate();
|
||||
//final MonetaryCurrency currency = transactionAmountUnprocessed.getCurrency();
|
||||
// final MonetaryCurrency currency =
|
||||
// transactionAmountUnprocessed.getCurrency();
|
||||
Money transactionAmountRemaining = transactionAmountUnprocessed;
|
||||
Money principalPortion = Money.zero(transactionAmountRemaining.getCurrency());
|
||||
Money interestPortion = Money.zero(transactionAmountRemaining.getCurrency());
|
||||
@@ -138,7 +148,10 @@ public class PrincipalInterestPenaltyFeesOrderLoanRepaymentScheduleTransactionPr
|
||||
}
|
||||
|
||||
loanTransaction.updateComponents(principalPortion, interestPortion, feeChargesPortion, penaltyChargesPortion);
|
||||
|
||||
if (principalPortion.plus(interestPortion).plus(feeChargesPortion).plus(penaltyChargesPortion).isGreaterThanZero()) {
|
||||
transactionMappings.add(LoanTransactionToRepaymentScheduleMapping.createFrom(currentInstallment, principalPortion,
|
||||
interestPortion, feeChargesPortion, penaltyChargesPortion));
|
||||
}
|
||||
return transactionAmountRemaining;
|
||||
}
|
||||
|
||||
|
||||
+44
-6
@@ -12,6 +12,7 @@ import org.mifosplatform.organisation.monetary.domain.MonetaryCurrency;
|
||||
import org.mifosplatform.organisation.monetary.domain.Money;
|
||||
import org.mifosplatform.portfolio.loanaccount.domain.LoanRepaymentScheduleInstallment;
|
||||
import org.mifosplatform.portfolio.loanaccount.domain.LoanTransaction;
|
||||
import org.mifosplatform.portfolio.loanaccount.domain.LoanTransactionToRepaymentScheduleMapping;
|
||||
import org.mifosplatform.portfolio.loanaccount.domain.transactionprocessor.AbstractLoanRepaymentScheduleTransactionProcessor;
|
||||
import org.mifosplatform.portfolio.loanaccount.domain.transactionprocessor.LoanRepaymentScheduleTransactionProcessor;
|
||||
|
||||
@@ -52,9 +53,10 @@ public class RBILoanRepaymentScheduleTransactionProcessor extends AbstractLoanRe
|
||||
@Override
|
||||
protected Money handleTransactionThatIsPaymentInAdvanceOfInstallment(final LoanRepaymentScheduleInstallment currentInstallment,
|
||||
final List<LoanRepaymentScheduleInstallment> installments, final LoanTransaction loanTransaction,
|
||||
final LocalDate transactionDate, final Money paymentInAdvance) {
|
||||
final LocalDate transactionDate, final Money paymentInAdvance,
|
||||
List<LoanTransactionToRepaymentScheduleMapping> transactionMappings) {
|
||||
|
||||
return handleTransactionThatIsOnTimePaymentOfInstallment(currentInstallment, loanTransaction, paymentInAdvance);
|
||||
return handleTransactionThatIsOnTimePaymentOfInstallment(currentInstallment, loanTransaction, paymentInAdvance, transactionMappings);
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -64,7 +66,7 @@ public class RBILoanRepaymentScheduleTransactionProcessor extends AbstractLoanRe
|
||||
@Override
|
||||
protected Money handleTransactionThatIsALateRepaymentOfInstallment(final LoanRepaymentScheduleInstallment currentInstallment,
|
||||
final List<LoanRepaymentScheduleInstallment> installments, final LoanTransaction loanTransaction,
|
||||
final Money transactionAmountUnprocessed) {
|
||||
final Money transactionAmountUnprocessed, List<LoanTransactionToRepaymentScheduleMapping> transactionMappings) {
|
||||
|
||||
// pay of overdue and current interest due given transaction date
|
||||
final LocalDate transactionDate = loanTransaction.getTransactionDate();
|
||||
@@ -80,6 +82,10 @@ public class RBILoanRepaymentScheduleTransactionProcessor extends AbstractLoanRe
|
||||
|
||||
final Money principalPortion = Money.zero(transactionAmountRemaining.getCurrency());
|
||||
loanTransaction.updateComponents(principalPortion, interestWaivedPortion, feeChargesPortion, penaltyChargesPortion);
|
||||
if (interestWaivedPortion.isGreaterThanZero()) {
|
||||
transactionMappings.add(LoanTransactionToRepaymentScheduleMapping.createFrom(currentInstallment, principalPortion,
|
||||
interestWaivedPortion, feeChargesPortion, penaltyChargesPortion));
|
||||
}
|
||||
} else if (loanTransaction.isChargePayment()) {
|
||||
final Money principalPortion = Money.zero(currency);
|
||||
final Money interestPortion = Money.zero(currency);
|
||||
@@ -91,6 +97,10 @@ public class RBILoanRepaymentScheduleTransactionProcessor extends AbstractLoanRe
|
||||
transactionAmountRemaining = transactionAmountRemaining.minus(feeChargesPortion);
|
||||
}
|
||||
loanTransaction.updateComponents(principalPortion, interestPortion, feeChargesPortion, penaltyChargesPortion);
|
||||
if (principalPortion.plus(interestPortion).plus(feeChargesPortion).plus(penaltyChargesPortion).isGreaterThanZero()) {
|
||||
transactionMappings.add(LoanTransactionToRepaymentScheduleMapping.createFrom(currentInstallment, principalPortion,
|
||||
interestPortion, feeChargesPortion, penaltyChargesPortion));
|
||||
}
|
||||
} else {
|
||||
|
||||
final LoanRepaymentScheduleInstallment currentInstallmentBasedOnTransactionDate = nearestInstallment(
|
||||
@@ -112,6 +122,10 @@ public class RBILoanRepaymentScheduleTransactionProcessor extends AbstractLoanRe
|
||||
|
||||
final Money principalPortion = Money.zero(currency);
|
||||
loanTransaction.updateComponents(principalPortion, interestPortion, feeChargesPortion, penaltyChargesPortion);
|
||||
if (principalPortion.plus(interestPortion).plus(feeChargesPortion).plus(penaltyChargesPortion).isGreaterThanZero()) {
|
||||
transactionMappings.add(LoanTransactionToRepaymentScheduleMapping.createFrom(installment, principalPortion,
|
||||
interestPortion, feeChargesPortion, penaltyChargesPortion));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -124,6 +138,21 @@ public class RBILoanRepaymentScheduleTransactionProcessor extends AbstractLoanRe
|
||||
|
||||
final Money interestPortion = Money.zero(currency);
|
||||
loanTransaction.updateComponents(principalPortion, interestPortion, Money.zero(currency), Money.zero(currency));
|
||||
boolean isMappingUpdated = false;
|
||||
for (LoanTransactionToRepaymentScheduleMapping repaymentScheduleMapping : transactionMappings) {
|
||||
if (repaymentScheduleMapping.getLoanRepaymentScheduleInstallment().getDueDate().equals(installment.getDueDate())) {
|
||||
repaymentScheduleMapping.updateComponents(principalPortion, principalPortion.zero(), principalPortion.zero(),
|
||||
principalPortion.zero());
|
||||
isMappingUpdated = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (!isMappingUpdated
|
||||
&& principalPortion.plus(interestPortion).plus(feeChargesPortion).plus(penaltyChargesPortion)
|
||||
.isGreaterThanZero()) {
|
||||
transactionMappings.add(LoanTransactionToRepaymentScheduleMapping.createFrom(installment, principalPortion,
|
||||
interestPortion, feeChargesPortion, penaltyChargesPortion));
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -150,7 +179,8 @@ public class RBILoanRepaymentScheduleTransactionProcessor extends AbstractLoanRe
|
||||
*/
|
||||
@Override
|
||||
protected Money handleTransactionThatIsOnTimePaymentOfInstallment(final LoanRepaymentScheduleInstallment currentInstallment,
|
||||
final LoanTransaction loanTransaction, final Money transactionAmountUnprocessed) {
|
||||
final LoanTransaction loanTransaction, final Money transactionAmountUnprocessed,
|
||||
final List<LoanTransactionToRepaymentScheduleMapping> transactionMappings) {
|
||||
|
||||
final LocalDate transactionDate = loanTransaction.getTransactionDate();
|
||||
final MonetaryCurrency currency = transactionAmountUnprocessed.getCurrency();
|
||||
@@ -197,6 +227,10 @@ public class RBILoanRepaymentScheduleTransactionProcessor extends AbstractLoanRe
|
||||
}
|
||||
|
||||
loanTransaction.updateComponents(principalPortion, interestPortion, feeChargesPortion, penaltyChargesPortion);
|
||||
if (principalPortion.plus(interestPortion).plus(feeChargesPortion).plus(penaltyChargesPortion).isGreaterThanZero()) {
|
||||
transactionMappings.add(LoanTransactionToRepaymentScheduleMapping.createFrom(currentInstallment, principalPortion,
|
||||
interestPortion, feeChargesPortion, penaltyChargesPortion));
|
||||
}
|
||||
return transactionAmountRemaining;
|
||||
}
|
||||
|
||||
@@ -213,7 +247,8 @@ public class RBILoanRepaymentScheduleTransactionProcessor extends AbstractLoanRe
|
||||
|
||||
@Override
|
||||
protected Money handleRefundTransactionPaymentOfInstallment(final LoanRepaymentScheduleInstallment currentInstallment,
|
||||
final LoanTransaction loanTransaction, final Money transactionAmountUnprocessed) {
|
||||
final LoanTransaction loanTransaction, final Money transactionAmountUnprocessed,
|
||||
final List<LoanTransactionToRepaymentScheduleMapping> transactionMappings) {
|
||||
|
||||
final LocalDate transactionDate = loanTransaction.getTransactionDate();
|
||||
// final MonetaryCurrency currency =
|
||||
@@ -245,7 +280,10 @@ public class RBILoanRepaymentScheduleTransactionProcessor extends AbstractLoanRe
|
||||
}
|
||||
|
||||
loanTransaction.updateComponents(principalPortion, interestPortion, feeChargesPortion, penaltyChargesPortion);
|
||||
|
||||
if (principalPortion.plus(interestPortion).plus(feeChargesPortion).plus(penaltyChargesPortion).isGreaterThanZero()) {
|
||||
transactionMappings.add(LoanTransactionToRepaymentScheduleMapping.createFrom(currentInstallment, principalPortion,
|
||||
interestPortion, feeChargesPortion, penaltyChargesPortion));
|
||||
}
|
||||
return transactionAmountRemaining;
|
||||
}
|
||||
}
|
||||
+52
-46
@@ -54,23 +54,23 @@ public abstract class AbstractLoanScheduleGenerator implements LoanScheduleGener
|
||||
final LoanRepaymentScheduleTransactionProcessor loanRepaymentScheduleTransactionProcessor, final LocalDate scheduleTillDate) {
|
||||
|
||||
final ApplicationCurrency applicationCurrency = loanApplicationTerms.getApplicationCurrency();
|
||||
// 1. generate list of proposed schedule due dates
|
||||
// generate list of proposed schedule due dates
|
||||
final LocalDate loanEndDate = this.scheduledDateGenerator.getLastRepaymentDate(loanApplicationTerms, holidayDetailDTO);
|
||||
loanApplicationTerms.updateLoanEndDate(loanEndDate);
|
||||
|
||||
// 2. determine the total charges due at time of disbursement
|
||||
// determine the total charges due at time of disbursement
|
||||
final BigDecimal chargesDueAtTimeOfDisbursement = deriveTotalChargesDueAtTimeOfDisbursement(loanCharges);
|
||||
|
||||
// 3. setup variables for tracking important facts required for loan
|
||||
// setup variables for tracking important facts required for loan
|
||||
// schedule generation.
|
||||
Money principalDisbursed ;
|
||||
|
||||
if(loanApplicationTerms.isMultiDisburseLoan() && loanApplicationTerms.getApprovedPrincipal().isGreaterThanZero()) {
|
||||
principalDisbursed = loanApplicationTerms.getApprovedPrincipal();
|
||||
}else {
|
||||
principalDisbursed = loanApplicationTerms.getPrincipal();
|
||||
Money principalToBeScheduled;
|
||||
|
||||
if (loanApplicationTerms.isMultiDisburseLoan() && loanApplicationTerms.getApprovedPrincipal().isGreaterThanZero()) {
|
||||
principalToBeScheduled = loanApplicationTerms.getApprovedPrincipal();
|
||||
} else {
|
||||
principalToBeScheduled = loanApplicationTerms.getPrincipal();
|
||||
}
|
||||
final MonetaryCurrency currency = principalDisbursed.getCurrency();
|
||||
final MonetaryCurrency currency = principalToBeScheduled.getCurrency();
|
||||
final int numberOfRepayments = loanApplicationTerms.getNumberOfRepayments();
|
||||
|
||||
// variables for cumulative totals
|
||||
@@ -80,14 +80,14 @@ public abstract class AbstractLoanScheduleGenerator implements LoanScheduleGener
|
||||
BigDecimal totalPenaltyChargesCharged = BigDecimal.ZERO;
|
||||
BigDecimal totalRepaymentExpected = chargesDueAtTimeOfDisbursement;
|
||||
final BigDecimal totalOutstanding = BigDecimal.ZERO;
|
||||
Money totalCumulativePrincipal = principalDisbursed.zero();
|
||||
Money totalCumulativeInterest = principalDisbursed.zero();
|
||||
Money totalOutstandingInterestPaymentDueToGrace = principalDisbursed.zero();
|
||||
Money totalCumulativePrincipal = principalToBeScheduled.zero();
|
||||
Money totalCumulativeInterest = principalToBeScheduled.zero();
|
||||
Money totalOutstandingInterestPaymentDueToGrace = principalToBeScheduled.zero();
|
||||
|
||||
final Collection<LoanScheduleModelPeriod> periods = createNewLoanScheduleListWithDisbursementDetails(numberOfRepayments,
|
||||
loanApplicationTerms, chargesDueAtTimeOfDisbursement);
|
||||
|
||||
// 4. Determine the total interest owed over the full loan for FLAT
|
||||
// Determine the total interest owed over the full loan for FLAT
|
||||
// interest method .
|
||||
Money totalInterestChargedForFullLoanTerm = loanApplicationTerms.calculateTotalInterestCharged(
|
||||
this.paymentPeriodsInOneYearCalculator, mc);
|
||||
@@ -104,10 +104,10 @@ public abstract class AbstractLoanScheduleGenerator implements LoanScheduleGener
|
||||
|
||||
// Actual period Number as per the schedule
|
||||
int periodNumber = 1;
|
||||
// Actual period Number and interest only repayments
|
||||
// Actual period Number plus interest only repayments
|
||||
int instalmentNumber = 1;
|
||||
|
||||
Money outstandingBalance = principalDisbursed;
|
||||
Money outstandingBalance = principalToBeScheduled;
|
||||
|
||||
// Set fixed EMI Amount
|
||||
updateFixedInstallmentAmount(mc, loanApplicationTerms, actualRepaymentDate, periodNumber, outstandingBalance, holidayDetailDTO);
|
||||
@@ -120,7 +120,7 @@ public abstract class AbstractLoanScheduleGenerator implements LoanScheduleGener
|
||||
// details to map
|
||||
BigDecimal disburseAmt = getDisbursementAmount(loanApplicationTerms, periodStartDate, periods, chargesDueAtTimeOfDisbursement,
|
||||
disburseDetailMap, isInterestRecalculationRequired(loanApplicationTerms, transactions));
|
||||
principalDisbursed = principalDisbursed.zero().plus(disburseAmt);
|
||||
principalToBeScheduled = principalToBeScheduled.zero().plus(disburseAmt);
|
||||
loanApplicationTerms.setPrincipal(loanApplicationTerms.getPrincipal().zero().plus(disburseAmt));
|
||||
outstandingBalance = outstandingBalance.zero().plus(disburseAmt);
|
||||
}
|
||||
@@ -228,16 +228,17 @@ public abstract class AbstractLoanScheduleGenerator implements LoanScheduleGener
|
||||
// updates actual outstanding balance with new
|
||||
// disbursement detail
|
||||
outstandingBalance = outstandingBalance.plus(disburseDetail.getValue());
|
||||
principalDisbursed = principalDisbursed.plus(disburseDetail.getValue());
|
||||
principalToBeScheduled = principalToBeScheduled.plus(disburseDetail.getValue());
|
||||
loanApplicationTerms.setPrincipal(loanApplicationTerms.getPrincipal().plus(disburseDetail.getValue()));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Adds new interest repayment to the schedule as per the repayment
|
||||
// process repayments to the schedule as per the repayment
|
||||
// transaction processor configuration
|
||||
// will be added only if there is a loan repayment between the
|
||||
// period for interest first repayment strategies
|
||||
// will add a new schedule with interest till the transaction date
|
||||
// for a loan repayment which falls between the
|
||||
// two periods for interest first repayment strategies
|
||||
Money earlyPaidAmount = Money.zero(currency);
|
||||
LoanScheduleModelPeriod lastInstallment = null;
|
||||
if (isInterestRecalculationRequired(loanApplicationTerms, transactions)) {
|
||||
@@ -282,7 +283,7 @@ public abstract class AbstractLoanScheduleGenerator implements LoanScheduleGener
|
||||
totalOutstandingInterestPaymentDueToGrace = principalInterestForThisPeriod.interestPaymentDueToGrace();
|
||||
}
|
||||
|
||||
Money principalForThisPeriod = principalDisbursed.zero();
|
||||
Money principalForThisPeriod = principalToBeScheduled.zero();
|
||||
|
||||
// applies all the applicable charges to the
|
||||
// newly
|
||||
@@ -290,17 +291,17 @@ public abstract class AbstractLoanScheduleGenerator implements LoanScheduleGener
|
||||
PrincipalInterest principalInterest = new PrincipalInterest(principalForThisPeriod,
|
||||
interestForThisinstallment, null);
|
||||
Money feeChargesForInstallment = cumulativeFeeChargesDueWithin(periodStartDate,
|
||||
detail.getTransactionDate(), loanCharges, currency, principalInterest, principalDisbursed,
|
||||
detail.getTransactionDate(), loanCharges, currency, principalInterest, principalToBeScheduled,
|
||||
totalCumulativeInterest, numberOfRepayments, true);
|
||||
Money penaltyChargesForInstallment = cumulativePenaltyChargesDueWithin(periodStartDate,
|
||||
detail.getTransactionDate(), loanCharges, currency, principalInterest, principalDisbursed,
|
||||
detail.getTransactionDate(), loanCharges, currency, principalInterest, principalToBeScheduled,
|
||||
totalCumulativeInterest, numberOfRepayments, true);
|
||||
|
||||
// 8. sum up real totalInstallmentDue from
|
||||
// sum up real totalInstallmentDue from
|
||||
// components
|
||||
final Money totalInstallmentDue = principalForThisPeriod.plus(interestForThisinstallment)
|
||||
.plus(feeChargesForInstallment).plus(penaltyChargesForInstallment);
|
||||
// 9. create repayment period from parts
|
||||
// create repayment period from parts
|
||||
installment = LoanScheduleModelRepaymentPeriod.repayment(instalmentNumber, periodStartDate,
|
||||
detail.getTransactionDate(), principalForThisPeriod, outstandingBalance,
|
||||
interestForThisinstallment, feeChargesForInstallment, penaltyChargesForInstallment,
|
||||
@@ -488,7 +489,7 @@ public abstract class AbstractLoanScheduleGenerator implements LoanScheduleGener
|
||||
mergeVariationsToMap(principalPortionMap, latePaymentMap, disburseDetailMap, compoundingMap), compoundingMap,
|
||||
periodStartDateApplicableForInterest, scheduledDueDate, daysInPeriodApplicableForInterest);
|
||||
|
||||
if (loanApplicationTerms.getFixedEmiAmount() != null
|
||||
if (loanApplicationTerms.getFixedEmiAmount() != null
|
||||
&& loanApplicationTerms.getFixedEmiAmount().compareTo(principalInterestForThisPeriod.interest().getAmount()) != 1) {
|
||||
String errorMsg = "EMI amount must be greater than : " + principalInterestForThisPeriod.interest().getAmount();
|
||||
throw new MultiDisbursementEmiAmountException(errorMsg, principalInterestForThisPeriod.interest().getAmount(),
|
||||
@@ -520,13 +521,14 @@ public abstract class AbstractLoanScheduleGenerator implements LoanScheduleGener
|
||||
BigDecimal fixedEmiAmount = loanApplicationTerms.getFixedEmiAmount();
|
||||
reducePrincipal = applyEarlyPaymentStrategy(loanApplicationTerms, reducePrincipal, totalCumulativePrincipal,
|
||||
periodNumber + 1, mc, holidayDetailDTO);
|
||||
if (loanApplicationTerms.getAmortizationMethod().isEqualInstallment() && fixedEmiAmount.compareTo(loanApplicationTerms.getFixedEmiAmount()) != 0) {
|
||||
if (loanApplicationTerms.getAmortizationMethod().isEqualInstallment()
|
||||
&& fixedEmiAmount.compareTo(loanApplicationTerms.getFixedEmiAmount()) != 0) {
|
||||
isEmiAmountChanged = true;
|
||||
}
|
||||
principalForThisPeriod = principalForThisPeriod.plus(earlyPaidAmount);
|
||||
}
|
||||
|
||||
// 6. update outstandingLoanBlance using current period
|
||||
// update outstandingLoanBlance using current period
|
||||
// 'principalDue'
|
||||
outstandingBalance = outstandingBalance.minus(principalForThisPeriod.minus(reducedBalance));
|
||||
|
||||
@@ -534,21 +536,21 @@ public abstract class AbstractLoanScheduleGenerator implements LoanScheduleGener
|
||||
principalForThisPeriod = principalForThisPeriod.plus(outstandingBalance);
|
||||
outstandingBalance = outstandingBalance.zero();
|
||||
}
|
||||
|
||||
if(!isNextRepaymentAvailable){
|
||||
disburseDetailMap.clear();
|
||||
|
||||
if (!isNextRepaymentAvailable) {
|
||||
disburseDetailMap.clear();
|
||||
}
|
||||
|
||||
// applies charges for the period
|
||||
PrincipalInterest principalInterest = new PrincipalInterest(principalForThisPeriod, interestForThisinstallment, null);
|
||||
Money feeChargesForInstallment = cumulativeFeeChargesDueWithin(periodStartDate, scheduledDueDate, loanCharges, currency,
|
||||
principalInterest, principalDisbursed, totalCumulativeInterest, numberOfRepayments, true);
|
||||
principalInterest, principalToBeScheduled, totalCumulativeInterest, numberOfRepayments, true);
|
||||
Money penaltyChargesForInstallment = cumulativePenaltyChargesDueWithin(periodStartDate, scheduledDueDate, loanCharges,
|
||||
currency, principalInterest, principalDisbursed, totalCumulativeInterest, numberOfRepayments, true);
|
||||
currency, principalInterest, principalToBeScheduled, totalCumulativeInterest, numberOfRepayments, true);
|
||||
totalFeeChargesCharged = totalFeeChargesCharged.add(feeChargesForInstallment.getAmount());
|
||||
totalPenaltyChargesCharged = totalPenaltyChargesCharged.add(penaltyChargesForInstallment.getAmount());
|
||||
|
||||
// 8. sum up real totalInstallmentDue from components
|
||||
// sum up real totalInstallmentDue from components
|
||||
final Money totalInstallmentDue = principalForThisPeriod.plus(interestForThisinstallment).plus(feeChargesForInstallment)
|
||||
.plus(penaltyChargesForInstallment);
|
||||
|
||||
@@ -559,7 +561,7 @@ public abstract class AbstractLoanScheduleGenerator implements LoanScheduleGener
|
||||
continue;
|
||||
}
|
||||
|
||||
// 9. create repayment period from parts
|
||||
// create repayment period from parts
|
||||
LoanScheduleModelPeriod installment = LoanScheduleModelRepaymentPeriod.repayment(instalmentNumber, periodStartDate,
|
||||
scheduledDueDate, principalForThisPeriod, outstandingBalance, interestForThisinstallment, feeChargesForInstallment,
|
||||
penaltyChargesForInstallment, totalInstallmentDue, false);
|
||||
@@ -614,7 +616,7 @@ public abstract class AbstractLoanScheduleGenerator implements LoanScheduleGener
|
||||
final Money totalDue = principalForThisPeriod//
|
||||
.plus(interestForThisinstallment);
|
||||
|
||||
// 9. create and replaces repayment period
|
||||
// create and replaces repayment period
|
||||
// from parts
|
||||
installment = LoanScheduleModelRepaymentPeriod.repayment(instalmentNumber, periodStartDate,
|
||||
detail.getTransactionDate(), principalForThisPeriod, outstandingBalance,
|
||||
@@ -643,7 +645,8 @@ public abstract class AbstractLoanScheduleGenerator implements LoanScheduleGener
|
||||
reducePrincipal = applyEarlyPaymentStrategy(loanApplicationTerms, reducePrincipal,
|
||||
totalCumulativePrincipal.plus(principalForThisPeriod.minus(principalProcessed)), periodNumber + 1, mc,
|
||||
holidayDetailDTO);
|
||||
if (loanApplicationTerms.getAmortizationMethod().isEqualInstallment() && fixedEmiAmount.compareTo(loanApplicationTerms.getFixedEmiAmount()) != 0) {
|
||||
if (loanApplicationTerms.getAmortizationMethod().isEqualInstallment()
|
||||
&& fixedEmiAmount.compareTo(loanApplicationTerms.getFixedEmiAmount()) != 0) {
|
||||
isEmiAmountChanged = true;
|
||||
}
|
||||
|
||||
@@ -694,18 +697,20 @@ public abstract class AbstractLoanScheduleGenerator implements LoanScheduleGener
|
||||
totalOutstandingInterestPaymentDueToGrace = totalOutstandingInterestPaymentDueToGrace.zero();
|
||||
}
|
||||
|
||||
// 7. determine fees and penalties for charges which depends on total
|
||||
// determine fees and penalties for charges which depends on total
|
||||
// loan interest
|
||||
for (LoanScheduleModelPeriod loanScheduleModelPeriod : periods) {
|
||||
if (loanScheduleModelPeriod.isRepaymentPeriod()) {
|
||||
PrincipalInterest principalInterest = new PrincipalInterest(Money.of(currency, loanScheduleModelPeriod.principalDue()),
|
||||
Money.of(currency, loanScheduleModelPeriod.interestDue()), null);
|
||||
Money feeChargesForInstallment = cumulativeFeeChargesDueWithin(loanScheduleModelPeriod.periodFromDate(),
|
||||
loanScheduleModelPeriod.periodDueDate(), nonCompoundingCharges, currency, principalInterest, principalDisbursed,
|
||||
totalCumulativeInterest, numberOfRepayments, !loanScheduleModelPeriod.isRecalculatedInterestComponent());
|
||||
loanScheduleModelPeriod.periodDueDate(), nonCompoundingCharges, currency, principalInterest,
|
||||
principalToBeScheduled, totalCumulativeInterest, numberOfRepayments,
|
||||
!loanScheduleModelPeriod.isRecalculatedInterestComponent());
|
||||
Money penaltyChargesForInstallment = cumulativePenaltyChargesDueWithin(loanScheduleModelPeriod.periodFromDate(),
|
||||
loanScheduleModelPeriod.periodDueDate(), nonCompoundingCharges, currency, principalInterest, principalDisbursed,
|
||||
totalCumulativeInterest, numberOfRepayments, !loanScheduleModelPeriod.isRecalculatedInterestComponent());
|
||||
loanScheduleModelPeriod.periodDueDate(), nonCompoundingCharges, currency, principalInterest,
|
||||
principalToBeScheduled, totalCumulativeInterest, numberOfRepayments,
|
||||
!loanScheduleModelPeriod.isRecalculatedInterestComponent());
|
||||
totalFeeChargesCharged = totalFeeChargesCharged.add(feeChargesForInstallment.getAmount());
|
||||
totalPenaltyChargesCharged = totalPenaltyChargesCharged.add(penaltyChargesForInstallment.getAmount());
|
||||
totalRepaymentExpected = totalRepaymentExpected.add(feeChargesForInstallment.getAmount()).add(
|
||||
@@ -730,7 +735,7 @@ public abstract class AbstractLoanScheduleGenerator implements LoanScheduleGener
|
||||
|
||||
loanApplicationTerms.resetFixedEmiAmount();
|
||||
|
||||
return LoanScheduleModel.from(periods, applicationCurrency, loanTermInDays, principalDisbursed,
|
||||
return LoanScheduleModel.from(periods, applicationCurrency, loanTermInDays, principalToBeScheduled,
|
||||
totalCumulativePrincipal.getAmount(), totalPrincipalPaid, totalCumulativeInterest.getAmount(), totalFeeChargesCharged,
|
||||
totalPenaltyChargesCharged, totalRepaymentExpected, totalOutstanding);
|
||||
}
|
||||
@@ -943,8 +948,9 @@ public abstract class AbstractLoanScheduleGenerator implements LoanScheduleGener
|
||||
updateFixedInstallmentAmount(mc, loanApplicationTerms, loanApplicationTerms.getExpectedDisbursementDate(),
|
||||
periodNumber, loanApplicationTerms.getPrincipal().minus(totalCumulativePrincipal), holidayDetailDTO);
|
||||
}
|
||||
if(loanApplicationTerms.getAmortizationMethod().isEqualPrincipal()){
|
||||
loanApplicationTerms.updateFixedPrincipalAmount(mc, periodNumber, loanApplicationTerms.getPrincipal().minus(totalCumulativePrincipal));
|
||||
if (loanApplicationTerms.getAmortizationMethod().isEqualPrincipal()) {
|
||||
loanApplicationTerms.updateFixedPrincipalAmount(mc, periodNumber,
|
||||
loanApplicationTerms.getPrincipal().minus(totalCumulativePrincipal));
|
||||
}
|
||||
reducePrincipal = reducePrincipal.zero();
|
||||
break;
|
||||
|
||||
-1
@@ -6,7 +6,6 @@
|
||||
package org.mifosplatform.portfolio.loanaccount.service;
|
||||
|
||||
import java.math.BigDecimal;
|
||||
import java.math.RoundingMode;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Collection;
|
||||
import java.util.HashMap;
|
||||
|
||||
+15
@@ -0,0 +1,15 @@
|
||||
CREATE TABLE `m_loan_transaction_repayment_schedule_mapping` (
|
||||
`id` BIGINT(20) NOT NULL AUTO_INCREMENT,
|
||||
`loan_transaction_id` BIGINT(20) NOT NULL,
|
||||
`loan_repayment_schedule_id` BIGINT(20) NOT NULL,
|
||||
`amount` DECIMAL(19,6) NOT NULL,
|
||||
`principal_portion_derived` DECIMAL(19,6) NULL DEFAULT NULL,
|
||||
`interest_portion_derived` DECIMAL(19,6) NULL DEFAULT NULL,
|
||||
`fee_charges_portion_derived` DECIMAL(19,6) NULL DEFAULT NULL,
|
||||
`penalty_charges_portion_derived` DECIMAL(19,6) NULL DEFAULT NULL,
|
||||
PRIMARY KEY (`id`),
|
||||
INDEX `FK_mappings_m_loan_transaction` (`loan_transaction_id`),
|
||||
INDEX `FK_mappings_m_loan_repayment_schedule` (`loan_repayment_schedule_id`),
|
||||
CONSTRAINT `FK_mappings_m_loan_repayment_schedule` FOREIGN KEY (`loan_repayment_schedule_id`) REFERENCES `m_loan_repayment_schedule` (`id`),
|
||||
CONSTRAINT `FK_mappings_m_loan_transaction` FOREIGN KEY (`loan_transaction_id`) REFERENCES `m_loan_transaction` (`id`)
|
||||
);
|
||||
Reference in New Issue
Block a user