FINERACT-1724: Refactor loan repayment transaction processor
This commit is contained in:
+32
-29
@@ -702,7 +702,7 @@ public class Loan extends AbstractAuditableWithUTCDateTimeCustom {
|
|||||||
final LoanRepaymentScheduleTransactionProcessor loanRepaymentScheduleTransactionProcessor = this.transactionProcessorFactory
|
final LoanRepaymentScheduleTransactionProcessor loanRepaymentScheduleTransactionProcessor = this.transactionProcessorFactory
|
||||||
.determineProcessor(this.transactionProcessingStrategyCode);
|
.determineProcessor(this.transactionProcessingStrategyCode);
|
||||||
final List<LoanTransaction> allNonContraTransactionsPostDisbursement = retrieveListOfTransactionsPostDisbursement();
|
final List<LoanTransaction> allNonContraTransactionsPostDisbursement = retrieveListOfTransactionsPostDisbursement();
|
||||||
changedTransactionDetail = loanRepaymentScheduleTransactionProcessor.handleTransaction(getDisbursementDate(),
|
changedTransactionDetail = loanRepaymentScheduleTransactionProcessor.reprocessLoanTranactions(getDisbursementDate(),
|
||||||
allNonContraTransactionsPostDisbursement, getCurrency(), getRepaymentScheduleInstallments(), getActiveCharges());
|
allNonContraTransactionsPostDisbursement, getCurrency(), getRepaymentScheduleInstallments(), getActiveCharges());
|
||||||
for (final Map.Entry<Long, LoanTransaction> mapEntry : changedTransactionDetail.getNewTransactionMappings().entrySet()) {
|
for (final Map.Entry<Long, LoanTransaction> mapEntry : changedTransactionDetail.getNewTransactionMappings().entrySet()) {
|
||||||
|
|
||||||
@@ -789,7 +789,8 @@ public class Loan extends AbstractAuditableWithUTCDateTimeCustom {
|
|||||||
}
|
}
|
||||||
final Set<LoanCharge> loanCharges = new HashSet<>(1);
|
final Set<LoanCharge> loanCharges = new HashSet<>(1);
|
||||||
loanCharges.add(charge);
|
loanCharges.add(charge);
|
||||||
loanRepaymentScheduleTransactionProcessor.handleTransaction(chargesPayment, getCurrency(), chargePaymentInstallments, loanCharges);
|
loanRepaymentScheduleTransactionProcessor.processLatestTransaction(chargesPayment, getCurrency(), chargePaymentInstallments,
|
||||||
|
loanCharges, getTotalOverpaidAsMoney());
|
||||||
|
|
||||||
updateLoanSummaryDerivedFields();
|
updateLoanSummaryDerivedFields();
|
||||||
doPostLoanTransactionChecks(chargesPayment.getTransactionDate(), loanLifecycleStateMachine);
|
doPostLoanTransactionChecks(chargesPayment.getTransactionDate(), loanLifecycleStateMachine);
|
||||||
@@ -862,8 +863,8 @@ public class Loan extends AbstractAuditableWithUTCDateTimeCustom {
|
|||||||
* affected Transactions
|
* affected Transactions
|
||||||
***/
|
***/
|
||||||
final List<LoanTransaction> allNonContraTransactionsPostDisbursement = retrieveListOfTransactionsPostDisbursement();
|
final List<LoanTransaction> allNonContraTransactionsPostDisbursement = retrieveListOfTransactionsPostDisbursement();
|
||||||
loanRepaymentScheduleTransactionProcessor.handleTransaction(getDisbursementDate(), allNonContraTransactionsPostDisbursement,
|
loanRepaymentScheduleTransactionProcessor.reprocessLoanTranactions(getDisbursementDate(),
|
||||||
getCurrency(), getRepaymentScheduleInstallments(), getActiveCharges());
|
allNonContraTransactionsPostDisbursement, getCurrency(), getRepaymentScheduleInstallments(), getActiveCharges());
|
||||||
}
|
}
|
||||||
this.charges.remove(loanCharge);
|
this.charges.remove(loanCharge);
|
||||||
updateLoanSummaryDerivedFields();
|
updateLoanSummaryDerivedFields();
|
||||||
@@ -930,8 +931,8 @@ public class Loan extends AbstractAuditableWithUTCDateTimeCustom {
|
|||||||
* affected Transactions
|
* affected Transactions
|
||||||
***/
|
***/
|
||||||
final List<LoanTransaction> allNonContraTransactionsPostDisbursement = retrieveListOfTransactionsPostDisbursement();
|
final List<LoanTransaction> allNonContraTransactionsPostDisbursement = retrieveListOfTransactionsPostDisbursement();
|
||||||
loanRepaymentScheduleTransactionProcessor.handleTransaction(getDisbursementDate(), allNonContraTransactionsPostDisbursement,
|
loanRepaymentScheduleTransactionProcessor.reprocessLoanTranactions(getDisbursementDate(),
|
||||||
getCurrency(), getRepaymentScheduleInstallments(), getActiveCharges());
|
allNonContraTransactionsPostDisbursement, getCurrency(), getRepaymentScheduleInstallments(), getActiveCharges());
|
||||||
} else {
|
} else {
|
||||||
// reprocess loan schedule based on charge been waived.
|
// reprocess loan schedule based on charge been waived.
|
||||||
final LoanRepaymentScheduleProcessingWrapper wrapper = new LoanRepaymentScheduleProcessingWrapper();
|
final LoanRepaymentScheduleProcessingWrapper wrapper = new LoanRepaymentScheduleProcessingWrapper();
|
||||||
@@ -1123,8 +1124,8 @@ public class Loan extends AbstractAuditableWithUTCDateTimeCustom {
|
|||||||
* affected Transactions
|
* affected Transactions
|
||||||
***/
|
***/
|
||||||
final List<LoanTransaction> allNonContraTransactionsPostDisbursement = retrieveListOfTransactionsPostDisbursement();
|
final List<LoanTransaction> allNonContraTransactionsPostDisbursement = retrieveListOfTransactionsPostDisbursement();
|
||||||
loanRepaymentScheduleTransactionProcessor.handleTransaction(getDisbursementDate(), allNonContraTransactionsPostDisbursement,
|
loanRepaymentScheduleTransactionProcessor.reprocessLoanTranactions(getDisbursementDate(),
|
||||||
getCurrency(), getRepaymentScheduleInstallments(), getActiveCharges());
|
allNonContraTransactionsPostDisbursement, getCurrency(), getRepaymentScheduleInstallments(), getActiveCharges());
|
||||||
} else {
|
} else {
|
||||||
// reprocess loan schedule based on charge been waived.
|
// reprocess loan schedule based on charge been waived.
|
||||||
final LoanRepaymentScheduleProcessingWrapper wrapper = new LoanRepaymentScheduleProcessingWrapper();
|
final LoanRepaymentScheduleProcessingWrapper wrapper = new LoanRepaymentScheduleProcessingWrapper();
|
||||||
@@ -2705,7 +2706,7 @@ public class Loan extends AbstractAuditableWithUTCDateTimeCustom {
|
|||||||
if (!allNonContraTransactionsPostDisbursement.isEmpty()) {
|
if (!allNonContraTransactionsPostDisbursement.isEmpty()) {
|
||||||
final LoanRepaymentScheduleTransactionProcessor loanRepaymentScheduleTransactionProcessor = this.transactionProcessorFactory
|
final LoanRepaymentScheduleTransactionProcessor loanRepaymentScheduleTransactionProcessor = this.transactionProcessorFactory
|
||||||
.determineProcessor(this.transactionProcessingStrategyCode);
|
.determineProcessor(this.transactionProcessingStrategyCode);
|
||||||
changedTransactionDetail = loanRepaymentScheduleTransactionProcessor.handleTransaction(getDisbursementDate(),
|
changedTransactionDetail = loanRepaymentScheduleTransactionProcessor.reprocessLoanTranactions(getDisbursementDate(),
|
||||||
allNonContraTransactionsPostDisbursement, getCurrency(), getRepaymentScheduleInstallments(), getActiveCharges());
|
allNonContraTransactionsPostDisbursement, getCurrency(), getRepaymentScheduleInstallments(), getActiveCharges());
|
||||||
for (final Map.Entry<Long, LoanTransaction> mapEntry : changedTransactionDetail.getNewTransactionMappings().entrySet()) {
|
for (final Map.Entry<Long, LoanTransaction> mapEntry : changedTransactionDetail.getNewTransactionMappings().entrySet()) {
|
||||||
mapEntry.getValue().updateLoan(this);
|
mapEntry.getValue().updateLoan(this);
|
||||||
@@ -3330,8 +3331,8 @@ public class Loan extends AbstractAuditableWithUTCDateTimeCustom {
|
|||||||
|
|
||||||
if (isTransactionChronologicallyLatest && adjustedTransaction == null
|
if (isTransactionChronologicallyLatest && adjustedTransaction == null
|
||||||
&& (!reprocess || !this.repaymentScheduleDetail().isInterestRecalculationEnabled()) && !isForeclosure()) {
|
&& (!reprocess || !this.repaymentScheduleDetail().isInterestRecalculationEnabled()) && !isForeclosure()) {
|
||||||
loanRepaymentScheduleTransactionProcessor.handleTransaction(loanTransaction, getCurrency(), getRepaymentScheduleInstallments(),
|
loanRepaymentScheduleTransactionProcessor.processLatestTransaction(loanTransaction, getCurrency(),
|
||||||
getActiveCharges());
|
getRepaymentScheduleInstallments(), getActiveCharges(), getTotalOverpaidAsMoney());
|
||||||
reprocess = false;
|
reprocess = false;
|
||||||
if (this.repaymentScheduleDetail().isInterestRecalculationEnabled()) {
|
if (this.repaymentScheduleDetail().isInterestRecalculationEnabled()) {
|
||||||
if (currentInstallment == null || currentInstallment.isNotFullyPaidOff()) {
|
if (currentInstallment == null || currentInstallment.isNotFullyPaidOff()) {
|
||||||
@@ -3350,7 +3351,7 @@ public class Loan extends AbstractAuditableWithUTCDateTimeCustom {
|
|||||||
regenerateRepaymentScheduleWithInterestRecalculation(scheduleGeneratorDTO);
|
regenerateRepaymentScheduleWithInterestRecalculation(scheduleGeneratorDTO);
|
||||||
}
|
}
|
||||||
final List<LoanTransaction> allNonContraTransactionsPostDisbursement = retrieveListOfTransactionsPostDisbursement();
|
final List<LoanTransaction> allNonContraTransactionsPostDisbursement = retrieveListOfTransactionsPostDisbursement();
|
||||||
changedTransactionDetail = loanRepaymentScheduleTransactionProcessor.handleTransaction(getDisbursementDate(),
|
changedTransactionDetail = loanRepaymentScheduleTransactionProcessor.reprocessLoanTranactions(getDisbursementDate(),
|
||||||
allNonContraTransactionsPostDisbursement, getCurrency(), getRepaymentScheduleInstallments(), getActiveCharges());
|
allNonContraTransactionsPostDisbursement, getCurrency(), getRepaymentScheduleInstallments(), getActiveCharges());
|
||||||
for (final Map.Entry<Long, LoanTransaction> mapEntry : changedTransactionDetail.getNewTransactionMappings().entrySet()) {
|
for (final Map.Entry<Long, LoanTransaction> mapEntry : changedTransactionDetail.getNewTransactionMappings().entrySet()) {
|
||||||
mapEntry.getValue().updateLoan(this);
|
mapEntry.getValue().updateLoan(this);
|
||||||
@@ -3778,7 +3779,7 @@ public class Loan extends AbstractAuditableWithUTCDateTimeCustom {
|
|||||||
if (this.repaymentScheduleDetail().isInterestRecalculationEnabled()) {
|
if (this.repaymentScheduleDetail().isInterestRecalculationEnabled()) {
|
||||||
regenerateRepaymentScheduleWithInterestRecalculation(scheduleGeneratorDTO);
|
regenerateRepaymentScheduleWithInterestRecalculation(scheduleGeneratorDTO);
|
||||||
}
|
}
|
||||||
ChangedTransactionDetail changedTransactionDetail = loanRepaymentScheduleTransactionProcessor.handleTransaction(
|
ChangedTransactionDetail changedTransactionDetail = loanRepaymentScheduleTransactionProcessor.reprocessLoanTranactions(
|
||||||
getDisbursementDate(), allNonContraTransactionsPostDisbursement, getCurrency(), getRepaymentScheduleInstallments(),
|
getDisbursementDate(), allNonContraTransactionsPostDisbursement, getCurrency(), getRepaymentScheduleInstallments(),
|
||||||
getActiveCharges());
|
getActiveCharges());
|
||||||
updateLoanSummaryDerivedFields();
|
updateLoanSummaryDerivedFields();
|
||||||
@@ -3904,7 +3905,8 @@ public class Loan extends AbstractAuditableWithUTCDateTimeCustom {
|
|||||||
}
|
}
|
||||||
|
|
||||||
addLoanTransaction(loanTransaction);
|
addLoanTransaction(loanTransaction);
|
||||||
loanRepaymentScheduleTransactionProcessor.handleWriteOff(loanTransaction, loanCurrency(), getRepaymentScheduleInstallments());
|
loanRepaymentScheduleTransactionProcessor.processLatestTransaction(loanTransaction, loanCurrency(),
|
||||||
|
getRepaymentScheduleInstallments(), getActiveCharges(), getTotalOverpaidAsMoney());
|
||||||
|
|
||||||
updateLoanSummaryDerivedFields();
|
updateLoanSummaryDerivedFields();
|
||||||
}
|
}
|
||||||
@@ -3926,7 +3928,7 @@ public class Loan extends AbstractAuditableWithUTCDateTimeCustom {
|
|||||||
regenerateRepaymentScheduleWithInterestRecalculation(scheduleGeneratorDTO);
|
regenerateRepaymentScheduleWithInterestRecalculation(scheduleGeneratorDTO);
|
||||||
}
|
}
|
||||||
final List<LoanTransaction> allNonContraTransactionsPostDisbursement = retrieveListOfTransactionsPostDisbursement();
|
final List<LoanTransaction> allNonContraTransactionsPostDisbursement = retrieveListOfTransactionsPostDisbursement();
|
||||||
changedTransactionDetail = loanRepaymentScheduleTransactionProcessor.handleTransaction(getDisbursementDate(),
|
changedTransactionDetail = loanRepaymentScheduleTransactionProcessor.reprocessLoanTranactions(getDisbursementDate(),
|
||||||
allNonContraTransactionsPostDisbursement, getCurrency(), getRepaymentScheduleInstallments(), getActiveCharges());
|
allNonContraTransactionsPostDisbursement, getCurrency(), getRepaymentScheduleInstallments(), getActiveCharges());
|
||||||
for (final Map.Entry<Long, LoanTransaction> mapEntry : changedTransactionDetail.getNewTransactionMappings().entrySet()) {
|
for (final Map.Entry<Long, LoanTransaction> mapEntry : changedTransactionDetail.getNewTransactionMappings().entrySet()) {
|
||||||
mapEntry.getValue().updateLoan(this);
|
mapEntry.getValue().updateLoan(this);
|
||||||
@@ -4008,8 +4010,8 @@ public class Loan extends AbstractAuditableWithUTCDateTimeCustom {
|
|||||||
}
|
}
|
||||||
|
|
||||||
addLoanTransaction(loanTransaction);
|
addLoanTransaction(loanTransaction);
|
||||||
loanRepaymentScheduleTransactionProcessor.handleWriteOff(loanTransaction, loanCurrency(),
|
loanRepaymentScheduleTransactionProcessor.processLatestTransaction(loanTransaction, loanCurrency(),
|
||||||
getRepaymentScheduleInstallments());
|
getRepaymentScheduleInstallments(), getActiveCharges(), getTotalOverpaidAsMoney());
|
||||||
|
|
||||||
updateLoanSummaryDerivedFields();
|
updateLoanSummaryDerivedFields();
|
||||||
} else if (totalOutstanding.isGreaterThanZero()) {
|
} else if (totalOutstanding.isGreaterThanZero()) {
|
||||||
@@ -5400,7 +5402,7 @@ public class Loan extends AbstractAuditableWithUTCDateTimeCustom {
|
|||||||
final LoanRepaymentScheduleTransactionProcessor loanRepaymentScheduleTransactionProcessor = this.transactionProcessorFactory
|
final LoanRepaymentScheduleTransactionProcessor loanRepaymentScheduleTransactionProcessor = this.transactionProcessorFactory
|
||||||
.determineProcessor(this.transactionProcessingStrategyCode);
|
.determineProcessor(this.transactionProcessingStrategyCode);
|
||||||
final List<LoanTransaction> allNonContraTransactionsPostDisbursement = retrieveListOfTransactionsPostDisbursement();
|
final List<LoanTransaction> allNonContraTransactionsPostDisbursement = retrieveListOfTransactionsPostDisbursement();
|
||||||
ChangedTransactionDetail changedTransactionDetail = loanRepaymentScheduleTransactionProcessor.handleTransaction(
|
ChangedTransactionDetail changedTransactionDetail = loanRepaymentScheduleTransactionProcessor.reprocessLoanTranactions(
|
||||||
getDisbursementDate(), allNonContraTransactionsPostDisbursement, getCurrency(), getRepaymentScheduleInstallments(),
|
getDisbursementDate(), allNonContraTransactionsPostDisbursement, getCurrency(), getRepaymentScheduleInstallments(),
|
||||||
getActiveCharges());
|
getActiveCharges());
|
||||||
for (final Map.Entry<Long, LoanTransaction> mapEntry : changedTransactionDetail.getNewTransactionMappings().entrySet()) {
|
for (final Map.Entry<Long, LoanTransaction> mapEntry : changedTransactionDetail.getNewTransactionMappings().entrySet()) {
|
||||||
@@ -5478,6 +5480,10 @@ public class Loan extends AbstractAuditableWithUTCDateTimeCustom {
|
|||||||
return this.totalOverpaid;
|
return this.totalOverpaid;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public Money getTotalOverpaidAsMoney() {
|
||||||
|
return Money.of(this.repaymentScheduleDetail().getCurrency(), this.totalOverpaid);
|
||||||
|
}
|
||||||
|
|
||||||
public LocalDate getOverpaidOnDate() {
|
public LocalDate getOverpaidOnDate() {
|
||||||
return this.overpaidOnDate;
|
return this.overpaidOnDate;
|
||||||
}
|
}
|
||||||
@@ -5539,7 +5545,7 @@ public class Loan extends AbstractAuditableWithUTCDateTimeCustom {
|
|||||||
final LoanRepaymentScheduleTransactionProcessor loanRepaymentScheduleTransactionProcessor = this.transactionProcessorFactory
|
final LoanRepaymentScheduleTransactionProcessor loanRepaymentScheduleTransactionProcessor = this.transactionProcessorFactory
|
||||||
.determineProcessor(this.transactionProcessingStrategyCode);
|
.determineProcessor(this.transactionProcessingStrategyCode);
|
||||||
final List<LoanTransaction> allNonContraTransactionsPostDisbursement = retrieveListOfTransactionsPostDisbursement();
|
final List<LoanTransaction> allNonContraTransactionsPostDisbursement = retrieveListOfTransactionsPostDisbursement();
|
||||||
ChangedTransactionDetail changedTransactionDetail = loanRepaymentScheduleTransactionProcessor.handleTransaction(
|
ChangedTransactionDetail changedTransactionDetail = loanRepaymentScheduleTransactionProcessor.reprocessLoanTranactions(
|
||||||
getDisbursementDate(), allNonContraTransactionsPostDisbursement, getCurrency(), getRepaymentScheduleInstallments(),
|
getDisbursementDate(), allNonContraTransactionsPostDisbursement, getCurrency(), getRepaymentScheduleInstallments(),
|
||||||
getActiveCharges());
|
getActiveCharges());
|
||||||
for (final Map.Entry<Long, LoanTransaction> mapEntry : changedTransactionDetail.getNewTransactionMappings().entrySet()) {
|
for (final Map.Entry<Long, LoanTransaction> mapEntry : changedTransactionDetail.getNewTransactionMappings().entrySet()) {
|
||||||
@@ -5782,7 +5788,7 @@ public class Loan extends AbstractAuditableWithUTCDateTimeCustom {
|
|||||||
for (LoanTransaction loanTransaction : allNonContraTransactionsPostDisbursement) {
|
for (LoanTransaction loanTransaction : allNonContraTransactionsPostDisbursement) {
|
||||||
copyTransactions.add(LoanTransaction.copyTransactionProperties(loanTransaction));
|
copyTransactions.add(LoanTransaction.copyTransactionProperties(loanTransaction));
|
||||||
}
|
}
|
||||||
loanRepaymentScheduleTransactionProcessor.handleTransaction(getDisbursementDate(), copyTransactions, getCurrency(),
|
loanRepaymentScheduleTransactionProcessor.reprocessLoanTranactions(getDisbursementDate(), copyTransactions, getCurrency(),
|
||||||
getRepaymentScheduleInstallments(), getActiveCharges());
|
getRepaymentScheduleInstallments(), getActiveCharges());
|
||||||
|
|
||||||
updateLoanSummaryDerivedFields();
|
updateLoanSummaryDerivedFields();
|
||||||
@@ -6382,11 +6388,11 @@ public class Loan extends AbstractAuditableWithUTCDateTimeCustom {
|
|||||||
|
|
||||||
// If is a refund
|
// If is a refund
|
||||||
if (adjustedTransaction == null) {
|
if (adjustedTransaction == null) {
|
||||||
loanRepaymentScheduleTransactionProcessor.handleRefund(loanTransaction, getCurrency(), getRepaymentScheduleInstallments(),
|
loanRepaymentScheduleTransactionProcessor.processLatestTransaction(loanTransaction, getCurrency(),
|
||||||
getActiveCharges());
|
getRepaymentScheduleInstallments(), getActiveCharges(), getTotalOverpaidAsMoney());
|
||||||
} else {
|
} else {
|
||||||
final List<LoanTransaction> allNonContraTransactionsPostDisbursement = retrieveListOfTransactionsPostDisbursement();
|
final List<LoanTransaction> allNonContraTransactionsPostDisbursement = retrieveListOfTransactionsPostDisbursement();
|
||||||
changedTransactionDetail = loanRepaymentScheduleTransactionProcessor.handleTransaction(getDisbursementDate(),
|
changedTransactionDetail = loanRepaymentScheduleTransactionProcessor.reprocessLoanTranactions(getDisbursementDate(),
|
||||||
allNonContraTransactionsPostDisbursement, getCurrency(), getRepaymentScheduleInstallments(), getActiveCharges());
|
allNonContraTransactionsPostDisbursement, getCurrency(), getRepaymentScheduleInstallments(), getActiveCharges());
|
||||||
for (final Map.Entry<Long, LoanTransaction> mapEntry : changedTransactionDetail.getNewTransactionMappings().entrySet()) {
|
for (final Map.Entry<Long, LoanTransaction> mapEntry : changedTransactionDetail.getNewTransactionMappings().entrySet()) {
|
||||||
mapEntry.getValue().updateLoan(this);
|
mapEntry.getValue().updateLoan(this);
|
||||||
@@ -6411,13 +6417,10 @@ public class Loan extends AbstractAuditableWithUTCDateTimeCustom {
|
|||||||
|
|
||||||
final LoanRepaymentScheduleTransactionProcessor loanRepaymentScheduleTransactionProcessor = this.transactionProcessorFactory
|
final LoanRepaymentScheduleTransactionProcessor loanRepaymentScheduleTransactionProcessor = this.transactionProcessorFactory
|
||||||
.determineProcessor(this.transactionProcessingStrategyCode);
|
.determineProcessor(this.transactionProcessingStrategyCode);
|
||||||
final Money overpaidAmount = MathUtil.negativeToZero(calculateTotalOverpayment()); // Before Transaction
|
|
||||||
|
|
||||||
if (chargebackTransaction.isNotZero(loanCurrency())) {
|
addLoanTransaction(chargebackTransaction);
|
||||||
addLoanTransaction(chargebackTransaction);
|
loanRepaymentScheduleTransactionProcessor.processLatestTransaction(chargebackTransaction, getCurrency(),
|
||||||
}
|
getRepaymentScheduleInstallments(), getActiveCharges(), getTotalOverpaidAsMoney());
|
||||||
loanRepaymentScheduleTransactionProcessor.handleChargeback(chargebackTransaction, getCurrency(), overpaidAmount,
|
|
||||||
getRepaymentScheduleInstallments());
|
|
||||||
|
|
||||||
updateLoanSummaryDerivedFields();
|
updateLoanSummaryDerivedFields();
|
||||||
if (!doPostLoanTransactionChecks(chargebackTransaction.getTransactionDate(), loanLifecycleStateMachine)) {
|
if (!doPostLoanTransactionChecks(chargebackTransaction.getTransactionDate(), loanLifecycleStateMachine)) {
|
||||||
|
|||||||
+13
-16
@@ -36,15 +36,22 @@ public interface LoanRepaymentScheduleTransactionProcessor {
|
|||||||
|
|
||||||
boolean accept(String s);
|
boolean accept(String s);
|
||||||
|
|
||||||
void handleTransaction(LoanTransaction loanTransaction, MonetaryCurrency currency, List<LoanRepaymentScheduleInstallment> installments,
|
/**
|
||||||
Set<LoanCharge> charges);
|
* Provides support for processing the latest transaction (which should be latest transaction) against the loan
|
||||||
|
* schedule.
|
||||||
|
*/
|
||||||
|
void processLatestTransaction(LoanTransaction loanTransaction, MonetaryCurrency currency,
|
||||||
|
List<LoanRepaymentScheduleInstallment> installments, Set<LoanCharge> charges, Money overpaidAmount);
|
||||||
|
|
||||||
ChangedTransactionDetail handleTransaction(LocalDate disbursementDate, List<LoanTransaction> repaymentsOrWaivers,
|
/**
|
||||||
|
* Provides support for passing all {@link LoanTransaction}'s so it will completely re-process the entire loan
|
||||||
|
* schedule. This is required in cases where the {@link LoanTransaction} being processed is in the past and falls
|
||||||
|
* before existing transactions or and adjustment is made to an existing in which case the entire loan schedule
|
||||||
|
* needs to be re-processed.
|
||||||
|
*/
|
||||||
|
ChangedTransactionDetail reprocessLoanTranactions(LocalDate disbursementDate, List<LoanTransaction> repaymentsOrWaivers,
|
||||||
MonetaryCurrency currency, List<LoanRepaymentScheduleInstallment> repaymentScheduleInstallments, Set<LoanCharge> charges);
|
MonetaryCurrency currency, List<LoanRepaymentScheduleInstallment> repaymentScheduleInstallments, Set<LoanCharge> charges);
|
||||||
|
|
||||||
void handleWriteOff(LoanTransaction loanTransaction, MonetaryCurrency loanCurrency,
|
|
||||||
List<LoanRepaymentScheduleInstallment> repaymentScheduleInstallments);
|
|
||||||
|
|
||||||
Money handleRepaymentSchedule(List<LoanTransaction> transactionsPostDisbursement, MonetaryCurrency currency,
|
Money handleRepaymentSchedule(List<LoanTransaction> transactionsPostDisbursement, MonetaryCurrency currency,
|
||||||
List<LoanRepaymentScheduleInstallment> installments, Set<LoanCharge> loanCharges);
|
List<LoanRepaymentScheduleInstallment> installments, Set<LoanCharge> loanCharges);
|
||||||
|
|
||||||
@@ -52,14 +59,4 @@ public interface LoanRepaymentScheduleTransactionProcessor {
|
|||||||
* Used in interest recalculation to introduce new interest only installment.
|
* Used in interest recalculation to introduce new interest only installment.
|
||||||
*/
|
*/
|
||||||
boolean isInterestFirstRepaymentScheduleTransactionProcessor();
|
boolean isInterestFirstRepaymentScheduleTransactionProcessor();
|
||||||
|
|
||||||
void handleRefund(LoanTransaction loanTransaction, MonetaryCurrency currency, List<LoanRepaymentScheduleInstallment> installments,
|
|
||||||
Set<LoanCharge> charges);
|
|
||||||
|
|
||||||
void handleChargeback(LoanTransaction loanTransaction, MonetaryCurrency currency, Money overpaidAmount,
|
|
||||||
List<LoanRepaymentScheduleInstallment> installments);
|
|
||||||
|
|
||||||
void processTransactionsFromDerivedFields(List<LoanTransaction> transactionsPostDisbursement, MonetaryCurrency currency,
|
|
||||||
List<LoanRepaymentScheduleInstallment> installments, Set<LoanCharge> charges);
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|||||||
+139
-269
@@ -63,15 +63,8 @@ public abstract class AbstractLoanRepaymentScheduleTransactionProcessor implemen
|
|||||||
return getCode().equalsIgnoreCase(s) || getName().equalsIgnoreCase(s);
|
return getCode().equalsIgnoreCase(s) || getName().equalsIgnoreCase(s);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
* Provides support for passing all {@link LoanTransaction}'s so it will completely re-process the entire loan
|
|
||||||
* schedule. This is required in cases where the {@link LoanTransaction} being processed is in the past and falls
|
|
||||||
* before existing transactions or and adjustment is made to an existing in which case the entire loan schedule
|
|
||||||
* needs to be re-processed.
|
|
||||||
*/
|
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public ChangedTransactionDetail handleTransaction(final LocalDate disbursementDate,
|
public ChangedTransactionDetail reprocessLoanTranactions(final LocalDate disbursementDate,
|
||||||
final List<LoanTransaction> transactionsPostDisbursement, final MonetaryCurrency currency,
|
final List<LoanTransaction> transactionsPostDisbursement, final MonetaryCurrency currency,
|
||||||
final List<LoanRepaymentScheduleInstallment> installments, final Set<LoanCharge> charges) {
|
final List<LoanRepaymentScheduleInstallment> installments, final Set<LoanCharge> charges) {
|
||||||
|
|
||||||
@@ -155,20 +148,15 @@ public abstract class AbstractLoanRepaymentScheduleTransactionProcessor implemen
|
|||||||
for (final LoanTransaction loanTransaction : transactionsToBeProcessed) {
|
for (final LoanTransaction loanTransaction : transactionsToBeProcessed) {
|
||||||
// TODO: analyze and remove this
|
// TODO: analyze and remove this
|
||||||
if (!loanTransaction.getTypeOf().equals(LoanTransactionType.REFUND_FOR_ACTIVE_LOAN)) {
|
if (!loanTransaction.getTypeOf().equals(LoanTransactionType.REFUND_FOR_ACTIVE_LOAN)) {
|
||||||
final Comparator<LoanRepaymentScheduleInstallment> byDate = new Comparator<LoanRepaymentScheduleInstallment>() {
|
final Comparator<LoanRepaymentScheduleInstallment> byDate = Comparator
|
||||||
|
.comparing(LoanRepaymentScheduleInstallment::getDueDate);
|
||||||
@Override
|
installments.sort(byDate);
|
||||||
public int compare(LoanRepaymentScheduleInstallment ord1, LoanRepaymentScheduleInstallment ord2) {
|
|
||||||
return ord1.getDueDate().compareTo(ord2.getDueDate());
|
|
||||||
}
|
|
||||||
};
|
|
||||||
Collections.sort(installments, byDate);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if (loanTransaction.isRepaymentLikeType() || loanTransaction.isInterestWaiver() || loanTransaction.isRecoveryRepayment()) {
|
if (loanTransaction.isRepaymentLikeType() || loanTransaction.isInterestWaiver() || loanTransaction.isRecoveryRepayment()) {
|
||||||
// pass through for new transactions
|
// pass through for new transactions
|
||||||
if (loanTransaction.getId() == null) {
|
if (loanTransaction.getId() == null) {
|
||||||
handleTransaction(loanTransaction, currency, installments, charges);
|
processLatestTransaction(loanTransaction, currency, installments, charges, null);
|
||||||
loanTransaction.adjustInterestComponent(currency);
|
loanTransaction.adjustInterestComponent(currency);
|
||||||
} else {
|
} else {
|
||||||
/**
|
/**
|
||||||
@@ -179,7 +167,7 @@ public abstract class AbstractLoanRepaymentScheduleTransactionProcessor implemen
|
|||||||
|
|
||||||
// Reset derived component of new loan transaction and
|
// Reset derived component of new loan transaction and
|
||||||
// re-process transaction
|
// re-process transaction
|
||||||
handleTransaction(newLoanTransaction, currency, installments, charges);
|
processLatestTransaction(newLoanTransaction, currency, installments, charges, null);
|
||||||
newLoanTransaction.adjustInterestComponent(currency);
|
newLoanTransaction.adjustInterestComponent(currency);
|
||||||
/**
|
/**
|
||||||
* Check if the transaction amounts have changed. If so, reverse the original transaction and update
|
* Check if the transaction amounts have changed. If so, reverse the original transaction and update
|
||||||
@@ -212,6 +200,134 @@ public abstract class AbstractLoanRepaymentScheduleTransactionProcessor implemen
|
|||||||
return changedTransactionDetail;
|
return changedTransactionDetail;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void processLatestTransaction(final LoanTransaction loanTransaction, final MonetaryCurrency currency,
|
||||||
|
final List<LoanRepaymentScheduleInstallment> installments, final Set<LoanCharge> charges, Money overpaidAmount) {
|
||||||
|
switch (loanTransaction.getTypeOf()) {
|
||||||
|
case WRITEOFF -> handleWriteOff(loanTransaction, currency, installments);
|
||||||
|
case REFUND_FOR_ACTIVE_LOAN -> handleRefund(loanTransaction, currency, installments, charges);
|
||||||
|
case CHARGEBACK -> handleChargeback(loanTransaction, currency, overpaidAmount, installments);
|
||||||
|
default -> {
|
||||||
|
Money transactionAmountUnprocessed = handleTransactionAndCharges(loanTransaction, currency, installments, charges, null,
|
||||||
|
false);
|
||||||
|
if (transactionAmountUnprocessed.isGreaterThanZero()) {
|
||||||
|
if (loanTransaction.isWaiver()) {
|
||||||
|
loanTransaction.updateComponentsAndTotal(transactionAmountUnprocessed.zero(), transactionAmountUnprocessed.zero(),
|
||||||
|
transactionAmountUnprocessed.zero(), transactionAmountUnprocessed.zero());
|
||||||
|
} else {
|
||||||
|
onLoanOverpayment(loanTransaction, transactionAmountUnprocessed);
|
||||||
|
loanTransaction.updateOverPayments(transactionAmountUnprocessed);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public Money handleRepaymentSchedule(final List<LoanTransaction> transactionsPostDisbursement, final MonetaryCurrency currency,
|
||||||
|
final List<LoanRepaymentScheduleInstallment> installments, Set<LoanCharge> loanCharges) {
|
||||||
|
Money unProcessed = Money.zero(currency);
|
||||||
|
for (final LoanTransaction loanTransaction : transactionsPostDisbursement) {
|
||||||
|
if (loanTransaction.isRepaymentLikeType() || loanTransaction.isInterestWaiver() || loanTransaction.isRecoveryRepayment()) {
|
||||||
|
loanTransaction.resetDerivedComponents();
|
||||||
|
}
|
||||||
|
if (loanTransaction.isInterestWaiver()) {
|
||||||
|
processTransaction(loanTransaction, currency, installments, loanCharges, null);
|
||||||
|
} else {
|
||||||
|
unProcessed = processTransaction(loanTransaction, currency, installments, loanCharges, null);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return unProcessed;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean isInterestFirstRepaymentScheduleTransactionProcessor() {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
// abstract interface
|
||||||
|
|
||||||
|
/**
|
||||||
|
* For early/'in advance' repayments.
|
||||||
|
*
|
||||||
|
* @param transactionMappings
|
||||||
|
* TODO
|
||||||
|
* @param charges
|
||||||
|
*/
|
||||||
|
protected abstract Money handleTransactionThatIsPaymentInAdvanceOfInstallment(LoanRepaymentScheduleInstallment currentInstallment,
|
||||||
|
List<LoanRepaymentScheduleInstallment> installments, LoanTransaction loanTransaction, Money paymentInAdvance,
|
||||||
|
List<LoanTransactionToRepaymentScheduleMapping> transactionMappings, Set<LoanCharge> charges);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* For normal on-time repayments.
|
||||||
|
*
|
||||||
|
* @param transactionMappings
|
||||||
|
* TODO
|
||||||
|
* @param charges
|
||||||
|
*/
|
||||||
|
protected abstract Money handleTransactionThatIsOnTimePaymentOfInstallment(LoanRepaymentScheduleInstallment currentInstallment,
|
||||||
|
LoanTransaction loanTransaction, Money transactionAmountUnprocessed,
|
||||||
|
List<LoanTransactionToRepaymentScheduleMapping> transactionMappings, Set<LoanCharge> charges);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* For late repayments, how should components of installment be paid off
|
||||||
|
*
|
||||||
|
* @param transactionMappings
|
||||||
|
* TODO
|
||||||
|
* @param charges
|
||||||
|
*/
|
||||||
|
protected abstract Money handleTransactionThatIsALateRepaymentOfInstallment(LoanRepaymentScheduleInstallment currentInstallment,
|
||||||
|
List<LoanRepaymentScheduleInstallment> installments, LoanTransaction loanTransaction, Money transactionAmountUnprocessed,
|
||||||
|
List<LoanTransactionToRepaymentScheduleMapping> transactionMappings, Set<LoanCharge> charges);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Invoked when a transaction results in an over-payment of the full loan.
|
||||||
|
*
|
||||||
|
* transaction amount is greater than the total expected principal and interest of the loan.
|
||||||
|
*/
|
||||||
|
@SuppressWarnings("unused")
|
||||||
|
protected void onLoanOverpayment(final LoanTransaction loanTransaction, final Money loanOverPaymentAmount) {
|
||||||
|
// empty implementation by default.
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Invoked when a there is a refund of an active loan or undo of an active loan
|
||||||
|
*
|
||||||
|
* Undoes principal, interest, fees and charges of this transaction based on the repayment strategy
|
||||||
|
*
|
||||||
|
* @param transactionMappings
|
||||||
|
* TODO
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
protected abstract Money handleRefundTransactionPaymentOfInstallment(LoanRepaymentScheduleInstallment currentInstallment,
|
||||||
|
LoanTransaction loanTransaction, Money transactionAmountUnprocessed,
|
||||||
|
List<LoanTransactionToRepaymentScheduleMapping> transactionMappings);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* This method is responsible for checking if the current transaction is 'an advance/early payment' based on the
|
||||||
|
* details passed through.
|
||||||
|
*
|
||||||
|
* Default implementation is check transaction date is before installment due date.
|
||||||
|
*/
|
||||||
|
protected boolean isTransactionInAdvanceOfInstallment(final int installmentIndex,
|
||||||
|
final List<LoanRepaymentScheduleInstallment> installments, final LocalDate transactionDate) {
|
||||||
|
final LoanRepaymentScheduleInstallment currentInstallment = installments.get(installmentIndex);
|
||||||
|
return transactionDate.isBefore(currentInstallment.getDueDate());
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* This method is responsible for checking if the current transaction is 'an advance/early payment' based on the
|
||||||
|
* details passed through.
|
||||||
|
*
|
||||||
|
* Default implementation simply processes transactions as 'Late' if the transaction date is after the installment
|
||||||
|
* due date.
|
||||||
|
*/
|
||||||
|
protected boolean isTransactionALateRepaymentOnInstallment(final int installmentIndex,
|
||||||
|
final List<LoanRepaymentScheduleInstallment> installments, final LocalDate transactionDate) {
|
||||||
|
final LoanRepaymentScheduleInstallment currentInstallment = installments.get(installmentIndex);
|
||||||
|
return transactionDate.isAfter(currentInstallment.getDueDate());
|
||||||
|
}
|
||||||
|
|
||||||
private void recalculateChargeOffTransaction(ChangedTransactionDetail changedTransactionDetail, LoanTransaction loanTransaction,
|
private void recalculateChargeOffTransaction(ChangedTransactionDetail changedTransactionDetail, LoanTransaction loanTransaction,
|
||||||
MonetaryCurrency currency, List<LoanRepaymentScheduleInstallment> installments) {
|
MonetaryCurrency currency, List<LoanRepaymentScheduleInstallment> installments) {
|
||||||
final LoanTransaction newLoanTransaction = LoanTransaction.copyTransactionProperties(loanTransaction);
|
final LoanTransaction newLoanTransaction = LoanTransaction.copyTransactionProperties(loanTransaction);
|
||||||
@@ -422,42 +538,9 @@ public abstract class AbstractLoanRepaymentScheduleTransactionProcessor implemen
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
* Provides support for processing the latest transaction (which should be latest transaction) against the loan
|
|
||||||
* schedule.
|
|
||||||
*/
|
|
||||||
@Override
|
|
||||||
public void handleTransaction(final LoanTransaction loanTransaction, final MonetaryCurrency currency,
|
|
||||||
final List<LoanRepaymentScheduleInstallment> installments, final Set<LoanCharge> charges) {
|
|
||||||
|
|
||||||
final Money amountToProcess = null;
|
|
||||||
final boolean isChargeAmount = false;
|
|
||||||
handleTransaction(loanTransaction, currency, installments, charges, amountToProcess, isChargeAmount);
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
private void handleTransaction(final LoanTransaction loanTransaction, final MonetaryCurrency currency,
|
|
||||||
final List<LoanRepaymentScheduleInstallment> installments, final Set<LoanCharge> charges, final Money chargeAmountToProcess,
|
|
||||||
final boolean isFeeCharge) {
|
|
||||||
|
|
||||||
Money transactionAmountUnprocessed = handleTransactionAndCharges(loanTransaction, currency, installments, charges,
|
|
||||||
chargeAmountToProcess, isFeeCharge);
|
|
||||||
|
|
||||||
if (transactionAmountUnprocessed.isGreaterThanZero()) {
|
|
||||||
if (loanTransaction.isWaiver()) {
|
|
||||||
loanTransaction.updateComponentsAndTotal(transactionAmountUnprocessed.zero(), transactionAmountUnprocessed.zero(),
|
|
||||||
transactionAmountUnprocessed.zero(), transactionAmountUnprocessed.zero());
|
|
||||||
} else {
|
|
||||||
onLoanOverpayment(loanTransaction, transactionAmountUnprocessed);
|
|
||||||
loanTransaction.updateOverPayments(transactionAmountUnprocessed);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private Money handleTransactionAndCharges(final LoanTransaction loanTransaction, final MonetaryCurrency currency,
|
private Money handleTransactionAndCharges(final LoanTransaction loanTransaction, final MonetaryCurrency currency,
|
||||||
final List<LoanRepaymentScheduleInstallment> installments, final Set<LoanCharge> charges, final Money chargeAmountToProcess,
|
final List<LoanRepaymentScheduleInstallment> installments, final Set<LoanCharge> charges, final Money chargeAmountToProcess,
|
||||||
final boolean isFeeCharge) {
|
final boolean isFeeCharge) {
|
||||||
// to.
|
|
||||||
if (loanTransaction.isRepaymentLikeType() || loanTransaction.isInterestWaiver() || loanTransaction.isRecoveryRepayment()) {
|
if (loanTransaction.isRepaymentLikeType() || loanTransaction.isInterestWaiver() || loanTransaction.isRecoveryRepayment()) {
|
||||||
loanTransaction.resetDerivedComponents();
|
loanTransaction.resetDerivedComponents();
|
||||||
}
|
}
|
||||||
@@ -505,20 +588,13 @@ public abstract class AbstractLoanRepaymentScheduleTransactionProcessor implemen
|
|||||||
for (final LoanRepaymentScheduleInstallment currentInstallment : installments) {
|
for (final LoanRepaymentScheduleInstallment currentInstallment : installments) {
|
||||||
if (transactionAmountUnprocessed.isGreaterThanZero()) {
|
if (transactionAmountUnprocessed.isGreaterThanZero()) {
|
||||||
if (currentInstallment.isNotFullyPaidOff()) {
|
if (currentInstallment.isNotFullyPaidOff()) {
|
||||||
|
|
||||||
// is this transaction early/late/on-time with respect to
|
|
||||||
// the
|
|
||||||
// current installment?
|
|
||||||
if (isTransactionInAdvanceOfInstallment(installmentIndex, installments, transactionDate)) {
|
if (isTransactionInAdvanceOfInstallment(installmentIndex, installments, transactionDate)) {
|
||||||
transactionAmountUnprocessed = handleTransactionThatIsPaymentInAdvanceOfInstallment(currentInstallment,
|
transactionAmountUnprocessed = handleTransactionThatIsPaymentInAdvanceOfInstallment(currentInstallment,
|
||||||
installments, loanTransaction, transactionAmountUnprocessed, transactionMappings, charges);
|
installments, loanTransaction, transactionAmountUnprocessed, transactionMappings, charges);
|
||||||
} else if (isTransactionALateRepaymentOnInstallment(installmentIndex, installments, transactionDate)) {
|
} else if (isTransactionALateRepaymentOnInstallment(installmentIndex, installments, transactionDate)) {
|
||||||
// does this result in a late payment of existing
|
|
||||||
// installment?
|
|
||||||
transactionAmountUnprocessed = handleTransactionThatIsALateRepaymentOfInstallment(currentInstallment, installments,
|
transactionAmountUnprocessed = handleTransactionThatIsALateRepaymentOfInstallment(currentInstallment, installments,
|
||||||
loanTransaction, transactionAmountUnprocessed, transactionMappings, charges);
|
loanTransaction, transactionAmountUnprocessed, transactionMappings, charges);
|
||||||
} else {
|
} else {
|
||||||
// standard transaction
|
|
||||||
transactionAmountUnprocessed = handleTransactionThatIsOnTimePaymentOfInstallment(currentInstallment,
|
transactionAmountUnprocessed = handleTransactionThatIsOnTimePaymentOfInstallment(currentInstallment,
|
||||||
loanTransaction, transactionAmountUnprocessed, transactionMappings, charges);
|
loanTransaction, transactionAmountUnprocessed, transactionMappings, charges);
|
||||||
}
|
}
|
||||||
@@ -611,8 +687,7 @@ public abstract class AbstractLoanRepaymentScheduleTransactionProcessor implemen
|
|||||||
return earliestUnpaidCharge;
|
return earliestUnpaidCharge;
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
private void handleWriteOff(final LoanTransaction loanTransaction, final MonetaryCurrency currency,
|
||||||
public void handleWriteOff(final LoanTransaction loanTransaction, final MonetaryCurrency currency,
|
|
||||||
final List<LoanRepaymentScheduleInstallment> installments) {
|
final List<LoanRepaymentScheduleInstallment> installments) {
|
||||||
|
|
||||||
final LocalDate transactionDate = loanTransaction.getTransactionDate();
|
final LocalDate transactionDate = loanTransaction.getTransactionDate();
|
||||||
@@ -637,121 +712,16 @@ public abstract class AbstractLoanRepaymentScheduleTransactionProcessor implemen
|
|||||||
loanTransaction.updateComponentsAndTotal(principalPortion, interestPortion, feeChargesPortion, penaltychargesPortion);
|
loanTransaction.updateComponentsAndTotal(principalPortion, interestPortion, feeChargesPortion, penaltychargesPortion);
|
||||||
}
|
}
|
||||||
|
|
||||||
// abstract interface
|
private void handleChargeback(LoanTransaction loanTransaction, MonetaryCurrency currency, Money overpaidAmount,
|
||||||
/**
|
|
||||||
* This method is responsible for checking if the current transaction is 'an advance/early payment' based on the
|
|
||||||
* details passed through.
|
|
||||||
*
|
|
||||||
* Default implementation simply processes transactions as 'Late' if the transaction date is after the installment
|
|
||||||
* due date.
|
|
||||||
*/
|
|
||||||
protected boolean isTransactionALateRepaymentOnInstallment(final int installmentIndex,
|
|
||||||
final List<LoanRepaymentScheduleInstallment> installments, final LocalDate transactionDate) {
|
|
||||||
|
|
||||||
final LoanRepaymentScheduleInstallment currentInstallment = installments.get(installmentIndex);
|
|
||||||
|
|
||||||
return transactionDate.isAfter(currentInstallment.getDueDate());
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* For late repayments, how should components of installment be paid off
|
|
||||||
*
|
|
||||||
* @param transactionMappings
|
|
||||||
* TODO
|
|
||||||
* @param charges
|
|
||||||
*/
|
|
||||||
protected abstract Money handleTransactionThatIsALateRepaymentOfInstallment(LoanRepaymentScheduleInstallment currentInstallment,
|
|
||||||
List<LoanRepaymentScheduleInstallment> installments, LoanTransaction loanTransaction, Money transactionAmountUnprocessed,
|
|
||||||
List<LoanTransactionToRepaymentScheduleMapping> transactionMappings, Set<LoanCharge> charges);
|
|
||||||
|
|
||||||
/**
|
|
||||||
* This method is responsible for checking if the current transaction is 'an advance/early payment' based on the
|
|
||||||
* details passed through.
|
|
||||||
*
|
|
||||||
* Default implementation is check transaction date is before installment due date.
|
|
||||||
*/
|
|
||||||
protected boolean isTransactionInAdvanceOfInstallment(final int currentInstallmentIndex,
|
|
||||||
final List<LoanRepaymentScheduleInstallment> installments, final LocalDate transactionDate) {
|
|
||||||
|
|
||||||
final LoanRepaymentScheduleInstallment currentInstallment = installments.get(currentInstallmentIndex);
|
|
||||||
|
|
||||||
return transactionDate.isBefore(currentInstallment.getDueDate());
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* For early/'in advance' repayments.
|
|
||||||
*
|
|
||||||
* @param transactionMappings
|
|
||||||
* TODO
|
|
||||||
* @param charges
|
|
||||||
*/
|
|
||||||
protected abstract Money handleTransactionThatIsPaymentInAdvanceOfInstallment(LoanRepaymentScheduleInstallment currentInstallment,
|
|
||||||
List<LoanRepaymentScheduleInstallment> installments, LoanTransaction loanTransaction, Money paymentInAdvance,
|
|
||||||
List<LoanTransactionToRepaymentScheduleMapping> transactionMappings, Set<LoanCharge> charges);
|
|
||||||
|
|
||||||
/**
|
|
||||||
* For normal on-time repayments.
|
|
||||||
*
|
|
||||||
* @param transactionMappings
|
|
||||||
* TODO
|
|
||||||
* @param charges
|
|
||||||
*/
|
|
||||||
protected abstract Money handleTransactionThatIsOnTimePaymentOfInstallment(LoanRepaymentScheduleInstallment currentInstallment,
|
|
||||||
LoanTransaction loanTransaction, Money transactionAmountUnprocessed,
|
|
||||||
List<LoanTransactionToRepaymentScheduleMapping> transactionMappings, Set<LoanCharge> charges);
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Invoked when a transaction results in an over-payment of the full loan.
|
|
||||||
*
|
|
||||||
* transaction amount is greater than the total expected principal and interest of the loan.
|
|
||||||
*/
|
|
||||||
@SuppressWarnings("unused")
|
|
||||||
protected void onLoanOverpayment(final LoanTransaction loanTransaction, final Money loanOverPaymentAmount) {
|
|
||||||
// empty implementation by default.
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public Money handleRepaymentSchedule(final List<LoanTransaction> transactionsPostDisbursement, final MonetaryCurrency currency,
|
|
||||||
final List<LoanRepaymentScheduleInstallment> installments, Set<LoanCharge> loanCharges) {
|
|
||||||
Money unProcessed = Money.zero(currency);
|
|
||||||
for (final LoanTransaction loanTransaction : transactionsPostDisbursement) {
|
|
||||||
Money amountToProcess = null;
|
|
||||||
if (loanTransaction.isRepaymentLikeType() || loanTransaction.isInterestWaiver() || loanTransaction.isRecoveryRepayment()) {
|
|
||||||
loanTransaction.resetDerivedComponents();
|
|
||||||
}
|
|
||||||
if (loanTransaction.isInterestWaiver()) {
|
|
||||||
processTransaction(loanTransaction, currency, installments, loanCharges, amountToProcess);
|
|
||||||
} else {
|
|
||||||
unProcessed = processTransaction(loanTransaction, currency, installments, loanCharges, amountToProcess);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return unProcessed;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public boolean isInterestFirstRepaymentScheduleTransactionProcessor() {
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void handleChargeback(LoanTransaction loanTransaction, MonetaryCurrency currency, Money overpaidAmount,
|
|
||||||
List<LoanRepaymentScheduleInstallment> installments) {
|
List<LoanRepaymentScheduleInstallment> installments) {
|
||||||
processCreditTransaction(loanTransaction, overpaidAmount, currency, installments);
|
processCreditTransaction(loanTransaction, overpaidAmount, currency, installments);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
private void handleRefund(LoanTransaction loanTransaction, MonetaryCurrency currency,
|
||||||
public void handleRefund(LoanTransaction loanTransaction, MonetaryCurrency currency,
|
|
||||||
List<LoanRepaymentScheduleInstallment> installments, final Set<LoanCharge> charges) {
|
List<LoanRepaymentScheduleInstallment> installments, final Set<LoanCharge> charges) {
|
||||||
// TODO Auto-generated method stub
|
|
||||||
List<LoanTransactionToRepaymentScheduleMapping> transactionMappings = new ArrayList<>();
|
List<LoanTransactionToRepaymentScheduleMapping> transactionMappings = new ArrayList<>();
|
||||||
final Comparator<LoanRepaymentScheduleInstallment> byDate = new Comparator<LoanRepaymentScheduleInstallment>() {
|
final Comparator<LoanRepaymentScheduleInstallment> byDate = Comparator.comparing(LoanRepaymentScheduleInstallment::getDueDate);
|
||||||
|
installments.sort(Collections.reverseOrder(byDate));
|
||||||
@Override
|
|
||||||
public int compare(LoanRepaymentScheduleInstallment ord1, LoanRepaymentScheduleInstallment ord2) {
|
|
||||||
return ord1.getDueDate().compareTo(ord2.getDueDate());
|
|
||||||
}
|
|
||||||
};
|
|
||||||
Collections.sort(installments, Collections.reverseOrder(byDate));
|
|
||||||
Money transactionAmountUnprocessed = loanTransaction.getAmount(currency);
|
Money transactionAmountUnprocessed = loanTransaction.getAmount(currency);
|
||||||
|
|
||||||
for (final LoanRepaymentScheduleInstallment currentInstallment : installments) {
|
for (final LoanRepaymentScheduleInstallment currentInstallment : installments) {
|
||||||
@@ -786,19 +756,6 @@ public abstract class AbstractLoanRepaymentScheduleTransactionProcessor implemen
|
|||||||
loanTransaction.updateLoanTransactionToRepaymentScheduleMappings(transactionMappings);
|
loanTransaction.updateLoanTransactionToRepaymentScheduleMappings(transactionMappings);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
* Invoked when a there is a refund of an active loan or undo of an active loan
|
|
||||||
*
|
|
||||||
* Undoes principal, interest, fees and charges of this transaction based on the repayment strategy
|
|
||||||
*
|
|
||||||
* @param transactionMappings
|
|
||||||
* TODO
|
|
||||||
*
|
|
||||||
*/
|
|
||||||
protected abstract Money handleRefundTransactionPaymentOfInstallment(LoanRepaymentScheduleInstallment currentInstallment,
|
|
||||||
LoanTransaction loanTransaction, Money transactionAmountUnprocessed,
|
|
||||||
List<LoanTransactionToRepaymentScheduleMapping> transactionMappings);
|
|
||||||
|
|
||||||
private void undoChargesPaidAmountBy(final LoanTransaction loanTransaction, final Money feeCharges, final Set<LoanCharge> charges,
|
private void undoChargesPaidAmountBy(final LoanTransaction loanTransaction, final Money feeCharges, final Set<LoanCharge> charges,
|
||||||
final Integer installmentNumber) {
|
final Integer installmentNumber) {
|
||||||
|
|
||||||
@@ -853,91 +810,4 @@ public abstract class AbstractLoanRepaymentScheduleTransactionProcessor implemen
|
|||||||
|
|
||||||
return latestPaidCharge;
|
return latestPaidCharge;
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
|
||||||
public void processTransactionsFromDerivedFields(List<LoanTransaction> transactionsPostDisbursement, MonetaryCurrency currency,
|
|
||||||
List<LoanRepaymentScheduleInstallment> installments, final Set<LoanCharge> charges) {
|
|
||||||
for (final LoanTransaction loanTransaction : transactionsPostDisbursement) {
|
|
||||||
if (!loanTransaction.isAccrualTransaction()) {
|
|
||||||
processTransactionFromDerivedFields(loanTransaction, currency, installments, charges);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private void processTransactionFromDerivedFields(final LoanTransaction loanTransaction, MonetaryCurrency currency,
|
|
||||||
List<LoanRepaymentScheduleInstallment> installments, final Set<LoanCharge> charges) {
|
|
||||||
Money principal = loanTransaction.getPrincipalPortion(currency);
|
|
||||||
Money interest = loanTransaction.getInterestPortion(currency);
|
|
||||||
if (loanTransaction.isInterestWaiver()) {
|
|
||||||
interest = loanTransaction.getAmount(currency);
|
|
||||||
}
|
|
||||||
Money feeCharges = loanTransaction.getFeeChargesPortion(currency);
|
|
||||||
Money penaltyCharges = loanTransaction.getPenaltyChargesPortion(currency);
|
|
||||||
final LocalDate transactionDate = loanTransaction.getTransactionDate();
|
|
||||||
if (principal.isGreaterThanZero() || interest.isGreaterThanZero() || feeCharges.isGreaterThanZero()
|
|
||||||
|| penaltyCharges.isGreaterThanZero()) {
|
|
||||||
for (final LoanRepaymentScheduleInstallment currentInstallment : installments) {
|
|
||||||
if (currentInstallment.isNotFullyPaidOff()) {
|
|
||||||
if (penaltyCharges.isGreaterThanZero()) {
|
|
||||||
Money penaltyChargesPortion = Money.zero(currency);
|
|
||||||
if (loanTransaction.isWaiver()) {
|
|
||||||
penaltyChargesPortion = currentInstallment.waivePenaltyChargesComponent(transactionDate, penaltyCharges);
|
|
||||||
} else {
|
|
||||||
penaltyChargesPortion = currentInstallment.payPenaltyChargesComponent(transactionDate, penaltyCharges);
|
|
||||||
}
|
|
||||||
penaltyCharges = penaltyCharges.minus(penaltyChargesPortion);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (feeCharges.isGreaterThanZero()) {
|
|
||||||
Money feeChargesPortion = Money.zero(currency);
|
|
||||||
if (loanTransaction.isWaiver()) {
|
|
||||||
feeChargesPortion = currentInstallment.waiveFeeChargesComponent(transactionDate, feeCharges);
|
|
||||||
} else {
|
|
||||||
feeChargesPortion = currentInstallment.payFeeChargesComponent(transactionDate, feeCharges);
|
|
||||||
}
|
|
||||||
feeCharges = feeCharges.minus(feeChargesPortion);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (interest.isGreaterThanZero()) {
|
|
||||||
Money interestPortion = Money.zero(currency);
|
|
||||||
if (loanTransaction.isWaiver()) {
|
|
||||||
interestPortion = currentInstallment.waiveInterestComponent(transactionDate, interest);
|
|
||||||
} else {
|
|
||||||
interestPortion = currentInstallment.payInterestComponent(transactionDate, interest);
|
|
||||||
}
|
|
||||||
interest = interest.minus(interestPortion);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (principal.isGreaterThanZero()) {
|
|
||||||
Money principalPortion = currentInstallment.payPrincipalComponent(transactionDate, principal);
|
|
||||||
principal = principal.minus(principalPortion);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if (!(principal.isGreaterThanZero() || interest.isGreaterThanZero() || feeCharges.isGreaterThanZero()
|
|
||||||
|| penaltyCharges.isGreaterThanZero())) {
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
final Set<LoanCharge> loanFees = extractFeeCharges(charges);
|
|
||||||
final Set<LoanCharge> loanPenalties = extractPenaltyCharges(charges);
|
|
||||||
Integer installmentNumber = null;
|
|
||||||
if (loanTransaction.isChargePayment() && installments.size() == 1) {
|
|
||||||
installmentNumber = installments.get(0).getInstallmentNumber();
|
|
||||||
}
|
|
||||||
|
|
||||||
if (loanTransaction.isNotWaiver()) {
|
|
||||||
feeCharges = loanTransaction.getFeeChargesPortion(currency);
|
|
||||||
penaltyCharges = loanTransaction.getPenaltyChargesPortion(currency);
|
|
||||||
if (feeCharges.isGreaterThanZero()) {
|
|
||||||
updateChargesPaidAmountBy(loanTransaction, feeCharges, loanFees, installmentNumber);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (penaltyCharges.isGreaterThanZero()) {
|
|
||||||
updateChargesPaidAmountBy(loanTransaction, penaltyCharges, loanPenalties, installmentNumber);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|||||||
+21
@@ -18,10 +18,13 @@
|
|||||||
*/
|
*/
|
||||||
package org.apache.fineract.portfolio.loanaccount.domain.transactionprocessor.impl;
|
package org.apache.fineract.portfolio.loanaccount.domain.transactionprocessor.impl;
|
||||||
|
|
||||||
|
import java.time.LocalDate;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
import java.util.Set;
|
import java.util.Set;
|
||||||
import org.apache.commons.lang3.NotImplementedException;
|
import org.apache.commons.lang3.NotImplementedException;
|
||||||
|
import org.apache.fineract.organisation.monetary.domain.MonetaryCurrency;
|
||||||
import org.apache.fineract.organisation.monetary.domain.Money;
|
import org.apache.fineract.organisation.monetary.domain.Money;
|
||||||
|
import org.apache.fineract.portfolio.loanaccount.domain.ChangedTransactionDetail;
|
||||||
import org.apache.fineract.portfolio.loanaccount.domain.LoanCharge;
|
import org.apache.fineract.portfolio.loanaccount.domain.LoanCharge;
|
||||||
import org.apache.fineract.portfolio.loanaccount.domain.LoanRepaymentScheduleInstallment;
|
import org.apache.fineract.portfolio.loanaccount.domain.LoanRepaymentScheduleInstallment;
|
||||||
import org.apache.fineract.portfolio.loanaccount.domain.LoanTransaction;
|
import org.apache.fineract.portfolio.loanaccount.domain.LoanTransaction;
|
||||||
@@ -69,4 +72,22 @@ public class AdvancedPaymentScheduleTransactionProcessor extends AbstractLoanRep
|
|||||||
List<LoanTransactionToRepaymentScheduleMapping> transactionMappings) {
|
List<LoanTransactionToRepaymentScheduleMapping> transactionMappings) {
|
||||||
throw new NotImplementedException();
|
throw new NotImplementedException();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public ChangedTransactionDetail reprocessLoanTranactions(LocalDate disbursementDate, List<LoanTransaction> transactionsPostDisbursement,
|
||||||
|
MonetaryCurrency currency, List<LoanRepaymentScheduleInstallment> installments, Set<LoanCharge> charges) {
|
||||||
|
throw new NotImplementedException();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void processLatestTransaction(LoanTransaction loanTransaction, MonetaryCurrency currency,
|
||||||
|
List<LoanRepaymentScheduleInstallment> installments, Set<LoanCharge> charges, Money overpaidAmount) {
|
||||||
|
throw new NotImplementedException();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public Money handleRepaymentSchedule(List<LoanTransaction> transactionsPostDisbursement, MonetaryCurrency currency,
|
||||||
|
List<LoanRepaymentScheduleInstallment> installments, Set<LoanCharge> loanCharges) {
|
||||||
|
return super.handleRepaymentSchedule(transactionsPostDisbursement, currency, installments, loanCharges);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
-18
@@ -56,18 +56,6 @@ public class CreocoreLoanRepaymentScheduleTransactionProcessor extends AbstractL
|
|||||||
return STRATEGY_NAME;
|
return STRATEGY_NAME;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
* For creocore, early is defined as any date before the installment due date
|
|
||||||
*/
|
|
||||||
@Override
|
|
||||||
protected boolean isTransactionInAdvanceOfInstallment(final int currentInstallmentIndex,
|
|
||||||
final List<LoanRepaymentScheduleInstallment> installments, final LocalDate transactionDate) {
|
|
||||||
|
|
||||||
final LoanRepaymentScheduleInstallment currentInstallment = installments.get(currentInstallmentIndex);
|
|
||||||
|
|
||||||
return transactionDate.isBefore(currentInstallment.getDueDate());
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* For early/'in advance' repayments, pay off in the same way as on-time payments, interest first then principal.
|
* For early/'in advance' repayments, pay off in the same way as on-time payments, interest first then principal.
|
||||||
*/
|
*/
|
||||||
@@ -153,12 +141,6 @@ public class CreocoreLoanRepaymentScheduleTransactionProcessor extends AbstractL
|
|||||||
return transactionAmountRemaining;
|
return transactionAmountRemaining;
|
||||||
}
|
}
|
||||||
|
|
||||||
@SuppressWarnings("unused")
|
|
||||||
@Override
|
|
||||||
protected void onLoanOverpayment(final LoanTransaction loanTransaction, final Money loanOverPaymentAmount) {
|
|
||||||
// dont do anything for with loan over-payment
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
protected Money handleRefundTransactionPaymentOfInstallment(final LoanRepaymentScheduleInstallment currentInstallment,
|
protected Money handleRefundTransactionPaymentOfInstallment(final LoanRepaymentScheduleInstallment currentInstallment,
|
||||||
final LoanTransaction loanTransaction, final Money transactionAmountUnprocessed,
|
final LoanTransaction loanTransaction, final Money transactionAmountUnprocessed,
|
||||||
|
|||||||
-5
@@ -245,11 +245,6 @@ public class DuePenFeeIntPriInAdvancePriPenFeeIntLoanRepaymentScheduleTransactio
|
|||||||
return transactionAmountRemaining;
|
return transactionAmountRemaining;
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
|
||||||
protected void onLoanOverpayment(final LoanTransaction loanTransaction, final Money loanOverPaymentAmount) {
|
|
||||||
// TODO - KW - dont do anything with loan over-payment for now
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
protected Money handleRefundTransactionPaymentOfInstallment(final LoanRepaymentScheduleInstallment currentInstallment,
|
protected Money handleRefundTransactionPaymentOfInstallment(final LoanRepaymentScheduleInstallment currentInstallment,
|
||||||
final LoanTransaction loanTransaction, final Money transactionAmountUnprocessed,
|
final LoanTransaction loanTransaction, final Money transactionAmountUnprocessed,
|
||||||
|
|||||||
-5
@@ -247,11 +247,6 @@ public class DuePenIntPriFeeInAdvancePenIntPriFeeLoanRepaymentScheduleTransactio
|
|||||||
return transactionAmountRemaining;
|
return transactionAmountRemaining;
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
|
||||||
protected void onLoanOverpayment(final LoanTransaction loanTransaction, final Money loanOverPaymentAmount) {
|
|
||||||
// TODO - KW - dont do anything with loan over-payment for now
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
protected Money handleRefundTransactionPaymentOfInstallment(final LoanRepaymentScheduleInstallment currentInstallment,
|
protected Money handleRefundTransactionPaymentOfInstallment(final LoanRepaymentScheduleInstallment currentInstallment,
|
||||||
final LoanTransaction loanTransaction, final Money transactionAmountUnprocessed,
|
final LoanTransaction loanTransaction, final Money transactionAmountUnprocessed,
|
||||||
|
|||||||
+4
-18
@@ -56,15 +56,6 @@ public class FineractStyleLoanRepaymentScheduleTransactionProcessor extends Abst
|
|||||||
return STRATEGY_NAME;
|
return STRATEGY_NAME;
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
|
||||||
protected boolean isTransactionInAdvanceOfInstallment(final int currentInstallmentIndex,
|
|
||||||
final List<LoanRepaymentScheduleInstallment> installments, final LocalDate transactionDate) {
|
|
||||||
|
|
||||||
final LoanRepaymentScheduleInstallment currentInstallment = installments.get(currentInstallmentIndex);
|
|
||||||
|
|
||||||
return transactionDate.isBefore(currentInstallment.getDueDate());
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* For early/'in advance' repayments, pay off in the same way as on-time payments, interest first then principal.
|
* For early/'in advance' repayments, pay off in the same way as on-time payments, interest first then principal.
|
||||||
*/
|
*/
|
||||||
@@ -151,11 +142,6 @@ public class FineractStyleLoanRepaymentScheduleTransactionProcessor extends Abst
|
|||||||
return transactionAmountRemaining;
|
return transactionAmountRemaining;
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
|
||||||
protected void onLoanOverpayment(final LoanTransaction loanTransaction, final Money loanOverPaymentAmount) {
|
|
||||||
// TODO - KW - dont do anything with loan over-payment for now
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
protected Money handleRefundTransactionPaymentOfInstallment(final LoanRepaymentScheduleInstallment currentInstallment,
|
protected Money handleRefundTransactionPaymentOfInstallment(final LoanRepaymentScheduleInstallment currentInstallment,
|
||||||
final LoanTransaction loanTransaction, final Money transactionAmountUnprocessed,
|
final LoanTransaction loanTransaction, final Money transactionAmountUnprocessed,
|
||||||
@@ -164,10 +150,10 @@ public class FineractStyleLoanRepaymentScheduleTransactionProcessor extends Abst
|
|||||||
final LocalDate transactionDate = loanTransaction.getTransactionDate();
|
final LocalDate transactionDate = loanTransaction.getTransactionDate();
|
||||||
final MonetaryCurrency currency = transactionAmountUnprocessed.getCurrency();
|
final MonetaryCurrency currency = transactionAmountUnprocessed.getCurrency();
|
||||||
Money transactionAmountRemaining = transactionAmountUnprocessed;
|
Money transactionAmountRemaining = transactionAmountUnprocessed;
|
||||||
Money principalPortion = Money.zero(transactionAmountRemaining.getCurrency());
|
Money principalPortion = Money.zero(currency);
|
||||||
Money interestPortion = Money.zero(transactionAmountRemaining.getCurrency());
|
Money interestPortion = Money.zero(currency);
|
||||||
Money feeChargesPortion = Money.zero(transactionAmountRemaining.getCurrency());
|
Money feeChargesPortion = Money.zero(currency);
|
||||||
Money penaltyChargesPortion = Money.zero(transactionAmountRemaining.getCurrency());
|
Money penaltyChargesPortion = Money.zero(currency);
|
||||||
|
|
||||||
principalPortion = currentInstallment.unpayPrincipalComponent(transactionDate, transactionAmountRemaining);
|
principalPortion = currentInstallment.unpayPrincipalComponent(transactionDate, transactionAmountRemaining);
|
||||||
transactionAmountRemaining = transactionAmountRemaining.minus(principalPortion);
|
transactionAmountRemaining = transactionAmountRemaining.minus(principalPortion);
|
||||||
|
|||||||
-3
@@ -216,9 +216,6 @@ public class HeavensFamilyLoanRepaymentScheduleTransactionProcessor extends Abst
|
|||||||
return transactionAmountRemaining;
|
return transactionAmountRemaining;
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
|
||||||
protected void onLoanOverpayment(final LoanTransaction loanTransaction, final Money loanOverPaymentAmount) {}
|
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
protected Money handleRefundTransactionPaymentOfInstallment(final LoanRepaymentScheduleInstallment currentInstallment,
|
protected Money handleRefundTransactionPaymentOfInstallment(final LoanRepaymentScheduleInstallment currentInstallment,
|
||||||
final LoanTransaction loanTransaction, final Money transactionAmountUnprocessed,
|
final LoanTransaction loanTransaction, final Money transactionAmountUnprocessed,
|
||||||
|
|||||||
-19
@@ -59,19 +59,6 @@ public class RBILoanRepaymentScheduleTransactionProcessor extends AbstractLoanRe
|
|||||||
return STRATEGY_NAME;
|
return STRATEGY_NAME;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
* For creocore, early is defined as any date before the installment due date
|
|
||||||
*/
|
|
||||||
@SuppressWarnings("unused")
|
|
||||||
@Override
|
|
||||||
protected boolean isTransactionInAdvanceOfInstallment(final int currentInstallmentIndex,
|
|
||||||
final List<LoanRepaymentScheduleInstallment> installments, final LocalDate transactionDate) {
|
|
||||||
|
|
||||||
final LoanRepaymentScheduleInstallment currentInstallment = installments.get(currentInstallmentIndex);
|
|
||||||
|
|
||||||
return transactionDate.isBefore(currentInstallment.getDueDate());
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* For early/'in advance' repayments, pays off principal component only.
|
* For early/'in advance' repayments, pays off principal component only.
|
||||||
*/
|
*/
|
||||||
@@ -259,12 +246,6 @@ public class RBILoanRepaymentScheduleTransactionProcessor extends AbstractLoanRe
|
|||||||
return transactionAmountRemaining;
|
return transactionAmountRemaining;
|
||||||
}
|
}
|
||||||
|
|
||||||
@SuppressWarnings("unused")
|
|
||||||
@Override
|
|
||||||
protected void onLoanOverpayment(final LoanTransaction loanTransaction, final Money loanOverPaymentAmount) {
|
|
||||||
// dont do anything for with loan over-payment
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public boolean isInterestFirstRepaymentScheduleTransactionProcessor() {
|
public boolean isInterestFirstRepaymentScheduleTransactionProcessor() {
|
||||||
return true;
|
return true;
|
||||||
|
|||||||
+2
-2
@@ -2808,8 +2808,8 @@ public abstract class AbstractLoanScheduleGenerator implements LoanScheduleGener
|
|||||||
loanRepaymentScheduleTransactionProcessor, onDate, calculateTill);
|
loanRepaymentScheduleTransactionProcessor, onDate, calculateTill);
|
||||||
List<LoanTransaction> loanTransactions = loan.retrieveListOfTransactionsPostDisbursementExcludeAccruals();
|
List<LoanTransaction> loanTransactions = loan.retrieveListOfTransactionsPostDisbursementExcludeAccruals();
|
||||||
|
|
||||||
loanRepaymentScheduleTransactionProcessor.handleTransaction(loanApplicationTerms.getExpectedDisbursementDate(), loanTransactions,
|
loanRepaymentScheduleTransactionProcessor.reprocessLoanTranactions(loanApplicationTerms.getExpectedDisbursementDate(),
|
||||||
currency, loanScheduleDTO.getInstallments(), loan.getActiveCharges());
|
loanTransactions, currency, loanScheduleDTO.getInstallments(), loan.getActiveCharges());
|
||||||
Money feeCharges = Money.zero(currency);
|
Money feeCharges = Money.zero(currency);
|
||||||
Money penaltyCharges = Money.zero(currency);
|
Money penaltyCharges = Money.zero(currency);
|
||||||
Money totalPrincipal = Money.zero(currency);
|
Money totalPrincipal = Money.zero(currency);
|
||||||
|
|||||||
+2
-2
@@ -809,8 +809,8 @@ public class LoanChargeWritePlatformServiceImpl implements LoanChargeWritePlatfo
|
|||||||
defaultLoanLifecycleStateMachine.transition(LoanEvent.LOAN_REPAYMENT_OR_WAIVER, loan);
|
defaultLoanLifecycleStateMachine.transition(LoanEvent.LOAN_REPAYMENT_OR_WAIVER, loan);
|
||||||
final LoanRepaymentScheduleTransactionProcessor loanRepaymentScheduleTransactionProcessor = loanRepaymentScheduleTransactionProcessorFactory
|
final LoanRepaymentScheduleTransactionProcessor loanRepaymentScheduleTransactionProcessor = loanRepaymentScheduleTransactionProcessorFactory
|
||||||
.determineProcessor(loan.transactionProcessingStrategy());
|
.determineProcessor(loan.transactionProcessingStrategy());
|
||||||
loanRepaymentScheduleTransactionProcessor.handleTransaction(loanChargeAdjustmentTransaction, loan.getCurrency(),
|
loanRepaymentScheduleTransactionProcessor.processLatestTransaction(loanChargeAdjustmentTransaction, loan.getCurrency(),
|
||||||
loan.getRepaymentScheduleInstallments(), loan.getActiveCharges());
|
loan.getRepaymentScheduleInstallments(), loan.getActiveCharges(), loan.getTotalOverpaidAsMoney());
|
||||||
|
|
||||||
loan.addLoanTransaction(loanChargeAdjustmentTransaction);
|
loan.addLoanTransaction(loanChargeAdjustmentTransaction);
|
||||||
loan.updateLoanSummaryAndStatus();
|
loan.updateLoanSummaryAndStatus();
|
||||||
|
|||||||
Reference in New Issue
Block a user