Merge branch 'PR95' into develop
This commit is contained in:
+5
-9
@@ -166,8 +166,7 @@ public class AccountingScenarioIntegrationTest {
|
||||
float expected_value = this.LP_PRINCIPAL - PRINCIPAL_VALUE_FOR_EACH_PERIOD;
|
||||
this.loanTransactionHelper.verifyRepaymentScheduleEntryFor(1, expected_value, loanID);
|
||||
final JournalEntry[] assetAccountFirstEntry = { new JournalEntry(this.REPAYMENT_AMOUNT[1], JournalEntry.TransactionType.DEBIT),
|
||||
new JournalEntry(FIRST_INTEREST, JournalEntry.TransactionType.CREDIT),
|
||||
new JournalEntry(FIRST_PRINCIPAL, JournalEntry.TransactionType.CREDIT), };
|
||||
new JournalEntry(FIRST_INTEREST + FIRST_PRINCIPAL, JournalEntry.TransactionType.CREDIT) };
|
||||
this.journalEntryHelper.checkJournalEntryForAssetAccount(assetAccount, this.REPAYMENT_DATE[1], assetAccountFirstEntry);
|
||||
System.out.println("Repayment 1 Done......");
|
||||
|
||||
@@ -179,8 +178,7 @@ public class AccountingScenarioIntegrationTest {
|
||||
expected_value = expected_value - PRINCIPAL_VALUE_FOR_EACH_PERIOD;
|
||||
this.loanTransactionHelper.verifyRepaymentScheduleEntryFor(2, expected_value, loanID);
|
||||
final JournalEntry[] assetAccountSecondEntry = { new JournalEntry(this.REPAYMENT_AMOUNT[2], JournalEntry.TransactionType.DEBIT),
|
||||
new JournalEntry(SECOND_AND_THIRD_INTEREST, JournalEntry.TransactionType.CREDIT),
|
||||
new JournalEntry(SECOND_PRINCIPAL, JournalEntry.TransactionType.CREDIT), };
|
||||
new JournalEntry(SECOND_AND_THIRD_INTEREST + SECOND_PRINCIPAL, JournalEntry.TransactionType.CREDIT) };
|
||||
this.journalEntryHelper.checkJournalEntryForAssetAccount(assetAccount, this.REPAYMENT_DATE[2], assetAccountSecondEntry);
|
||||
System.out.println("Repayment 2 Done ......");
|
||||
|
||||
@@ -605,8 +603,7 @@ public class AccountingScenarioIntegrationTest {
|
||||
float expected_value = this.LP_PRINCIPAL - PRINCIPAL_VALUE_FOR_EACH_PERIOD;
|
||||
this.loanTransactionHelper.verifyRepaymentScheduleEntryFor(1, expected_value, loanID);
|
||||
final JournalEntry[] assetAccountFirstEntry = { new JournalEntry(this.REPAYMENT_AMOUNT[1], JournalEntry.TransactionType.DEBIT),
|
||||
new JournalEntry(FIRST_INTEREST, JournalEntry.TransactionType.CREDIT),
|
||||
new JournalEntry(FIRST_PRINCIPAL, JournalEntry.TransactionType.CREDIT), };
|
||||
new JournalEntry(FIRST_INTEREST + FIRST_PRINCIPAL, JournalEntry.TransactionType.CREDIT) };
|
||||
this.journalEntryHelper.checkJournalEntryForAssetAccount(assetAccount, this.REPAYMENT_DATE[1], assetAccountFirstEntry);
|
||||
System.out.println("Repayment 1 Done......");
|
||||
|
||||
@@ -622,8 +619,7 @@ public class AccountingScenarioIntegrationTest {
|
||||
FEE_PORTION, PENALTY_PORTION, loanID);
|
||||
this.loanTransactionHelper.verifyRepaymentScheduleEntryFor(2, expected_value, loanID);
|
||||
final JournalEntry[] assetAccountSecondEntry = { new JournalEntry(this.REPAYMENT_AMOUNT[2], JournalEntry.TransactionType.DEBIT),
|
||||
new JournalEntry(SECOND_AND_THIRD_INTEREST, JournalEntry.TransactionType.CREDIT),
|
||||
new JournalEntry(SECOND_PRINCIPAL, JournalEntry.TransactionType.CREDIT), };
|
||||
new JournalEntry(SECOND_AND_THIRD_INTEREST + SECOND_PRINCIPAL, JournalEntry.TransactionType.CREDIT) };
|
||||
this.journalEntryHelper.checkJournalEntryForAssetAccount(assetAccount, this.REPAYMENT_DATE[2], assetAccountSecondEntry);
|
||||
System.out.println("Repayment 2 Done ......");
|
||||
|
||||
@@ -723,7 +719,7 @@ public class AccountingScenarioIntegrationTest {
|
||||
float expected_value = this.LP_PRINCIPAL - PRINCIPAL_VALUE_FOR_EACH_PERIOD;
|
||||
this.loanTransactionHelper.verifyRepaymentScheduleEntryFor(1, expected_value, loanID);
|
||||
final JournalEntry[] assetAccountEntry = { new JournalEntry(15000f, JournalEntry.TransactionType.DEBIT),
|
||||
new JournalEntry(1000f, JournalEntry.TransactionType.CREDIT), new JournalEntry(10000f, JournalEntry.TransactionType.CREDIT) };
|
||||
new JournalEntry(11000f, JournalEntry.TransactionType.CREDIT) };
|
||||
this.journalEntryHelper.checkJournalEntryForAssetAccount(assetAccount, this.REPAYMENT_DATE[1], assetAccountEntry);
|
||||
this.journalEntryHelper.checkJournalEntryForLiabilityAccount(overpaymentAccount, this.REPAYMENT_DATE[1], new JournalEntry(4000f,
|
||||
JournalEntry.TransactionType.CREDIT));
|
||||
|
||||
+165
-169
@@ -1873,9 +1873,8 @@ public class ClientLoanIntegrationTest {
|
||||
validateCharge(flatInstallmentFee, loanCharges, "50", "150.00", "50.0", "0.0");
|
||||
|
||||
this.journalEntryHelper.checkJournalEntryForAssetAccount(assetAccount, "20 October 2011", new JournalEntry(
|
||||
Float.valueOf("3301.49"), JournalEntry.TransactionType.DEBIT), new JournalEntry(Float.valueOf("150.00"),
|
||||
JournalEntry.TransactionType.CREDIT), new JournalEntry(Float.valueOf("240"), JournalEntry.TransactionType.CREDIT),
|
||||
new JournalEntry(Float.valueOf("2911.49"), JournalEntry.TransactionType.CREDIT));
|
||||
Float.valueOf("3301.49"), JournalEntry.TransactionType.DEBIT), new JournalEntry(Float.valueOf("3301.49"),
|
||||
JournalEntry.TransactionType.CREDIT));
|
||||
|
||||
this.loanTransactionHelper.addChargesForLoan(loanID, LoanTransactionHelper.getSpecifiedDueDateChargesForLoanAsJSON(
|
||||
String.valueOf(flatSpecifiedDueDate), "29 October 2011", "100"));
|
||||
@@ -1899,9 +1898,7 @@ public class ClientLoanIntegrationTest {
|
||||
System.out.println("----------Make repayment 2------------");
|
||||
this.loanTransactionHelper.makeRepayment("20 November 2011", Float.valueOf("3251.49"), loanID);
|
||||
this.journalEntryHelper.checkJournalEntryForAssetAccount(assetAccount, "20 November 2011",
|
||||
new JournalEntry(Float.valueOf("3251.49"), JournalEntry.TransactionType.DEBIT), new JournalEntry(Float.valueOf("100"),
|
||||
JournalEntry.TransactionType.CREDIT),
|
||||
new JournalEntry(Float.valueOf("181.77"), JournalEntry.TransactionType.CREDIT), new JournalEntry(Float.valueOf("2969.72"),
|
||||
new JournalEntry(Float.valueOf("3251.49"), JournalEntry.TransactionType.DEBIT), new JournalEntry(Float.valueOf("3251.49"),
|
||||
JournalEntry.TransactionType.CREDIT));
|
||||
|
||||
loanSchedule.clear();
|
||||
@@ -1937,17 +1934,13 @@ public class ClientLoanIntegrationTest {
|
||||
|
||||
// checking the journal entry as applied penalty has been collected
|
||||
this.journalEntryHelper.checkJournalEntryForAssetAccount(assetAccount, "20 October 2011", new JournalEntry(
|
||||
Float.valueOf("3301.49"), JournalEntry.TransactionType.DEBIT), new JournalEntry(Float.valueOf("100"),
|
||||
JournalEntry.TransactionType.CREDIT), new JournalEntry(Float.valueOf("150"), JournalEntry.TransactionType.CREDIT),
|
||||
new JournalEntry(Float.valueOf("240"), JournalEntry.TransactionType.CREDIT), new JournalEntry(Float.valueOf("2811.49"),
|
||||
JournalEntry.TransactionType.CREDIT));
|
||||
Float.valueOf("3301.49"), JournalEntry.TransactionType.DEBIT), new JournalEntry(Float.valueOf("3301.49"),
|
||||
JournalEntry.TransactionType.CREDIT));
|
||||
|
||||
System.out.println("----------Make repayment 3 advance------------");
|
||||
this.loanTransactionHelper.makeRepayment("20 November 2011", Float.valueOf("3301.49"), loanID);
|
||||
this.journalEntryHelper.checkJournalEntryForAssetAccount(assetAccount, "20 November 2011",
|
||||
new JournalEntry(Float.valueOf("3301.49"), JournalEntry.TransactionType.DEBIT), new JournalEntry(Float.valueOf("50.00"),
|
||||
JournalEntry.TransactionType.CREDIT),
|
||||
new JournalEntry(Float.valueOf("122.38"), JournalEntry.TransactionType.CREDIT), new JournalEntry(Float.valueOf("3129.11"),
|
||||
new JournalEntry(Float.valueOf("3301.49"), JournalEntry.TransactionType.DEBIT), new JournalEntry(Float.valueOf("3301.49"),
|
||||
JournalEntry.TransactionType.CREDIT));
|
||||
this.loanTransactionHelper.addChargesForLoan(loanID, LoanTransactionHelper.getSpecifiedDueDateChargesForLoanAsJSON(
|
||||
String.valueOf(flatPenaltySpecifiedDueDate), "10 January 2012", "100"));
|
||||
@@ -1970,10 +1963,10 @@ public class ClientLoanIntegrationTest {
|
||||
System.out.println("----------Make over payment for repayment 4 ------------");
|
||||
this.loanTransactionHelper.makeRepayment("20 January 2012", Float.valueOf("3220.60"), loanID);
|
||||
this.journalEntryHelper.checkJournalEntryForAssetAccount(assetAccount, "20 January 2012", new JournalEntry(
|
||||
Float.valueOf("3220.60"), JournalEntry.TransactionType.DEBIT), new JournalEntry(Float.valueOf("50.00"),
|
||||
JournalEntry.TransactionType.CREDIT), new JournalEntry(Float.valueOf("3089.68"), JournalEntry.TransactionType.CREDIT));
|
||||
this.journalEntryHelper.checkJournalEntryForLiabilityAccount(overpaymentAccount, "20 January 2012", new JournalEntry(80.92f,
|
||||
Float.valueOf("3220.60"), JournalEntry.TransactionType.DEBIT), new JournalEntry(Float.valueOf("3139.68"),
|
||||
JournalEntry.TransactionType.CREDIT));
|
||||
this.journalEntryHelper.checkJournalEntryForLiabilityAccount(overpaymentAccount, "20 January 2012",
|
||||
new JournalEntry(Float.valueOf("80.92"), JournalEntry.TransactionType.CREDIT));
|
||||
loanStatusHashMap = (HashMap) this.loanTransactionHelper.getLoanDetail(this.requestSpec, this.responseSpec, loanID, "status");
|
||||
LoanStatusChecker.verifyLoanAccountIsOverPaid(loanStatusHashMap);
|
||||
}
|
||||
@@ -2069,9 +2062,8 @@ public class ClientLoanIntegrationTest {
|
||||
validateCharge(percentageInstallmentFee, loanCharges, "1", "90.89", "29.11", "0.0");
|
||||
|
||||
this.journalEntryHelper.checkJournalEntryForAssetAccount(assetAccount, "20 October 2011", new JournalEntry(
|
||||
Float.valueOf("3300.60"), JournalEntry.TransactionType.DEBIT), new JournalEntry(Float.valueOf("149.11"),
|
||||
JournalEntry.TransactionType.CREDIT), new JournalEntry(Float.valueOf("240"), JournalEntry.TransactionType.CREDIT),
|
||||
new JournalEntry(Float.valueOf("2911.49"), JournalEntry.TransactionType.CREDIT));
|
||||
Float.valueOf("3300.60"), JournalEntry.TransactionType.DEBIT), new JournalEntry(Float.valueOf("3300.60"),
|
||||
JournalEntry.TransactionType.CREDIT));
|
||||
|
||||
this.loanTransactionHelper.addChargesForLoan(loanID, LoanTransactionHelper.getSpecifiedDueDateChargesForLoanAsJSON(
|
||||
String.valueOf(percentageSpecifiedDueDateCharge), "29 October 2011", "1"));
|
||||
@@ -2095,9 +2087,7 @@ public class ClientLoanIntegrationTest {
|
||||
System.out.println("----------Make repayment 2------------");
|
||||
this.loanTransactionHelper.makeRepayment("20 November 2011", Float.valueOf("3271.49"), loanID);
|
||||
this.journalEntryHelper.checkJournalEntryForAssetAccount(assetAccount, "20 November 2011",
|
||||
new JournalEntry(Float.valueOf("3271.49"), JournalEntry.TransactionType.DEBIT), new JournalEntry(Float.valueOf("120"),
|
||||
JournalEntry.TransactionType.CREDIT),
|
||||
new JournalEntry(Float.valueOf("181.77"), JournalEntry.TransactionType.CREDIT), new JournalEntry(Float.valueOf("2969.72"),
|
||||
new JournalEntry(Float.valueOf("3271.49"), JournalEntry.TransactionType.DEBIT), new JournalEntry(Float.valueOf("3271.49"),
|
||||
JournalEntry.TransactionType.CREDIT));
|
||||
|
||||
loanSchedule.clear();
|
||||
@@ -2133,17 +2123,13 @@ public class ClientLoanIntegrationTest {
|
||||
|
||||
// checking the journal entry as applied penalty has been collected
|
||||
this.journalEntryHelper.checkJournalEntryForAssetAccount(assetAccount, "20 October 2011", new JournalEntry(
|
||||
Float.valueOf("3300.60"), JournalEntry.TransactionType.DEBIT), new JournalEntry(Float.valueOf("120"),
|
||||
JournalEntry.TransactionType.CREDIT), new JournalEntry(Float.valueOf("149.11"), JournalEntry.TransactionType.CREDIT),
|
||||
new JournalEntry(Float.valueOf("240"), JournalEntry.TransactionType.CREDIT), new JournalEntry(Float.valueOf("2791.49"),
|
||||
JournalEntry.TransactionType.CREDIT));
|
||||
Float.valueOf("3300.60"), JournalEntry.TransactionType.DEBIT), new JournalEntry(Float.valueOf("3300.60"),
|
||||
JournalEntry.TransactionType.CREDIT));
|
||||
|
||||
System.out.println("----------Make repayment 3 advance------------");
|
||||
this.loanTransactionHelper.makeRepayment("20 November 2011", Float.valueOf("3301.78"), loanID);
|
||||
this.journalEntryHelper.checkJournalEntryForAssetAccount(assetAccount, "20 November 2011",
|
||||
new JournalEntry(Float.valueOf("3301.78"), JournalEntry.TransactionType.DEBIT), new JournalEntry(Float.valueOf("30.29"),
|
||||
JournalEntry.TransactionType.CREDIT),
|
||||
new JournalEntry(Float.valueOf("122.38"), JournalEntry.TransactionType.CREDIT), new JournalEntry(Float.valueOf("3149.11"),
|
||||
new JournalEntry(Float.valueOf("3301.78"), JournalEntry.TransactionType.DEBIT), new JournalEntry(Float.valueOf("3301.78"),
|
||||
JournalEntry.TransactionType.CREDIT));
|
||||
this.loanTransactionHelper.addChargesForLoan(loanID, LoanTransactionHelper.getSpecifiedDueDateChargesForLoanAsJSON(
|
||||
String.valueOf(percentagePenaltySpecifiedDueDate), "10 January 2012", "1"));
|
||||
@@ -2166,10 +2152,10 @@ public class ClientLoanIntegrationTest {
|
||||
System.out.println("----------Make over payment for repayment 4 ------------");
|
||||
this.loanTransactionHelper.makeRepayment("20 January 2012", Float.valueOf("3220.58"), loanID);
|
||||
this.journalEntryHelper.checkJournalEntryForAssetAccount(assetAccount, "20 January 2012", new JournalEntry(
|
||||
Float.valueOf("3220.58"), JournalEntry.TransactionType.DEBIT), new JournalEntry(Float.valueOf("30.90"),
|
||||
JournalEntry.TransactionType.CREDIT), new JournalEntry(Float.valueOf("3089.68"), JournalEntry.TransactionType.CREDIT));
|
||||
this.journalEntryHelper.checkJournalEntryForLiabilityAccount(overpaymentAccount, "20 January 2012", new JournalEntry(100f,
|
||||
Float.valueOf("3220.58"), JournalEntry.TransactionType.DEBIT), new JournalEntry(Float.valueOf("3120.58"),
|
||||
JournalEntry.TransactionType.CREDIT));
|
||||
this.journalEntryHelper.checkJournalEntryForLiabilityAccount(overpaymentAccount, "20 January 2012",
|
||||
new JournalEntry(Float.valueOf("100.00"), JournalEntry.TransactionType.CREDIT));
|
||||
loanStatusHashMap = (HashMap) this.loanTransactionHelper.getLoanDetail(this.requestSpec, this.responseSpec, loanID, "status");
|
||||
LoanStatusChecker.verifyLoanAccountIsOverPaid(loanStatusHashMap);
|
||||
}
|
||||
@@ -2274,9 +2260,8 @@ public class ClientLoanIntegrationTest {
|
||||
validateCharge(amountPlusInterestPercentageInstallmentFee, loanCharges, "1", "94.53", "31.51", "0.0");
|
||||
|
||||
this.journalEntryHelper.checkJournalEntryForAssetAccount(assetAccount, "20 October 2011", new JournalEntry(
|
||||
Float.valueOf("3309.06"), JournalEntry.TransactionType.DEBIT), new JournalEntry(Float.valueOf("157.57"),
|
||||
JournalEntry.TransactionType.CREDIT), new JournalEntry(Float.valueOf("240"), JournalEntry.TransactionType.CREDIT),
|
||||
new JournalEntry(Float.valueOf("2911.49"), JournalEntry.TransactionType.CREDIT));
|
||||
Float.valueOf("3309.06"), JournalEntry.TransactionType.DEBIT), new JournalEntry(Float.valueOf("3309.06"),
|
||||
JournalEntry.TransactionType.CREDIT));
|
||||
|
||||
this.loanTransactionHelper.addChargesForLoan(
|
||||
loanID,
|
||||
@@ -2303,9 +2288,7 @@ public class ClientLoanIntegrationTest {
|
||||
System.out.println("----------Make repayment 2------------");
|
||||
this.loanTransactionHelper.makeRepayment("20 November 2011", Float.valueOf("3277.55"), loanID);
|
||||
this.journalEntryHelper.checkJournalEntryForAssetAccount(assetAccount, "20 November 2011",
|
||||
new JournalEntry(Float.valueOf("3277.55"), JournalEntry.TransactionType.DEBIT), new JournalEntry(Float.valueOf("126.06"),
|
||||
JournalEntry.TransactionType.CREDIT),
|
||||
new JournalEntry(Float.valueOf("181.77"), JournalEntry.TransactionType.CREDIT), new JournalEntry(Float.valueOf("2969.72"),
|
||||
new JournalEntry(Float.valueOf("3277.55"), JournalEntry.TransactionType.DEBIT), new JournalEntry(Float.valueOf("3277.55"),
|
||||
JournalEntry.TransactionType.CREDIT));
|
||||
|
||||
loanSchedule.clear();
|
||||
@@ -2343,17 +2326,13 @@ public class ClientLoanIntegrationTest {
|
||||
|
||||
// checking the journal entry as applied penalty has been collected
|
||||
this.journalEntryHelper.checkJournalEntryForAssetAccount(assetAccount, "20 October 2011", new JournalEntry(
|
||||
Float.valueOf("3309.06"), JournalEntry.TransactionType.DEBIT), new JournalEntry(Float.valueOf("120"),
|
||||
JournalEntry.TransactionType.CREDIT), new JournalEntry(Float.valueOf("157.57"), JournalEntry.TransactionType.CREDIT),
|
||||
new JournalEntry(Float.valueOf("240"), JournalEntry.TransactionType.CREDIT), new JournalEntry(Float.valueOf("2791.49"),
|
||||
JournalEntry.TransactionType.CREDIT));
|
||||
Float.valueOf("3309.06"), JournalEntry.TransactionType.DEBIT), new JournalEntry(Float.valueOf("3309.06"),
|
||||
JournalEntry.TransactionType.CREDIT));
|
||||
|
||||
System.out.println("----------Make repayment 3 advance------------");
|
||||
this.loanTransactionHelper.makeRepayment("20 November 2011", Float.valueOf("3303"), loanID);
|
||||
this.journalEntryHelper.checkJournalEntryForAssetAccount(assetAccount, "20 November 2011", new JournalEntry(Float.valueOf("3303"),
|
||||
JournalEntry.TransactionType.DEBIT), new JournalEntry(Float.valueOf("31.51"), JournalEntry.TransactionType.CREDIT),
|
||||
new JournalEntry(Float.valueOf("122.38"), JournalEntry.TransactionType.CREDIT), new JournalEntry(Float.valueOf("3149.11"),
|
||||
JournalEntry.TransactionType.CREDIT));
|
||||
JournalEntry.TransactionType.DEBIT), new JournalEntry(Float.valueOf("3303"), JournalEntry.TransactionType.CREDIT));
|
||||
this.loanTransactionHelper.addChargesForLoan(
|
||||
loanID,
|
||||
LoanTransactionHelper.getSpecifiedDueDateChargesForLoanAsJSON(
|
||||
@@ -2377,9 +2356,9 @@ public class ClientLoanIntegrationTest {
|
||||
System.out.println("----------Make over payment for repayment 4 ------------");
|
||||
this.loanTransactionHelper.makeRepayment("20 January 2012", Float.valueOf("3221.61"), loanID);
|
||||
this.journalEntryHelper.checkJournalEntryForAssetAccount(assetAccount, "20 January 2012", new JournalEntry(
|
||||
Float.valueOf("3221.61"), JournalEntry.TransactionType.DEBIT), new JournalEntry(Float.valueOf("31.51"),
|
||||
JournalEntry.TransactionType.CREDIT), new JournalEntry(Float.valueOf("3089.68"), JournalEntry.TransactionType.CREDIT));
|
||||
this.journalEntryHelper.checkJournalEntryForLiabilityAccount(overpaymentAccount, "20 January 2012", new JournalEntry(100.42f,
|
||||
Float.valueOf("3221.61"), JournalEntry.TransactionType.DEBIT), new JournalEntry(Float.valueOf("3121.19"),
|
||||
JournalEntry.TransactionType.CREDIT));
|
||||
this.journalEntryHelper.checkJournalEntryForLiabilityAccount(overpaymentAccount, "20 January 2012", new JournalEntry(Float.valueOf("100.42"),
|
||||
JournalEntry.TransactionType.CREDIT));
|
||||
loanStatusHashMap = (HashMap) this.loanTransactionHelper.getLoanDetail(this.requestSpec, this.responseSpec, loanID, "status");
|
||||
LoanStatusChecker.verifyLoanAccountIsOverPaid(loanStatusHashMap);
|
||||
@@ -2468,9 +2447,8 @@ public class ClientLoanIntegrationTest {
|
||||
validateCharge(flatInstallmentFee, loanCharges, "50", "150.00", "50.0", "0.0");
|
||||
|
||||
this.journalEntryHelper.checkJournalEntryForAssetAccount(assetAccount, "20 October 2011", new JournalEntry(
|
||||
Float.valueOf("3301.49"), JournalEntry.TransactionType.DEBIT), new JournalEntry(Float.valueOf("150.00"),
|
||||
JournalEntry.TransactionType.CREDIT), new JournalEntry(Float.valueOf("240"), JournalEntry.TransactionType.CREDIT),
|
||||
new JournalEntry(Float.valueOf("2911.49"), JournalEntry.TransactionType.CREDIT));
|
||||
Float.valueOf("3301.49"), JournalEntry.TransactionType.DEBIT), new JournalEntry(Float.valueOf("3301.49"),
|
||||
JournalEntry.TransactionType.CREDIT));
|
||||
|
||||
this.loanTransactionHelper.addChargesForLoan(loanID, LoanTransactionHelper.getSpecifiedDueDateChargesForLoanAsJSON(
|
||||
String.valueOf(flatSpecifiedDueDate), "29 October 2011", "100"));
|
||||
@@ -2509,9 +2487,7 @@ public class ClientLoanIntegrationTest {
|
||||
System.out.println("----------Make repayment 2------------");
|
||||
this.loanTransactionHelper.makeRepayment("20 November 2011", Float.valueOf("3251.49"), loanID);
|
||||
this.journalEntryHelper.checkJournalEntryForAssetAccount(assetAccount, "20 November 2011",
|
||||
new JournalEntry(Float.valueOf("3251.49"), JournalEntry.TransactionType.DEBIT), new JournalEntry(Float.valueOf("100.00"),
|
||||
JournalEntry.TransactionType.CREDIT),
|
||||
new JournalEntry(Float.valueOf("181.77"), JournalEntry.TransactionType.CREDIT), new JournalEntry(Float.valueOf("2969.72"),
|
||||
new JournalEntry(Float.valueOf("3251.49"), JournalEntry.TransactionType.DEBIT), new JournalEntry(Float.valueOf("3251.49"),
|
||||
JournalEntry.TransactionType.CREDIT));
|
||||
|
||||
loanSchedule.clear();
|
||||
@@ -2547,17 +2523,13 @@ public class ClientLoanIntegrationTest {
|
||||
|
||||
// checking the journal entry as applied penalty has been collected
|
||||
this.journalEntryHelper.checkJournalEntryForAssetAccount(assetAccount, "20 October 2011", new JournalEntry(
|
||||
Float.valueOf("3301.49"), JournalEntry.TransactionType.DEBIT), new JournalEntry(Float.valueOf("100"),
|
||||
JournalEntry.TransactionType.CREDIT), new JournalEntry(Float.valueOf("150"), JournalEntry.TransactionType.CREDIT),
|
||||
new JournalEntry(Float.valueOf("240"), JournalEntry.TransactionType.CREDIT), new JournalEntry(Float.valueOf("2811.49"),
|
||||
JournalEntry.TransactionType.CREDIT));
|
||||
Float.valueOf("3301.49"), JournalEntry.TransactionType.DEBIT), new JournalEntry(Float.valueOf("3301.49"),
|
||||
JournalEntry.TransactionType.CREDIT));
|
||||
|
||||
System.out.println("----------Make repayment 3 advance------------");
|
||||
this.loanTransactionHelper.makeRepayment("20 November 2011", Float.valueOf("3301.49"), loanID);
|
||||
this.journalEntryHelper.checkJournalEntryForAssetAccount(assetAccount, "20 November 2011",
|
||||
new JournalEntry(Float.valueOf("3301.49"), JournalEntry.TransactionType.DEBIT), new JournalEntry(Float.valueOf("50"),
|
||||
JournalEntry.TransactionType.CREDIT),
|
||||
new JournalEntry(Float.valueOf("122.38"), JournalEntry.TransactionType.CREDIT), new JournalEntry(Float.valueOf("3129.11"),
|
||||
new JournalEntry(Float.valueOf("3301.49"), JournalEntry.TransactionType.DEBIT), new JournalEntry(Float.valueOf("3301.49"),
|
||||
JournalEntry.TransactionType.CREDIT));
|
||||
|
||||
this.loanTransactionHelper.addChargesForLoan(loanID, LoanTransactionHelper.getSpecifiedDueDateChargesForLoanAsJSON(
|
||||
@@ -2581,8 +2553,8 @@ public class ClientLoanIntegrationTest {
|
||||
System.out.println("----------Make repayment 4 ------------");
|
||||
this.loanTransactionHelper.makeRepayment("20 January 2012", Float.valueOf("3139.68"), loanID);
|
||||
this.journalEntryHelper.checkJournalEntryForAssetAccount(assetAccount, "20 January 2012", new JournalEntry(
|
||||
Float.valueOf("3139.68"), JournalEntry.TransactionType.DEBIT), new JournalEntry(Float.valueOf("50.00"),
|
||||
JournalEntry.TransactionType.CREDIT), new JournalEntry(Float.valueOf("3089.68"), JournalEntry.TransactionType.CREDIT));
|
||||
Float.valueOf("3139.68"), JournalEntry.TransactionType.DEBIT), new JournalEntry(Float.valueOf("3139.68"),
|
||||
JournalEntry.TransactionType.CREDIT));
|
||||
loanStatusHashMap = (HashMap) this.loanTransactionHelper.getLoanDetail(this.requestSpec, this.responseSpec, loanID, "status");
|
||||
LoanStatusChecker.verifyLoanAccountIsClosed(loanStatusHashMap);
|
||||
}
|
||||
@@ -2673,9 +2645,8 @@ public class ClientLoanIntegrationTest {
|
||||
validateCharge(percentageInstallmentFee, loanCharges, "1", "90.89", "29.11", "0.0");
|
||||
|
||||
this.journalEntryHelper.checkJournalEntryForAssetAccount(assetAccount, "20 October 2011", new JournalEntry(
|
||||
Float.valueOf("3300.60"), JournalEntry.TransactionType.DEBIT), new JournalEntry(Float.valueOf("149.11"),
|
||||
JournalEntry.TransactionType.CREDIT), new JournalEntry(Float.valueOf("240"), JournalEntry.TransactionType.CREDIT),
|
||||
new JournalEntry(Float.valueOf("2911.49"), JournalEntry.TransactionType.CREDIT));
|
||||
Float.valueOf("3300.60"), JournalEntry.TransactionType.DEBIT), new JournalEntry(Float.valueOf("3300.60"),
|
||||
JournalEntry.TransactionType.CREDIT));
|
||||
|
||||
this.loanTransactionHelper.addChargesForLoan(loanID, LoanTransactionHelper.getSpecifiedDueDateChargesForLoanAsJSON(
|
||||
String.valueOf(percentageSpecifiedDueDateCharge), "29 October 2011", "1"));
|
||||
@@ -2715,9 +2686,7 @@ public class ClientLoanIntegrationTest {
|
||||
System.out.println("----------Make repayment 2------------");
|
||||
this.loanTransactionHelper.makeRepayment("20 November 2011", Float.valueOf("3271.49"), loanID);
|
||||
this.journalEntryHelper.checkJournalEntryForAssetAccount(assetAccount, "20 November 2011",
|
||||
new JournalEntry(Float.valueOf("3271.49"), JournalEntry.TransactionType.DEBIT), new JournalEntry(Float.valueOf("120"),
|
||||
JournalEntry.TransactionType.CREDIT),
|
||||
new JournalEntry(Float.valueOf("181.77"), JournalEntry.TransactionType.CREDIT), new JournalEntry(Float.valueOf("2969.72"),
|
||||
new JournalEntry(Float.valueOf("3271.49"), JournalEntry.TransactionType.DEBIT), new JournalEntry(Float.valueOf("3271.49"),
|
||||
JournalEntry.TransactionType.CREDIT));
|
||||
|
||||
loanSchedule.clear();
|
||||
@@ -2753,17 +2722,13 @@ public class ClientLoanIntegrationTest {
|
||||
|
||||
// checking the journal entry as applied penalty has been collected
|
||||
this.journalEntryHelper.checkJournalEntryForAssetAccount(assetAccount, "20 October 2011", new JournalEntry(
|
||||
Float.valueOf("3300.60"), JournalEntry.TransactionType.DEBIT), new JournalEntry(Float.valueOf("120"),
|
||||
JournalEntry.TransactionType.CREDIT), new JournalEntry(Float.valueOf("149.11"), JournalEntry.TransactionType.CREDIT),
|
||||
new JournalEntry(Float.valueOf("240"), JournalEntry.TransactionType.CREDIT), new JournalEntry(Float.valueOf("2791.49"),
|
||||
JournalEntry.TransactionType.CREDIT));
|
||||
Float.valueOf("3300.60"), JournalEntry.TransactionType.DEBIT), new JournalEntry(Float.valueOf("3300.60"),
|
||||
JournalEntry.TransactionType.CREDIT));
|
||||
|
||||
System.out.println("----------Make repayment 3 advance------------");
|
||||
this.loanTransactionHelper.makeRepayment("20 November 2011", Float.valueOf("3301.78"), loanID);
|
||||
this.journalEntryHelper.checkJournalEntryForAssetAccount(assetAccount, "20 November 2011",
|
||||
new JournalEntry(Float.valueOf("3301.78"), JournalEntry.TransactionType.DEBIT), new JournalEntry(Float.valueOf("30.29"),
|
||||
JournalEntry.TransactionType.CREDIT),
|
||||
new JournalEntry(Float.valueOf("122.38"), JournalEntry.TransactionType.CREDIT), new JournalEntry(Float.valueOf("3149.11"),
|
||||
new JournalEntry(Float.valueOf("3301.78"), JournalEntry.TransactionType.DEBIT), new JournalEntry(Float.valueOf("3301.78"),
|
||||
JournalEntry.TransactionType.CREDIT));
|
||||
|
||||
this.loanTransactionHelper.addChargesForLoan(loanID, LoanTransactionHelper.getSpecifiedDueDateChargesForLoanAsJSON(
|
||||
@@ -2787,8 +2752,8 @@ public class ClientLoanIntegrationTest {
|
||||
System.out.println("----------Make repayment 4 ------------");
|
||||
this.loanTransactionHelper.makeRepayment("20 January 2012", Float.valueOf("3120.58"), loanID);
|
||||
this.journalEntryHelper.checkJournalEntryForAssetAccount(assetAccount, "20 January 2012", new JournalEntry(
|
||||
Float.valueOf("3120.58"), JournalEntry.TransactionType.DEBIT), new JournalEntry(Float.valueOf("30.90"),
|
||||
JournalEntry.TransactionType.CREDIT), new JournalEntry(Float.valueOf("3089.68"), JournalEntry.TransactionType.CREDIT));
|
||||
Float.valueOf("3120.58"), JournalEntry.TransactionType.DEBIT), new JournalEntry(Float.valueOf("3120.58"),
|
||||
JournalEntry.TransactionType.CREDIT));
|
||||
loanStatusHashMap = (HashMap) this.loanTransactionHelper.getLoanDetail(this.requestSpec, this.responseSpec, loanID, "status");
|
||||
LoanStatusChecker.verifyLoanAccountIsClosed(loanStatusHashMap);
|
||||
}
|
||||
@@ -2880,9 +2845,8 @@ public class ClientLoanIntegrationTest {
|
||||
validateCharge(amountPlusInterestPercentageInstallmentFee, loanCharges, "1", "94.53", "31.51", "0.0");
|
||||
|
||||
this.journalEntryHelper.checkJournalEntryForAssetAccount(assetAccount, "20 October 2011", new JournalEntry(
|
||||
Float.valueOf("3309.06"), JournalEntry.TransactionType.DEBIT), new JournalEntry(Float.valueOf("157.57"),
|
||||
JournalEntry.TransactionType.CREDIT), new JournalEntry(Float.valueOf("240"), JournalEntry.TransactionType.CREDIT),
|
||||
new JournalEntry(Float.valueOf("2911.49"), JournalEntry.TransactionType.CREDIT));
|
||||
Float.valueOf("3309.06"), JournalEntry.TransactionType.DEBIT), new JournalEntry(Float.valueOf("3309.06"),
|
||||
JournalEntry.TransactionType.CREDIT));
|
||||
|
||||
this.loanTransactionHelper.addChargesForLoan(
|
||||
loanID,
|
||||
@@ -2925,9 +2889,7 @@ public class ClientLoanIntegrationTest {
|
||||
System.out.println("----------Make repayment 2------------");
|
||||
this.loanTransactionHelper.makeRepayment("20 November 2011", Float.valueOf("3277.55"), loanID);
|
||||
this.journalEntryHelper.checkJournalEntryForAssetAccount(assetAccount, "20 November 2011",
|
||||
new JournalEntry(Float.valueOf("3277.55"), JournalEntry.TransactionType.DEBIT), new JournalEntry(Float.valueOf("126.06"),
|
||||
JournalEntry.TransactionType.CREDIT),
|
||||
new JournalEntry(Float.valueOf("181.77"), JournalEntry.TransactionType.CREDIT), new JournalEntry(Float.valueOf("2969.72"),
|
||||
new JournalEntry(Float.valueOf("3277.55"), JournalEntry.TransactionType.DEBIT), new JournalEntry(Float.valueOf("3277.55"),
|
||||
JournalEntry.TransactionType.CREDIT));
|
||||
|
||||
loanSchedule.clear();
|
||||
@@ -2965,17 +2927,13 @@ public class ClientLoanIntegrationTest {
|
||||
|
||||
// checking the journal entry as applied penalty has been collected
|
||||
this.journalEntryHelper.checkJournalEntryForAssetAccount(assetAccount, "20 October 2011", new JournalEntry(
|
||||
Float.valueOf("3309.06"), JournalEntry.TransactionType.DEBIT), new JournalEntry(Float.valueOf("120"),
|
||||
JournalEntry.TransactionType.CREDIT), new JournalEntry(Float.valueOf("157.57"), JournalEntry.TransactionType.CREDIT),
|
||||
new JournalEntry(Float.valueOf("240"), JournalEntry.TransactionType.CREDIT), new JournalEntry(Float.valueOf("2791.49"),
|
||||
JournalEntry.TransactionType.CREDIT));
|
||||
Float.valueOf("3309.06"), JournalEntry.TransactionType.DEBIT), new JournalEntry(Float.valueOf("3309.06"),
|
||||
JournalEntry.TransactionType.CREDIT));
|
||||
|
||||
System.out.println("----------Make repayment 3 advance------------");
|
||||
this.loanTransactionHelper.makeRepayment("20 November 2011", Float.valueOf("3303"), loanID);
|
||||
this.journalEntryHelper.checkJournalEntryForAssetAccount(assetAccount, "20 November 2011", new JournalEntry(Float.valueOf("3303"),
|
||||
JournalEntry.TransactionType.DEBIT), new JournalEntry(Float.valueOf("31.51"), JournalEntry.TransactionType.CREDIT),
|
||||
new JournalEntry(Float.valueOf("122.38"), JournalEntry.TransactionType.CREDIT), new JournalEntry(Float.valueOf("3149.11"),
|
||||
JournalEntry.TransactionType.CREDIT));
|
||||
JournalEntry.TransactionType.DEBIT), new JournalEntry(Float.valueOf("3303"), JournalEntry.TransactionType.CREDIT));
|
||||
|
||||
this.loanTransactionHelper.addChargesForLoan(
|
||||
loanID,
|
||||
@@ -3000,8 +2958,8 @@ public class ClientLoanIntegrationTest {
|
||||
System.out.println("----------Make repayment 4 ------------");
|
||||
this.loanTransactionHelper.makeRepayment("20 January 2012", Float.valueOf("3121.19"), loanID);
|
||||
this.journalEntryHelper.checkJournalEntryForAssetAccount(assetAccount, "20 January 2012", new JournalEntry(
|
||||
Float.valueOf("3121.19"), JournalEntry.TransactionType.DEBIT), new JournalEntry(Float.valueOf("31.51"),
|
||||
JournalEntry.TransactionType.CREDIT), new JournalEntry(Float.valueOf("3089.68"), JournalEntry.TransactionType.CREDIT));
|
||||
Float.valueOf("3121.19"), JournalEntry.TransactionType.DEBIT), new JournalEntry(Float.valueOf("3121.19"),
|
||||
JournalEntry.TransactionType.CREDIT));
|
||||
loanStatusHashMap = (HashMap) this.loanTransactionHelper.getLoanDetail(this.requestSpec, this.responseSpec, loanID, "status");
|
||||
LoanStatusChecker.verifyLoanAccountIsClosed(loanStatusHashMap);
|
||||
}
|
||||
@@ -3198,7 +3156,7 @@ public class ClientLoanIntegrationTest {
|
||||
LoanProductTestBuilder.RECALCULATION_COMPOUNDING_METHOD_NONE,
|
||||
LoanProductTestBuilder.RECALCULATION_STRATEGY_REDUCE_EMI_AMOUN,
|
||||
LoanProductTestBuilder.RECALCULATION_FREQUENCY_TYPE_SAME_AS_REPAYMENT_PERIOD, "0", null,
|
||||
LoanProductTestBuilder.INTEREST_APPLICABLE_STRATEGY_ON_PRE_CLOSE_DATE, null);
|
||||
LoanProductTestBuilder.INTEREST_APPLICABLE_STRATEGY_ON_PRE_CLOSE_DATE, null, null, null);
|
||||
|
||||
final Integer loanID = applyForLoanApplicationForInterestRecalculation(clientID, loanProductID, LOAN_DISBURSEMENT_DATE, null,
|
||||
LoanApplicationTestBuilder.DEFAULT_STRATEGY, new ArrayList<HashMap>(0));
|
||||
@@ -3305,7 +3263,8 @@ public class ClientLoanIntegrationTest {
|
||||
final Integer loanProductID = createLoanProductWithInterestRecalculation(LoanProductTestBuilder.DEFAULT_STRATEGY,
|
||||
LoanProductTestBuilder.RECALCULATION_COMPOUNDING_METHOD_NONE,
|
||||
LoanProductTestBuilder.RECALCULATION_STRATEGY_REDUCE_EMI_AMOUN,
|
||||
LoanProductTestBuilder.RECALCULATION_FREQUENCY_TYPE_SAME_AS_REPAYMENT_PERIOD, "0", null, preCloseInterestStrategy, null);
|
||||
LoanProductTestBuilder.RECALCULATION_FREQUENCY_TYPE_SAME_AS_REPAYMENT_PERIOD, "0", null, preCloseInterestStrategy, null,
|
||||
null, null);
|
||||
|
||||
final Integer loanID = applyForLoanApplicationForInterestRecalculation(clientID, loanProductID, LOAN_DISBURSEMENT_DATE, null,
|
||||
LoanApplicationTestBuilder.DEFAULT_STRATEGY, new ArrayList<HashMap>(0));
|
||||
@@ -3384,7 +3343,7 @@ public class ClientLoanIntegrationTest {
|
||||
LoanProductTestBuilder.RECALCULATION_COMPOUNDING_METHOD_NONE,
|
||||
LoanProductTestBuilder.RECALCULATION_STRATEGY_REDUCE_EMI_AMOUN,
|
||||
LoanProductTestBuilder.RECALCULATION_FREQUENCY_TYPE_SAME_AS_REPAYMENT_PERIOD, "0", null,
|
||||
LoanProductTestBuilder.INTEREST_APPLICABLE_STRATEGY_ON_PRE_CLOSE_DATE, null);
|
||||
LoanProductTestBuilder.INTEREST_APPLICABLE_STRATEGY_ON_PRE_CLOSE_DATE, null, null, null);
|
||||
|
||||
List<HashMap> charges = new ArrayList<>();
|
||||
Integer installmentCharge = ChargesHelper.createCharges(requestSpec, responseSpec,
|
||||
@@ -3473,6 +3432,8 @@ public class ClientLoanIntegrationTest {
|
||||
Calendar todaysDate = Calendar.getInstance(Utils.getTimeZoneOfTenant());
|
||||
todaysDate.add(Calendar.DAY_OF_MONTH, -14);
|
||||
final String LOAN_DISBURSEMENT_DATE = dateFormat.format(todaysDate.getTime());
|
||||
Integer dayOfMonth = getDayOfMonth(todaysDate);
|
||||
Integer dayOfWeek = getDayOfWeek(todaysDate);
|
||||
|
||||
final Integer clientID = ClientHelper.createClient(this.requestSpec, this.responseSpec);
|
||||
ClientHelper.verifyClientCreatedOnServer(this.requestSpec, this.responseSpec, clientID);
|
||||
@@ -3481,10 +3442,10 @@ public class ClientLoanIntegrationTest {
|
||||
LoanProductTestBuilder.RECALCULATION_STRATEGY_REDUCE_NUMBER_OF_INSTALLMENTS,
|
||||
LoanProductTestBuilder.RECALCULATION_FREQUENCY_TYPE_DAILY, "1", LOAN_DISBURSEMENT_DATE,
|
||||
LoanProductTestBuilder.RECALCULATION_FREQUENCY_TYPE_WEEKLY, "1", LOAN_DISBURSEMENT_DATE,
|
||||
LoanProductTestBuilder.INTEREST_APPLICABLE_STRATEGY_ON_PRE_CLOSE_DATE, null);
|
||||
LoanProductTestBuilder.INTEREST_APPLICABLE_STRATEGY_ON_PRE_CLOSE_DATE, null, null, dayOfWeek, null, dayOfWeek);
|
||||
|
||||
final Integer loanID = applyForLoanApplicationForInterestRecalculation(clientID, loanProductID, LOAN_DISBURSEMENT_DATE,
|
||||
LOAN_DISBURSEMENT_DATE, LOAN_DISBURSEMENT_DATE, LoanApplicationTestBuilder.RBI_INDIA_STRATEGY, new ArrayList<HashMap>(0));
|
||||
LoanApplicationTestBuilder.RBI_INDIA_STRATEGY, new ArrayList<HashMap>(0));
|
||||
|
||||
Assert.assertNotNull(loanID);
|
||||
HashMap loanStatusHashMap = LoanStatusChecker.getStatusOfLoan(this.requestSpec, this.responseSpec, loanID);
|
||||
@@ -3560,8 +3521,8 @@ public class ClientLoanIntegrationTest {
|
||||
paymentday.put("penaltyChargesDue", "0");
|
||||
addRepaymentValues(expectedvalues, todaysDate, -1, false, "2482.76", "46.15", "0.0", "0.0");
|
||||
expectedvalues.add(paymentday);
|
||||
addRepaymentValues(expectedvalues, todaysDate, 1, false, "2517.28", "11.63", "0.0", "0.0");
|
||||
addRepaymentValues(expectedvalues, todaysDate, 1, false, "1009.87", "4.66", "0.0", "0.0");
|
||||
addRepaymentValues(expectedvalues, todaysDate, 1, false, "2517.31", "11.6", "0.0", "0.0");
|
||||
addRepaymentValues(expectedvalues, todaysDate, 1, false, "1009.84", "4.66", "0.0", "0.0");
|
||||
verifyLoanRepaymentSchedule(loanSchedule, expectedvalues);
|
||||
|
||||
HashMap prepayDetail = this.loanTransactionHelper.getPrepayAmount(this.requestSpec, this.responseSpec, loanID);
|
||||
@@ -3583,8 +3544,12 @@ public class ClientLoanIntegrationTest {
|
||||
|
||||
Calendar todaysDate = Calendar.getInstance(Utils.getTimeZoneOfTenant());
|
||||
todaysDate.add(Calendar.DAY_OF_MONTH, -14);
|
||||
Integer compoundingDayOfMonth = getDayOfMonth(todaysDate);
|
||||
Integer compoundingDayOfWeek = getDayOfWeek(todaysDate);
|
||||
final String LOAN_DISBURSEMENT_DATE = dateFormat.format(todaysDate.getTime());
|
||||
todaysDate.add(Calendar.DAY_OF_MONTH, -2);
|
||||
Integer restDayOfMonth = getDayOfMonth(todaysDate);
|
||||
Integer restDayOfWeek = getDayOfWeek(todaysDate);
|
||||
final String REST_START_DATE = dateFormat.format(todaysDate.getTime());
|
||||
|
||||
todaysDate = Calendar.getInstance(Utils.getTimeZoneOfTenant());
|
||||
@@ -3609,10 +3574,11 @@ public class ClientLoanIntegrationTest {
|
||||
LoanProductTestBuilder.RECALCULATION_STRATEGY_RESCHEDULE_NEXT_REPAYMENTS,
|
||||
LoanProductTestBuilder.RECALCULATION_FREQUENCY_TYPE_WEEKLY, "1", REST_START_DATE,
|
||||
LoanProductTestBuilder.RECALCULATION_FREQUENCY_TYPE_WEEKLY, "1", LOAN_DISBURSEMENT_DATE,
|
||||
LoanProductTestBuilder.INTEREST_APPLICABLE_STRATEGY_ON_PRE_CLOSE_DATE, null);
|
||||
LoanProductTestBuilder.INTEREST_APPLICABLE_STRATEGY_ON_PRE_CLOSE_DATE, null, compoundingDayOfMonth, compoundingDayOfWeek,
|
||||
restDayOfMonth, restDayOfWeek);
|
||||
|
||||
final Integer loanID = applyForLoanApplicationForInterestRecalculation(clientID, loanProductID, LOAN_DISBURSEMENT_DATE,
|
||||
REST_START_DATE, LOAN_DISBURSEMENT_DATE, LoanApplicationTestBuilder.DEFAULT_STRATEGY, charges);
|
||||
LOAN_DISBURSEMENT_DATE, LoanApplicationTestBuilder.DEFAULT_STRATEGY, charges);
|
||||
|
||||
Assert.assertNotNull(loanID);
|
||||
HashMap loanStatusHashMap = LoanStatusChecker.getStatusOfLoan(this.requestSpec, this.responseSpec, loanID);
|
||||
@@ -3622,9 +3588,9 @@ public class ClientLoanIntegrationTest {
|
||||
List<Map<String, Object>> expectedvalues = new ArrayList<>();
|
||||
todaysDate = Calendar.getInstance(Utils.getTimeZoneOfTenant());
|
||||
addRepaymentValues(expectedvalues, todaysDate, -1, false, "2482.76", "46.15", "100.0", "0.0");
|
||||
addRepaymentValues(expectedvalues, todaysDate, 1, false, "2486.03", "42.88", "0.0", "0.0");
|
||||
addRepaymentValues(expectedvalues, todaysDate, 1, false, "2497.5", "31.41", "200", "0.0");
|
||||
addRepaymentValues(expectedvalues, todaysDate, 1, false, "2533.71", "19.93", "0.0", "0.0");
|
||||
addRepaymentValues(expectedvalues, todaysDate, 1, false, "2494.22", "34.69", "0.0", "0.0");
|
||||
addRepaymentValues(expectedvalues, todaysDate, 1, false, "2505.73", "23.18", "200", "0.0");
|
||||
addRepaymentValues(expectedvalues, todaysDate, 1, false, "2517.29", "11.62", "0.0", "0.0");
|
||||
verifyLoanRepaymentSchedule(loanSchedule, expectedvalues);
|
||||
|
||||
System.out.println("-----------------------------------APPROVE LOAN-----------------------------------------");
|
||||
@@ -3641,8 +3607,8 @@ public class ClientLoanIntegrationTest {
|
||||
todaysDate = Calendar.getInstance(Utils.getTimeZoneOfTenant());
|
||||
addRepaymentValues(expectedvalues, todaysDate, -1, false, "2482.76", "46.15", "100.0", "0.0");
|
||||
addRepaymentValues(expectedvalues, todaysDate, 1, false, "2482.08", "46.83", "0.0", "0.0");
|
||||
addRepaymentValues(expectedvalues, todaysDate, 1, false, "2488.82", "40.09", "200", "0.0");
|
||||
addRepaymentValues(expectedvalues, todaysDate, 1, false, "2546.34", "19.96", "0.0", "0.0");
|
||||
addRepaymentValues(expectedvalues, todaysDate, 1, false, "2505.67", "23.24", "200", "0.0");
|
||||
addRepaymentValues(expectedvalues, todaysDate, 1, false, "2529.49", "11.67", "0.0", "0.0");
|
||||
|
||||
verifyLoanRepaymentSchedule(loanSchedule, expectedvalues);
|
||||
|
||||
@@ -3656,9 +3622,9 @@ public class ClientLoanIntegrationTest {
|
||||
expectedvalues = new ArrayList<>();
|
||||
todaysDate = Calendar.getInstance(Utils.getTimeZoneOfTenant());
|
||||
addRepaymentValues(expectedvalues, todaysDate, -1, false, "2482.76", "46.15", "100.0", "0.0");
|
||||
addRepaymentValues(expectedvalues, todaysDate, 1, false, "2486.03", "42.88", "0.0", "0.0");
|
||||
addRepaymentValues(expectedvalues, todaysDate, 1, false, "2497.5", "31.41", "200", "0.0");
|
||||
addRepaymentValues(expectedvalues, todaysDate, 1, false, "2533.71", "19.93", "0.0", "0.0");
|
||||
addRepaymentValues(expectedvalues, todaysDate, 1, false, "2494.22", "34.69", "0.0", "0.0");
|
||||
addRepaymentValues(expectedvalues, todaysDate, 1, false, "2505.73", "23.18", "200", "0.0");
|
||||
addRepaymentValues(expectedvalues, todaysDate, 1, false, "2517.29", "11.62", "0.0", "0.0");
|
||||
verifyLoanRepaymentSchedule(loanSchedule, expectedvalues);
|
||||
|
||||
Float earlyPayment = new Float("5100");
|
||||
@@ -3671,9 +3637,9 @@ public class ClientLoanIntegrationTest {
|
||||
expectedvalues = new ArrayList<>();
|
||||
todaysDate = Calendar.getInstance(Utils.getTimeZoneOfTenant());
|
||||
addRepaymentValues(expectedvalues, todaysDate, -1, false, "2482.76", "46.15", "100.0", "0.0");
|
||||
addRepaymentValues(expectedvalues, todaysDate, 1, false, "5100.0", "36.16", "0.0", "0.0");
|
||||
addRepaymentValues(expectedvalues, todaysDate, 1, false, "0", "11.16", "200", "0.0");
|
||||
addRepaymentValues(expectedvalues, todaysDate, 1, false, "2417.24", "11.16", "0.0", "0.0");
|
||||
addRepaymentValues(expectedvalues, todaysDate, 1, false, "5065.31", "34.69", "0.0", "0.0");
|
||||
addRepaymentValues(expectedvalues, todaysDate, 1, false, "0", "11.32", "200", "0.0");
|
||||
addRepaymentValues(expectedvalues, todaysDate, 1, false, "2451.93", "11.32", "0.0", "0.0");
|
||||
verifyLoanRepaymentSchedule(loanSchedule, expectedvalues);
|
||||
|
||||
HashMap prepayDetail = this.loanTransactionHelper.getPrepayAmount(this.requestSpec, this.responseSpec, loanID);
|
||||
@@ -3689,7 +3655,7 @@ public class ClientLoanIntegrationTest {
|
||||
@Test
|
||||
public void testLoanScheduleWithInterestRecalculation_WITH_REST_WEEKLY_INTEREST_COMPOUND_INTEREST_FEE_STRATEGY_REDUCE_NEXT_INSTALLMENTS_PRE_CLOSE_INTEREST_PRE_CLOSE_DATE() {
|
||||
String preCloseInterestStrategy = LoanProductTestBuilder.INTEREST_APPLICABLE_STRATEGY_ON_PRE_CLOSE_DATE;
|
||||
String preCloseAmount = "7766.82";
|
||||
String preCloseAmount = "7761.89";
|
||||
testLoanScheduleWithInterestRecalculation_WITH_REST_WEEKLY_INTEREST_COMPOUND_INTEREST_FEE_STRATEGY_REDUCE_NEXT_INSTALLMENTS_PRE_CLOSE_INTEREST(
|
||||
preCloseInterestStrategy, preCloseAmount);
|
||||
|
||||
@@ -3698,7 +3664,7 @@ public class ClientLoanIntegrationTest {
|
||||
@Test
|
||||
public void testLoanScheduleWithInterestRecalculation_WITH_REST_WEEKLY_INTEREST_COMPOUND_INTEREST_FEE_STRATEGY_REDUCE_NEXT_INSTALLMENTS_PRE_CLOSE_INTEREST_REST_DATE() {
|
||||
String preCloseInterestStrategy = LoanProductTestBuilder.INTEREST_APPLICABLE_STRATEGY_REST_DATE;
|
||||
String preCloseAmount = "7771.8";
|
||||
String preCloseAmount = "7786.79";
|
||||
testLoanScheduleWithInterestRecalculation_WITH_REST_WEEKLY_INTEREST_COMPOUND_INTEREST_FEE_STRATEGY_REDUCE_NEXT_INSTALLMENTS_PRE_CLOSE_INTEREST(
|
||||
preCloseInterestStrategy, preCloseAmount);
|
||||
|
||||
@@ -3715,7 +3681,9 @@ public class ClientLoanIntegrationTest {
|
||||
todaysDate.add(Calendar.DAY_OF_MONTH, -16);
|
||||
final String LOAN_DISBURSEMENT_DATE = dateFormat.format(todaysDate.getTime());
|
||||
todaysDate.add(Calendar.DAY_OF_MONTH, -4);
|
||||
final String REST_START_DATE = dateFormat.format(todaysDate.getTime());
|
||||
Integer restDateOfMonth = getDayOfMonth(todaysDate);
|
||||
Integer restDateOfWeek = getDayOfWeek(todaysDate);
|
||||
final String REST_START_DATE = null;
|
||||
|
||||
todaysDate = Calendar.getInstance(Utils.getTimeZoneOfTenant());
|
||||
todaysDate.add(Calendar.DAY_OF_MONTH, -16);
|
||||
@@ -3738,7 +3706,8 @@ public class ClientLoanIntegrationTest {
|
||||
LoanProductTestBuilder.DEFAULT_STRATEGY, LoanProductTestBuilder.RECALCULATION_COMPOUNDING_METHOD_INTEREST_AND_FEE,
|
||||
LoanProductTestBuilder.RECALCULATION_STRATEGY_RESCHEDULE_NEXT_REPAYMENTS,
|
||||
LoanProductTestBuilder.RECALCULATION_FREQUENCY_TYPE_WEEKLY, "1", REST_START_DATE,
|
||||
LoanProductTestBuilder.RECALCULATION_FREQUENCY_TYPE_SAME_AS_REPAYMENT_PERIOD, null, null, preCloseInterestStrategy, null);
|
||||
LoanProductTestBuilder.RECALCULATION_FREQUENCY_TYPE_SAME_AS_REPAYMENT_PERIOD, null, null, preCloseInterestStrategy, null,
|
||||
null, null, restDateOfMonth, restDateOfWeek);
|
||||
|
||||
final Integer loanID = applyForLoanApplicationForInterestRecalculation(clientID, loanProductID, LOAN_DISBURSEMENT_DATE,
|
||||
REST_START_DATE, LoanApplicationTestBuilder.DEFAULT_STRATEGY, charges);
|
||||
@@ -3751,9 +3720,9 @@ public class ClientLoanIntegrationTest {
|
||||
List<Map<String, Object>> expectedvalues = new ArrayList<>();
|
||||
todaysDate = Calendar.getInstance(Utils.getTimeZoneOfTenant());
|
||||
addRepaymentValues(expectedvalues, todaysDate, -9, true, "2482.76", "46.15", "100.0", "0.0");
|
||||
addRepaymentValues(expectedvalues, todaysDate, 1, false, "2489.3", "39.61", "0.0", "0.0");
|
||||
addRepaymentValues(expectedvalues, todaysDate, 1, false, "2500.78", "28.13", "200", "0.0");
|
||||
addRepaymentValues(expectedvalues, todaysDate, 1, false, "2527.16", "16.62", "0.0", "0.0");
|
||||
addRepaymentValues(expectedvalues, todaysDate, 1, false, "2494.22", "34.69", "0.0", "0.0");
|
||||
addRepaymentValues(expectedvalues, todaysDate, 1, false, "2505.73", "23.18", "200", "0.0");
|
||||
addRepaymentValues(expectedvalues, todaysDate, 1, false, "2517.29", "11.62", "0.0", "0.0");
|
||||
verifyLoanRepaymentSchedule(loanSchedule, expectedvalues);
|
||||
|
||||
System.out.println("-----------------------------------APPROVE LOAN-----------------------------------------");
|
||||
@@ -3770,8 +3739,8 @@ public class ClientLoanIntegrationTest {
|
||||
todaysDate = Calendar.getInstance(Utils.getTimeZoneOfTenant());
|
||||
addRepaymentValues(expectedvalues, todaysDate, -9, true, "2482.76", "46.15", "100.0", "0.0");
|
||||
addRepaymentValues(expectedvalues, todaysDate, 1, false, "2482.08", "46.83", "0.0", "0.0");
|
||||
addRepaymentValues(expectedvalues, todaysDate, 1, false, "2495.47", "33.44", "200", "0.0");
|
||||
addRepaymentValues(expectedvalues, todaysDate, 1, false, "2539.69", "16.66", "0.0", "0.0");
|
||||
addRepaymentValues(expectedvalues, todaysDate, 1, false, "2481.87", "47.04", "200", "0.0");
|
||||
addRepaymentValues(expectedvalues, todaysDate, 1, false, "2553.29", "11.78", "0.0", "0.0");
|
||||
|
||||
verifyLoanRepaymentSchedule(loanSchedule, expectedvalues);
|
||||
|
||||
@@ -3785,9 +3754,9 @@ public class ClientLoanIntegrationTest {
|
||||
expectedvalues = new ArrayList<>();
|
||||
todaysDate = Calendar.getInstance(Utils.getTimeZoneOfTenant());
|
||||
addRepaymentValues(expectedvalues, todaysDate, -9, true, "2482.76", "46.15", "100.0", "0.0");
|
||||
addRepaymentValues(expectedvalues, todaysDate, 1, false, "2489.3", "39.61", "0.0", "0.0");
|
||||
addRepaymentValues(expectedvalues, todaysDate, 1, false, "2500.7", "28.21", "200", "0.0");
|
||||
addRepaymentValues(expectedvalues, todaysDate, 1, false, "2527.24", "16.62", "0.0", "0.0");
|
||||
addRepaymentValues(expectedvalues, todaysDate, 1, false, "2494.22", "34.69", "0.0", "0.0");
|
||||
addRepaymentValues(expectedvalues, todaysDate, 1, false, "2494.05", "34.86", "200", "0.0");
|
||||
addRepaymentValues(expectedvalues, todaysDate, 1, false, "2528.97", "11.67", "0.0", "0.0");
|
||||
verifyLoanRepaymentSchedule(loanSchedule, expectedvalues);
|
||||
|
||||
HashMap prepayDetail = this.loanTransactionHelper.getPrepayAmount(this.requestSpec, this.responseSpec, loanID);
|
||||
@@ -3831,7 +3800,7 @@ public class ClientLoanIntegrationTest {
|
||||
LoanProductTestBuilder.RECALCULATION_FREQUENCY_TYPE_DAILY, "1", REST_START_DATE,
|
||||
LoanProductTestBuilder.RECALCULATION_FREQUENCY_TYPE_SAME_AS_REPAYMENT_PERIOD, recalculationCompoundingFrequencyInterval,
|
||||
recalculationCompoundingFrequencyDate, LoanProductTestBuilder.INTEREST_APPLICABLE_STRATEGY_ON_PRE_CLOSE_DATE, null,
|
||||
overdueFeeChargeId.toString(), false);
|
||||
overdueFeeChargeId.toString(), false, null, null, null, null);
|
||||
|
||||
final Integer loanID = applyForLoanApplicationForInterestRecalculation(clientID, loanProductID, LOAN_DISBURSEMENT_DATE,
|
||||
REST_START_DATE, LoanApplicationTestBuilder.DEFAULT_STRATEGY, null);
|
||||
@@ -3940,7 +3909,7 @@ public class ClientLoanIntegrationTest {
|
||||
LoanProductTestBuilder.RECALCULATION_COMPOUNDING_METHOD_NONE,
|
||||
LoanProductTestBuilder.RECALCULATION_STRATEGY_REDUCE_EMI_AMOUN,
|
||||
LoanProductTestBuilder.RECALCULATION_FREQUENCY_TYPE_SAME_AS_REPAYMENT_PERIOD, "0", null,
|
||||
LoanProductTestBuilder.INTEREST_APPLICABLE_STRATEGY_ON_PRE_CLOSE_DATE, accounts);
|
||||
LoanProductTestBuilder.INTEREST_APPLICABLE_STRATEGY_ON_PRE_CLOSE_DATE, accounts, null, null);
|
||||
|
||||
final Integer loanID = applyForLoanApplicationForInterestRecalculation(clientID, loanProductID, LOAN_DISBURSEMENT_DATE, null,
|
||||
LoanApplicationTestBuilder.DEFAULT_STRATEGY, new ArrayList<HashMap>(0));
|
||||
@@ -3983,6 +3952,7 @@ public class ClientLoanIntegrationTest {
|
||||
this.journalEntryHelper.checkJournalEntryForAssetAccount(assetAccount, LOAN_DISBURSEMENT_DATE, assetAccountInitialEntry);
|
||||
todaysDate = Calendar.getInstance(Utils.getTimeZoneOfTenant());
|
||||
String runOndate = dateFormat.format(todaysDate.getTime());
|
||||
System.out.println("runOndate : " + runOndate);
|
||||
this.periodicAccrualAccountingHelper.runPeriodicAccrualAccounting(runOndate);
|
||||
this.loanTransactionHelper.checkAccrualTransactionForRepayment(Utils.getLocalDateOfTenant().minusDays(7), 46.15f, 0f, 0f, loanID);
|
||||
this.loanTransactionHelper.checkAccrualTransactionForRepayment(Utils.getLocalDateOfTenant(), 46.15f, 0f, 0f, loanID);
|
||||
@@ -4002,6 +3972,7 @@ public class ClientLoanIntegrationTest {
|
||||
addRepaymentValues(expectedvalues, todaysDate, 1, false, "2517.29", "11.62", "0.0", "0.0");
|
||||
verifyLoanRepaymentSchedule(loanSchedule, expectedvalues);
|
||||
|
||||
this.periodicAccrualAccountingHelper.runPeriodicAccrualAccounting(runOndate);
|
||||
this.loanTransactionHelper.checkAccrualTransactionForRepayment(Utils.getLocalDateOfTenant().minusDays(7), 46.15f, 0f, 0f, loanID);
|
||||
this.loanTransactionHelper.checkAccrualTransactionForRepayment(Utils.getLocalDateOfTenant(), 34.69f, 0f, 0f, loanID);
|
||||
|
||||
@@ -4036,7 +4007,8 @@ public class ClientLoanIntegrationTest {
|
||||
LoanProductTestBuilder.RECALCULATION_STRATEGY_RESCHEDULE_NEXT_REPAYMENTS,
|
||||
LoanProductTestBuilder.RECALCULATION_FREQUENCY_TYPE_DAILY, "1", LOAN_DISBURSEMENT_DATE,
|
||||
LoanProductTestBuilder.RECALCULATION_FREQUENCY_TYPE_SAME_AS_REPAYMENT_PERIOD, "1", LOAN_DISBURSEMENT_DATE,
|
||||
LoanProductTestBuilder.INTEREST_APPLICABLE_STRATEGY_ON_PRE_CLOSE_DATE, null);
|
||||
LoanProductTestBuilder.INTEREST_APPLICABLE_STRATEGY_ON_PRE_CLOSE_DATE, null, getDayOfMonth(todaysDate),
|
||||
getDayOfWeek(todaysDate), getDayOfMonth(todaysDate), getDayOfWeek(todaysDate));
|
||||
|
||||
final Integer loanID = applyForLoanApplicationForInterestRecalculation(clientID, loanProductID, LOAN_DISBURSEMENT_DATE,
|
||||
LOAN_DISBURSEMENT_DATE, LoanApplicationTestBuilder.RBI_INDIA_STRATEGY, new ArrayList<HashMap>(0));
|
||||
@@ -4119,7 +4091,7 @@ public class ClientLoanIntegrationTest {
|
||||
LoanProductTestBuilder.RECALCULATION_FREQUENCY_TYPE_DAILY, "1", LOAN_DISBURSEMENT_DATE,
|
||||
LoanProductTestBuilder.RECALCULATION_FREQUENCY_TYPE_SAME_AS_REPAYMENT_PERIOD, recalculationCompoundingFrequencyInterval,
|
||||
recalculationCompoundingFrequencyDate, LoanProductTestBuilder.INTEREST_APPLICABLE_STRATEGY_ON_PRE_CLOSE_DATE, null, null,
|
||||
true);
|
||||
true, null, null, getDayOfMonth(todaysDate), getDayOfWeek(todaysDate));
|
||||
|
||||
final Integer loanID = applyForLoanApplicationForInterestRecalculation(clientID, loanProductID, LOAN_DISBURSEMENT_DATE,
|
||||
LOAN_DISBURSEMENT_DATE, LoanApplicationTestBuilder.RBI_INDIA_STRATEGY, new ArrayList<HashMap>(0));
|
||||
@@ -4206,10 +4178,10 @@ public class ClientLoanIntegrationTest {
|
||||
final Integer loanProductID = createLoanProductWithInterestRecalculation(LoanProductTestBuilder.DEFAULT_STRATEGY,
|
||||
LoanProductTestBuilder.RECALCULATION_COMPOUNDING_METHOD_NONE,
|
||||
LoanProductTestBuilder.RECALCULATION_STRATEGY_REDUCE_EMI_AMOUN,
|
||||
LoanProductTestBuilder.RECALCULATION_FREQUENCY_TYPE_SAME_AS_REPAYMENT_PERIOD, "0", null, preCloseStrategy, null);
|
||||
LoanProductTestBuilder.RECALCULATION_FREQUENCY_TYPE_SAME_AS_REPAYMENT_PERIOD, "0", null, preCloseStrategy, null, null, null);
|
||||
|
||||
final Integer loanID = applyForLoanApplicationForInterestRecalculationWithMoratorium(clientID, loanProductID,
|
||||
LOAN_DISBURSEMENT_DATE, null, LoanApplicationTestBuilder.DEFAULT_STRATEGY, new ArrayList<HashMap>(0), "1", null);
|
||||
LOAN_DISBURSEMENT_DATE, LoanApplicationTestBuilder.DEFAULT_STRATEGY, new ArrayList<HashMap>(0), "1", null);
|
||||
|
||||
Assert.assertNotNull(loanID);
|
||||
HashMap loanStatusHashMap = LoanStatusChecker.getStatusOfLoan(this.requestSpec, this.responseSpec, loanID);
|
||||
@@ -4284,14 +4256,19 @@ public class ClientLoanIntegrationTest {
|
||||
private Integer createLoanProductWithInterestRecalculation(final String repaymentStrategy,
|
||||
final String interestRecalculationCompoundingMethod, final String rescheduleStrategyMethod,
|
||||
final String recalculationRestFrequencyType, final String recalculationRestFrequencyInterval,
|
||||
final String recalculationRestFrequencyDate, final String preCloseInterestCalculationStrategy, final Account[] accounts) {
|
||||
final String recalculationRestFrequencyDate, final String preCloseInterestCalculationStrategy, final Account[] accounts,
|
||||
final Integer recalculationRestFrequencyOnDayType, final Integer recalculationRestFrequencyDayOfWeekType) {
|
||||
final String recalculationCompoundingFrequencyType = null;
|
||||
final String recalculationCompoundingFrequencyInterval = null;
|
||||
final String recalculationCompoundingFrequencyDate = null;
|
||||
final Integer recalculationCompoundingFrequencyOnDayType = null;
|
||||
final Integer recalculationCompoundingFrequencyDayOfWeekType = null;
|
||||
return createLoanProductWithInterestRecalculation(repaymentStrategy, interestRecalculationCompoundingMethod,
|
||||
rescheduleStrategyMethod, recalculationRestFrequencyType, recalculationRestFrequencyInterval,
|
||||
recalculationRestFrequencyDate, recalculationCompoundingFrequencyType, recalculationCompoundingFrequencyInterval,
|
||||
recalculationCompoundingFrequencyDate, preCloseInterestCalculationStrategy, accounts, null, false);
|
||||
recalculationCompoundingFrequencyDate, preCloseInterestCalculationStrategy, accounts, null, false,
|
||||
recalculationCompoundingFrequencyOnDayType, recalculationCompoundingFrequencyDayOfWeekType,
|
||||
recalculationRestFrequencyOnDayType, recalculationRestFrequencyDayOfWeekType);
|
||||
}
|
||||
|
||||
private Integer createLoanProductWithInterestRecalculationAndCompoundingDetails(final String repaymentStrategy,
|
||||
@@ -4299,11 +4276,15 @@ public class ClientLoanIntegrationTest {
|
||||
final String recalculationRestFrequencyType, final String recalculationRestFrequencyInterval,
|
||||
final String recalculationRestFrequencyDate, final String recalculationCompoundingFrequencyType,
|
||||
final String recalculationCompoundingFrequencyInterval, final String recalculationCompoundingFrequencyDate,
|
||||
final String preCloseInterestCalculationStrategy, final Account[] accounts) {
|
||||
final String preCloseInterestCalculationStrategy, final Account[] accounts,
|
||||
final Integer recalculationCompoundingFrequencyOnDayType, final Integer recalculationCompoundingFrequencyDayOfWeekType,
|
||||
final Integer recalculationRestFrequencyOnDayType, final Integer recalculationRestFrequencyDayOfWeekType) {
|
||||
return createLoanProductWithInterestRecalculation(repaymentStrategy, interestRecalculationCompoundingMethod,
|
||||
rescheduleStrategyMethod, recalculationRestFrequencyType, recalculationRestFrequencyInterval,
|
||||
recalculationRestFrequencyDate, recalculationCompoundingFrequencyType, recalculationCompoundingFrequencyInterval,
|
||||
recalculationCompoundingFrequencyDate, preCloseInterestCalculationStrategy, accounts, null, false);
|
||||
recalculationCompoundingFrequencyDate, preCloseInterestCalculationStrategy, accounts, null, false,
|
||||
recalculationCompoundingFrequencyOnDayType, recalculationCompoundingFrequencyDayOfWeekType,
|
||||
recalculationRestFrequencyOnDayType, recalculationRestFrequencyDayOfWeekType);
|
||||
}
|
||||
|
||||
private Integer createLoanProductWithInterestRecalculation(final String repaymentStrategy,
|
||||
@@ -4312,7 +4293,9 @@ public class ClientLoanIntegrationTest {
|
||||
final String recalculationRestFrequencyDate, final String recalculationCompoundingFrequencyType,
|
||||
final String recalculationCompoundingFrequencyInterval, final String recalculationCompoundingFrequencyDate,
|
||||
final String preCloseInterestCalculationStrategy, final Account[] accounts, final String chargeId,
|
||||
boolean isArrearsBasedOnOriginalSchedule) {
|
||||
boolean isArrearsBasedOnOriginalSchedule, final Integer recalculationCompoundingFrequencyOnDayType,
|
||||
final Integer recalculationCompoundingFrequencyDayOfWeekType, final Integer recalculationRestFrequencyOnDayType,
|
||||
final Integer recalculationRestFrequencyDayOfWeekType) {
|
||||
System.out.println("------------------------------CREATING NEW LOAN PRODUCT ---------------------------------------");
|
||||
LoanProductTestBuilder builder = new LoanProductTestBuilder()
|
||||
.withPrincipal("10000000.00")
|
||||
@@ -4328,9 +4311,10 @@ public class ClientLoanIntegrationTest {
|
||||
.withInterestRecalculationDetails(interestRecalculationCompoundingMethod, rescheduleStrategyMethod,
|
||||
preCloseInterestCalculationStrategy)
|
||||
.withInterestRecalculationRestFrequencyDetails(recalculationRestFrequencyType, recalculationRestFrequencyInterval,
|
||||
recalculationRestFrequencyDate)
|
||||
recalculationRestFrequencyOnDayType, recalculationRestFrequencyDayOfWeekType)
|
||||
.withInterestRecalculationCompoundingFrequencyDetails(recalculationCompoundingFrequencyType,
|
||||
recalculationCompoundingFrequencyInterval, recalculationCompoundingFrequencyDate);
|
||||
recalculationCompoundingFrequencyInterval, recalculationCompoundingFrequencyOnDayType,
|
||||
recalculationCompoundingFrequencyDayOfWeekType);
|
||||
if (accounts != null) {
|
||||
builder = builder.withAccountingRulePeriodicAccrual(accounts);
|
||||
}
|
||||
@@ -4342,30 +4326,27 @@ public class ClientLoanIntegrationTest {
|
||||
}
|
||||
|
||||
private Integer applyForLoanApplicationForInterestRecalculation(final Integer clientID, final Integer loanProductID,
|
||||
final String disbursementDate, final String restStartDate, final String repaymentStrategy, final List<HashMap> charges) {
|
||||
final String compoundingStartDate = null;
|
||||
return applyForLoanApplicationForInterestRecalculation(clientID, loanProductID, disbursementDate, restStartDate,
|
||||
compoundingStartDate, repaymentStrategy, charges);
|
||||
final String disbursementDate, final String repaymentStrategy, final List<HashMap> charges) {
|
||||
return applyForLoanApplicationForInterestRecalculation(clientID, loanProductID, disbursementDate, repaymentStrategy, charges, null,
|
||||
null);
|
||||
}
|
||||
|
||||
private Integer applyForLoanApplicationForInterestRecalculationWithMoratorium(final Integer clientID, final Integer loanProductID,
|
||||
final String disbursementDate, final String restStartDate, final String repaymentStrategy, final List<HashMap> charges,
|
||||
final String disbursementDate, final String repaymentStrategy, final List<HashMap> charges,
|
||||
final String graceOnInterestPayment, final String graceOnPrincipalPayment) {
|
||||
final String compoundingStartDate = null;
|
||||
return applyForLoanApplicationForInterestRecalculation(clientID, loanProductID, disbursementDate, restStartDate,
|
||||
compoundingStartDate, repaymentStrategy, charges, graceOnInterestPayment, graceOnPrincipalPayment);
|
||||
return applyForLoanApplicationForInterestRecalculation(clientID, loanProductID, disbursementDate, repaymentStrategy, charges,
|
||||
graceOnInterestPayment, graceOnPrincipalPayment);
|
||||
}
|
||||
|
||||
private Integer applyForLoanApplicationForInterestRecalculation(final Integer clientID, final Integer loanProductID,
|
||||
final String disbursementDate, final String restStartDate, final String compoundingStartDate, final String repaymentStrategy,
|
||||
final List<HashMap> charges) {
|
||||
return applyForLoanApplicationForInterestRecalculation(clientID, loanProductID, disbursementDate, restStartDate,
|
||||
compoundingStartDate, repaymentStrategy, charges, null, null);
|
||||
final String disbursementDate, final String compoundingStartDate, final String repaymentStrategy, final List<HashMap> charges) {
|
||||
return applyForLoanApplicationForInterestRecalculation(clientID, loanProductID, disbursementDate, repaymentStrategy, charges, null,
|
||||
null);
|
||||
}
|
||||
|
||||
private Integer applyForLoanApplicationForInterestRecalculation(final Integer clientID, final Integer loanProductID,
|
||||
final String disbursementDate, final String restStartDate, final String compoundingStartDate, final String repaymentStrategy,
|
||||
final List<HashMap> charges, final String graceOnInterestPayment, final String graceOnPrincipalPayment) {
|
||||
final String disbursementDate, final String repaymentStrategy, final List<HashMap> charges,
|
||||
final String graceOnInterestPayment, final String graceOnPrincipalPayment) {
|
||||
System.out.println("--------------------------------APPLYING FOR LOAN APPLICATION--------------------------------");
|
||||
final String loanApplicationJSON = new LoanApplicationTestBuilder() //
|
||||
.withPrincipal("10000.00") //
|
||||
@@ -4380,8 +4361,6 @@ public class ClientLoanIntegrationTest {
|
||||
.withInterestCalculationPeriodTypeSameAsRepaymentPeriod() //
|
||||
.withExpectedDisbursementDate(disbursementDate) //
|
||||
.withSubmittedOnDate(disbursementDate) //
|
||||
.withRestFrequencyDate(restStartDate)//
|
||||
.withCompoundingFrequencyDate(compoundingStartDate)//
|
||||
.withwithRepaymentStrategy(repaymentStrategy) //
|
||||
.withPrincipalGrace(graceOnPrincipalPayment) //
|
||||
.withInterestGrace(graceOnInterestPayment)//
|
||||
@@ -4593,9 +4572,9 @@ public class ClientLoanIntegrationTest {
|
||||
final Account expenseAccount = this.accountHelper.createExpenseAccount();
|
||||
final Account overpaymentAccount = this.accountHelper.createLiabilityAccount();
|
||||
|
||||
final Integer loanProductID = createLoanProduct("0", "0", LoanProductTestBuilder.DEFAULT_STRATEGY, ACCRUAL_UPFRONT,
|
||||
assetAccount, incomeAccount, expenseAccount, overpaymentAccount);// ,
|
||||
// LoanProductTestBuilder.EQUAL_INSTALLMENTS,
|
||||
final Integer loanProductID = createLoanProduct("0", "0", LoanProductTestBuilder.DEFAULT_STRATEGY, ACCRUAL_UPFRONT, assetAccount,
|
||||
incomeAccount, expenseAccount, overpaymentAccount);// ,
|
||||
// LoanProductTestBuilder.EQUAL_INSTALLMENTS,
|
||||
// LoanProductTestBuilder.FLAT_BALANCE);
|
||||
Assert.assertNotNull(loanProductID);
|
||||
|
||||
@@ -4656,9 +4635,7 @@ public class ClientLoanIntegrationTest {
|
||||
|
||||
this.loanTransactionHelper.makeRepayment(twoMonthsfromNow, Float.valueOf("2290"), loanID);
|
||||
this.journalEntryHelper.checkJournalEntryForAssetAccount(assetAccount, twoMonthsfromNow, new JournalEntry(Float.valueOf("2290"),
|
||||
JournalEntry.TransactionType.DEBIT), new JournalEntry(Float.valueOf("50"), JournalEntry.TransactionType.CREDIT),
|
||||
new JournalEntry(Float.valueOf("240"), JournalEntry.TransactionType.CREDIT), new JournalEntry(Float.valueOf("2000"),
|
||||
JournalEntry.TransactionType.CREDIT));
|
||||
JournalEntry.TransactionType.DEBIT), new JournalEntry(Float.valueOf("2290"), JournalEntry.TransactionType.CREDIT));
|
||||
|
||||
loanSchedule.clear();
|
||||
loanSchedule = this.loanTransactionHelper.getLoanRepaymentSchedule(this.requestSpec, this.responseSpec, loanID);
|
||||
@@ -4673,9 +4650,7 @@ public class ClientLoanIntegrationTest {
|
||||
|
||||
this.loanTransactionHelper.makeRepayment(oneMonthfromNow, Float.valueOf("4580"), loanID);
|
||||
this.journalEntryHelper.checkJournalEntryForAssetAccount(assetAccount, oneMonthfromNow, new JournalEntry(Float.valueOf("4580"),
|
||||
JournalEntry.TransactionType.DEBIT), new JournalEntry(Float.valueOf("100"), JournalEntry.TransactionType.CREDIT),
|
||||
new JournalEntry(Float.valueOf("480"), JournalEntry.TransactionType.CREDIT), new JournalEntry(Float.valueOf("4000"),
|
||||
JournalEntry.TransactionType.CREDIT));
|
||||
JournalEntry.TransactionType.DEBIT), new JournalEntry(Float.valueOf("4580"), JournalEntry.TransactionType.CREDIT));
|
||||
|
||||
loanSchedule.clear();
|
||||
loanSchedule = this.loanTransactionHelper.getLoanRepaymentSchedule(this.requestSpec, this.responseSpec, loanID);
|
||||
@@ -4967,10 +4942,9 @@ public class ClientLoanIntegrationTest {
|
||||
System.out.println("------------------------LOAN CREATED WITH ID------------------------------" + loanID);
|
||||
|
||||
loanProductID = this.loanTransactionHelper.getLoanProductId(new LoanProductTestBuilder().withAmortizationTypeAsEqualInstallments()
|
||||
.withRepaymentTypeAsMonth().withRepaymentAfterEvery("1")
|
||||
.withRepaymentStrategy(LoanProductTestBuilder.DEFAULT_STRATEGY).withInterestTypeAsDecliningBalance()
|
||||
.withInterestCalculationPeriodTypeAsDays().withInArrearsTolerance("10").withMoratorium("2", "3")
|
||||
.withLoanProductConfiguration(loanProductConfigurationAsFalse).build(null));
|
||||
.withRepaymentTypeAsMonth().withRepaymentAfterEvery("1").withRepaymentStrategy(LoanProductTestBuilder.DEFAULT_STRATEGY)
|
||||
.withInterestTypeAsDecliningBalance().withInterestCalculationPeriodTypeAsDays().withInArrearsTolerance("10")
|
||||
.withMoratorium("2", "3").withLoanProductConfiguration(loanProductConfigurationAsFalse).build(null));
|
||||
System.out.println("-------------------LOAN PRODUCT CREATED WITH ATTRIBUTE CONFIGURATION AS FALSE----------------------"
|
||||
+ loanProductID);
|
||||
/*
|
||||
@@ -4990,8 +4964,8 @@ public class ClientLoanIntegrationTest {
|
||||
"inArrearsTolerance", "graceOnArrearsAgeing");
|
||||
|
||||
for (String comparisonAttribute : comparisonAttributes) {
|
||||
Object val1 = JsonPath.from(loanProductDetails).get(comparisonAttribute);
|
||||
Object val2 = JsonPath.from(loanDetails).get(comparisonAttribute);
|
||||
Object val1 = JsonPath.from(loanProductDetails).get(comparisonAttribute);
|
||||
Object val2 = JsonPath.from(loanDetails).get(comparisonAttribute);
|
||||
assertEquals(val1, val2);
|
||||
}
|
||||
}
|
||||
@@ -5050,4 +5024,26 @@ public class ClientLoanIntegrationTest {
|
||||
|
||||
return this.loanTransactionHelper.getLoanId(loanApplicationJSON);
|
||||
}
|
||||
|
||||
public Integer getDayOfWeek(Calendar date) {
|
||||
Integer dayOfWeek = null;
|
||||
if (null != date) {
|
||||
dayOfWeek = date.get(Calendar.DAY_OF_WEEK) - 1;
|
||||
if (dayOfWeek.compareTo(0) == 0) {
|
||||
dayOfWeek = 7;
|
||||
}
|
||||
}
|
||||
return dayOfWeek;
|
||||
}
|
||||
|
||||
public Integer getDayOfMonth(Calendar date) {
|
||||
Integer dayOfMonth = null;
|
||||
if (null != date) {
|
||||
dayOfMonth = date.get(Calendar.DAY_OF_MONTH);
|
||||
if (dayOfMonth.compareTo(28) > 0) {
|
||||
dayOfMonth = 28;
|
||||
}
|
||||
}
|
||||
return dayOfMonth;
|
||||
}
|
||||
}
|
||||
+22
-19
@@ -72,7 +72,6 @@ public class LoanRepaymentRescheduleAtDisbursementTest {
|
||||
final String expectedDisbursementDate = "01 March 2015";
|
||||
final String disbursementDate = "01 March 2015";
|
||||
final String adjustRepaymentDate = "16 March 2015";
|
||||
final String recalculationRestFrequencyDate = "01 January 2012";
|
||||
|
||||
// CREATE CLIENT
|
||||
final Integer clientID = ClientHelper.createClient(this.requestSpec, this.responseSpec, "01 January 2014");
|
||||
@@ -83,7 +82,7 @@ public class LoanRepaymentRescheduleAtDisbursementTest {
|
||||
final Integer loanProductID = createLoanProductWithInterestRecalculation(LoanProductTestBuilder.RBI_INDIA_STRATEGY,
|
||||
LoanProductTestBuilder.RECALCULATION_COMPOUNDING_METHOD_NONE,
|
||||
LoanProductTestBuilder.RECALCULATION_STRATEGY_REDUCE_NUMBER_OF_INSTALLMENTS,
|
||||
LoanProductTestBuilder.RECALCULATION_FREQUENCY_TYPE_DAILY, "0", recalculationRestFrequencyDate,
|
||||
LoanProductTestBuilder.RECALCULATION_FREQUENCY_TYPE_DAILY, "0",
|
||||
LoanProductTestBuilder.INTEREST_APPLICABLE_STRATEGY_ON_PRE_CLOSE_DATE, null);
|
||||
|
||||
// CREATE TRANCHES
|
||||
@@ -98,7 +97,7 @@ public class LoanRepaymentRescheduleAtDisbursementTest {
|
||||
|
||||
// APPLY FOR TRANCHE LOAN WITH INTEREST RECALCULATION
|
||||
final Integer loanID = applyForLoanApplicationForInterestRecalculation(clientID, loanProductID, disbursementDate,
|
||||
recalculationRestFrequencyDate, LoanApplicationTestBuilder.RBI_INDIA_STRATEGY, new ArrayList<HashMap>(0), createTranches);
|
||||
LoanApplicationTestBuilder.RBI_INDIA_STRATEGY, new ArrayList<HashMap>(0), createTranches);
|
||||
|
||||
HashMap loanStatusHashMap = LoanStatusChecker.getStatusOfLoan(this.requestSpec, this.responseSpec, loanID);
|
||||
|
||||
@@ -148,23 +147,28 @@ public class LoanRepaymentRescheduleAtDisbursementTest {
|
||||
private Integer createLoanProductWithInterestRecalculation(final String repaymentStrategy,
|
||||
final String interestRecalculationCompoundingMethod, final String rescheduleStrategyMethod,
|
||||
final String recalculationRestFrequencyType, final String recalculationRestFrequencyInterval,
|
||||
final String recalculationRestFrequencyDate, final String preCloseInterestCalculationStrategy, final Account[] accounts) {
|
||||
final String preCloseInterestCalculationStrategy, final Account[] accounts) {
|
||||
final String recalculationCompoundingFrequencyType = null;
|
||||
final String recalculationCompoundingFrequencyInterval = null;
|
||||
final String recalculationCompoundingFrequencyDate = null;
|
||||
final Integer recalculationCompoundingFrequencyOnDayType = null;
|
||||
final Integer recalculationCompoundingFrequencyDayOfWeekType = null;
|
||||
final Integer recalculationRestFrequencyOnDayType = null;
|
||||
final Integer recalculationRestFrequencyDayOfWeekType = null;
|
||||
return createLoanProductWithInterestRecalculation(repaymentStrategy, interestRecalculationCompoundingMethod,
|
||||
rescheduleStrategyMethod, recalculationRestFrequencyType, recalculationRestFrequencyInterval,
|
||||
recalculationRestFrequencyDate, recalculationCompoundingFrequencyType, recalculationCompoundingFrequencyInterval,
|
||||
recalculationCompoundingFrequencyDate, preCloseInterestCalculationStrategy, accounts, null, false);
|
||||
recalculationCompoundingFrequencyType, recalculationCompoundingFrequencyInterval, preCloseInterestCalculationStrategy,
|
||||
accounts, null, false, recalculationCompoundingFrequencyOnDayType, recalculationCompoundingFrequencyDayOfWeekType,
|
||||
recalculationRestFrequencyOnDayType, recalculationRestFrequencyDayOfWeekType);
|
||||
}
|
||||
|
||||
private Integer createLoanProductWithInterestRecalculation(final String repaymentStrategy,
|
||||
final String interestRecalculationCompoundingMethod, final String rescheduleStrategyMethod,
|
||||
final String recalculationRestFrequencyType, final String recalculationRestFrequencyInterval,
|
||||
final String recalculationRestFrequencyDate, final String recalculationCompoundingFrequencyType,
|
||||
final String recalculationCompoundingFrequencyInterval, final String recalculationCompoundingFrequencyDate,
|
||||
final String recalculationCompoundingFrequencyType, final String recalculationCompoundingFrequencyInterval,
|
||||
final String preCloseInterestCalculationStrategy, final Account[] accounts, final String chargeId,
|
||||
boolean isArrearsBasedOnOriginalSchedule) {
|
||||
boolean isArrearsBasedOnOriginalSchedule, final Integer recalculationCompoundingFrequencyOnDayType,
|
||||
final Integer recalculationCompoundingFrequencyDayOfWeekType, final Integer recalculationRestFrequencyOnDayType,
|
||||
final Integer recalculationRestFrequencyDayOfWeekType) {
|
||||
System.out.println("------------------------------CREATING NEW LOAN PRODUCT ---------------------------------------");
|
||||
LoanProductTestBuilder builder = new LoanProductTestBuilder()
|
||||
.withPrincipal("10000.00")
|
||||
@@ -180,9 +184,10 @@ public class LoanRepaymentRescheduleAtDisbursementTest {
|
||||
.withInterestRecalculationDetails(interestRecalculationCompoundingMethod, rescheduleStrategyMethod,
|
||||
preCloseInterestCalculationStrategy)
|
||||
.withInterestRecalculationRestFrequencyDetails(recalculationRestFrequencyType, recalculationRestFrequencyInterval,
|
||||
recalculationRestFrequencyDate)
|
||||
recalculationRestFrequencyOnDayType, recalculationRestFrequencyDayOfWeekType)
|
||||
.withInterestRecalculationCompoundingFrequencyDetails(recalculationCompoundingFrequencyType,
|
||||
recalculationCompoundingFrequencyInterval, recalculationCompoundingFrequencyDate);
|
||||
recalculationCompoundingFrequencyInterval, recalculationCompoundingFrequencyOnDayType,
|
||||
recalculationCompoundingFrequencyDayOfWeekType);
|
||||
if (accounts != null) {
|
||||
builder = builder.withAccountingRulePeriodicAccrual(accounts);
|
||||
}
|
||||
@@ -194,17 +199,16 @@ public class LoanRepaymentRescheduleAtDisbursementTest {
|
||||
}
|
||||
|
||||
private Integer applyForLoanApplicationForInterestRecalculation(final Integer clientID, final Integer loanProductID,
|
||||
final String disbursementDate, final String restStartDate, final String repaymentStrategy, final List<HashMap> charges, List<HashMap> tranches) {
|
||||
final String disbursementDate, final String repaymentStrategy, final List<HashMap> charges, List<HashMap> tranches) {
|
||||
final String graceOnInterestPayment = null;
|
||||
final String compoundingStartDate = null;
|
||||
final String graceOnPrincipalPayment = null;
|
||||
return applyForLoanApplicationForInterestRecalculation(clientID, loanProductID, disbursementDate, restStartDate,
|
||||
compoundingStartDate, repaymentStrategy, charges, graceOnInterestPayment, graceOnPrincipalPayment,tranches);
|
||||
return applyForLoanApplicationForInterestRecalculation(clientID, loanProductID, disbursementDate, repaymentStrategy, charges,
|
||||
graceOnInterestPayment, graceOnPrincipalPayment, tranches);
|
||||
}
|
||||
|
||||
private Integer applyForLoanApplicationForInterestRecalculation(final Integer clientID, final Integer loanProductID,
|
||||
final String disbursementDate, final String restStartDate, final String compoundingStartDate, final String repaymentStrategy,
|
||||
final List<HashMap> charges, final String graceOnInterestPayment, final String graceOnPrincipalPayment, List<HashMap> tranches) {
|
||||
final String disbursementDate, final String repaymentStrategy, final List<HashMap> charges, final String graceOnInterestPayment,
|
||||
final String graceOnPrincipalPayment, List<HashMap> tranches) {
|
||||
System.out.println("--------------------------------APPLYING FOR LOAN APPLICATION--------------------------------");
|
||||
final String loanApplicationJSON = new LoanApplicationTestBuilder() //
|
||||
.withPrincipal("10000.00") //
|
||||
@@ -222,7 +226,6 @@ public class LoanRepaymentRescheduleAtDisbursementTest {
|
||||
.withInterestCalculationPeriodTypeAsDays() //
|
||||
.withExpectedDisbursementDate(disbursementDate) //
|
||||
.withSubmittedOnDate(disbursementDate) //
|
||||
.withRestFrequencyDate(restStartDate)//
|
||||
.withwithRepaymentStrategy(repaymentStrategy) //
|
||||
.withCharges(charges)//
|
||||
.build(clientID.toString(), loanProductID.toString(), null);
|
||||
|
||||
+18
-8
@@ -111,7 +111,8 @@ public class LoanReschedulingWithinCenterTest {
|
||||
LoanProductTestBuilder.RECALCULATION_COMPOUNDING_METHOD_NONE,
|
||||
LoanProductTestBuilder.RECALCULATION_STRATEGY_REDUCE_NUMBER_OF_INSTALLMENTS,
|
||||
LoanProductTestBuilder.RECALCULATION_FREQUENCY_TYPE_DAILY, "0", recalculationRestFrequencyDate,
|
||||
LoanProductTestBuilder.INTEREST_APPLICABLE_STRATEGY_ON_PRE_CLOSE_DATE, null, isMultiTrancheLoan);
|
||||
LoanProductTestBuilder.INTEREST_APPLICABLE_STRATEGY_ON_PRE_CLOSE_DATE, null, isMultiTrancheLoan,
|
||||
null, null);
|
||||
|
||||
// APPLY FOR TRANCHE LOAN WITH INTEREST RECALCULATION
|
||||
final Integer loanId = applyForLoanApplicationForInterestRecalculation(clientId, groupId, calendarId, loanProductID, disbursalDate,
|
||||
@@ -222,7 +223,8 @@ public class LoanReschedulingWithinCenterTest {
|
||||
LoanProductTestBuilder.RECALCULATION_COMPOUNDING_METHOD_NONE,
|
||||
LoanProductTestBuilder.RECALCULATION_STRATEGY_REDUCE_NUMBER_OF_INSTALLMENTS,
|
||||
LoanProductTestBuilder.RECALCULATION_FREQUENCY_TYPE_DAILY, "0", recalculationRestFrequencyDate,
|
||||
LoanProductTestBuilder.INTEREST_APPLICABLE_STRATEGY_ON_PRE_CLOSE_DATE, null, isMultiTrancheLoan);
|
||||
LoanProductTestBuilder.INTEREST_APPLICABLE_STRATEGY_ON_PRE_CLOSE_DATE, null, isMultiTrancheLoan,
|
||||
null, null);
|
||||
|
||||
// CREATE TRANCHES
|
||||
List<HashMap> createTranches = new ArrayList<>();
|
||||
@@ -279,14 +281,18 @@ public class LoanReschedulingWithinCenterTest {
|
||||
final String interestRecalculationCompoundingMethod, final String rescheduleStrategyMethod,
|
||||
final String recalculationRestFrequencyType, final String recalculationRestFrequencyInterval,
|
||||
final String recalculationRestFrequencyDate, final String preCloseInterestCalculationStrategy, final Account[] accounts,
|
||||
final boolean isMultiTrancheLoan) {
|
||||
final boolean isMultiTrancheLoan, final Integer recalculationRestFrequencyOnDayType, final Integer recalculationRestFrequencyDayOfWeekType) {
|
||||
final String recalculationCompoundingFrequencyType = null;
|
||||
final String recalculationCompoundingFrequencyInterval = null;
|
||||
final String recalculationCompoundingFrequencyDate = null;
|
||||
final Integer recalculationCompoundingFrequencyOnDayType = null;
|
||||
final Integer recalculationCompoundingFrequencyDayOfWeekType = null;
|
||||
return createLoanProductWithInterestRecalculation(repaymentStrategy, interestRecalculationCompoundingMethod,
|
||||
rescheduleStrategyMethod, recalculationRestFrequencyType, recalculationRestFrequencyInterval,
|
||||
recalculationRestFrequencyDate, recalculationCompoundingFrequencyType, recalculationCompoundingFrequencyInterval,
|
||||
recalculationCompoundingFrequencyDate, preCloseInterestCalculationStrategy, accounts, null, false, isMultiTrancheLoan);
|
||||
recalculationCompoundingFrequencyDate, preCloseInterestCalculationStrategy, accounts, null, false, isMultiTrancheLoan,
|
||||
recalculationCompoundingFrequencyOnDayType, recalculationCompoundingFrequencyDayOfWeekType, recalculationRestFrequencyOnDayType,
|
||||
recalculationRestFrequencyDayOfWeekType);
|
||||
}
|
||||
|
||||
private Integer createLoanProductWithInterestRecalculation(final String repaymentStrategy,
|
||||
@@ -295,7 +301,10 @@ public class LoanReschedulingWithinCenterTest {
|
||||
final String recalculationRestFrequencyDate, final String recalculationCompoundingFrequencyType,
|
||||
final String recalculationCompoundingFrequencyInterval, final String recalculationCompoundingFrequencyDate,
|
||||
final String preCloseInterestCalculationStrategy, final Account[] accounts, final String chargeId,
|
||||
boolean isArrearsBasedOnOriginalSchedule, final boolean isMultiTrancheLoan) {
|
||||
boolean isArrearsBasedOnOriginalSchedule, final boolean isMultiTrancheLoan,
|
||||
final Integer recalculationCompoundingFrequencyOnDayType,
|
||||
final Integer recalculationCompoundingFrequencyDayOfWeekType, final Integer recalculationRestFrequencyOnDayType,
|
||||
final Integer recalculationRestFrequencyDayOfWeekType) {
|
||||
System.out.println("------------------------------CREATING NEW LOAN PRODUCT ---------------------------------------");
|
||||
LoanProductTestBuilder builder = new LoanProductTestBuilder()
|
||||
.withPrincipal("10000.00")
|
||||
@@ -311,9 +320,10 @@ public class LoanReschedulingWithinCenterTest {
|
||||
.withInterestRecalculationDetails(interestRecalculationCompoundingMethod, rescheduleStrategyMethod,
|
||||
preCloseInterestCalculationStrategy)
|
||||
.withInterestRecalculationRestFrequencyDetails(recalculationRestFrequencyType, recalculationRestFrequencyInterval,
|
||||
recalculationRestFrequencyDate)
|
||||
recalculationRestFrequencyOnDayType, recalculationRestFrequencyDayOfWeekType)
|
||||
.withInterestRecalculationCompoundingFrequencyDetails(recalculationCompoundingFrequencyType,
|
||||
recalculationCompoundingFrequencyInterval, recalculationCompoundingFrequencyDate);
|
||||
recalculationCompoundingFrequencyInterval, recalculationCompoundingFrequencyOnDayType,
|
||||
recalculationCompoundingFrequencyDayOfWeekType);
|
||||
if (accounts != null) {
|
||||
builder = builder.withAccountingRulePeriodicAccrual(accounts);
|
||||
}
|
||||
@@ -356,7 +366,6 @@ public class LoanReschedulingWithinCenterTest {
|
||||
.withInterestCalculationPeriodTypeAsDays() //
|
||||
.withExpectedDisbursementDate(disbursementDate) //
|
||||
.withSubmittedOnDate(disbursementDate) //
|
||||
.withRestFrequencyDate(restStartDate)//
|
||||
.withwithRepaymentStrategy(repaymentStrategy) //
|
||||
.withCharges(charges)//
|
||||
.build(clientID.toString(), groupId.toString(), loanProductID.toString(), null);
|
||||
@@ -389,4 +398,5 @@ public class LoanReschedulingWithinCenterTest {
|
||||
date.add(type, addvalue);
|
||||
return new ArrayList<>(Arrays.asList(date.get(Calendar.YEAR), date.get(Calendar.MONTH) + 1, date.get(Calendar.DAY_OF_MONTH)));
|
||||
}
|
||||
|
||||
}
|
||||
-16
@@ -61,8 +61,6 @@ public class LoanApplicationTestBuilder {
|
||||
private List<HashMap> disbursementData = null;
|
||||
@SuppressWarnings("rawtypes")
|
||||
private List<HashMap> charges = new ArrayList<>();
|
||||
private String recalculationRestFrequencyDate = null;
|
||||
private String recalculationCompoundingFrequencyDate = null;
|
||||
private String repaymentsStartingFromDate = null;
|
||||
|
||||
private String calendarId;
|
||||
@@ -135,12 +133,6 @@ public class LoanApplicationTestBuilder {
|
||||
map.put("maxOutstandingLoanBalance", maxOutstandingLoanBalance);
|
||||
|
||||
}
|
||||
if (recalculationRestFrequencyDate != null) {
|
||||
map.put("recalculationRestFrequencyDate", recalculationRestFrequencyDate);
|
||||
}
|
||||
if (recalculationCompoundingFrequencyDate != null) {
|
||||
map.put("recalculationCompoundingFrequencyDate", recalculationCompoundingFrequencyDate);
|
||||
}
|
||||
|
||||
System.out.println("Loan Application request : " + map);
|
||||
return new Gson().toJson(map);
|
||||
@@ -281,15 +273,7 @@ public class LoanApplicationTestBuilder {
|
||||
return this;
|
||||
}
|
||||
|
||||
public LoanApplicationTestBuilder withRestFrequencyDate(final String recalculationRestFrequencyDate) {
|
||||
this.recalculationRestFrequencyDate = recalculationRestFrequencyDate;
|
||||
return this;
|
||||
}
|
||||
|
||||
public LoanApplicationTestBuilder withCompoundingFrequencyDate(final String recalculationCompoundingFrequencyDate) {
|
||||
this.recalculationCompoundingFrequencyDate = recalculationCompoundingFrequencyDate;
|
||||
return this;
|
||||
}
|
||||
|
||||
public LoanApplicationTestBuilder withFirstRepaymentDate(final String firstRepaymentDate) {
|
||||
this.repaymentsStartingFromDate = firstRepaymentDate;
|
||||
|
||||
+16
-8
@@ -104,10 +104,8 @@ public class LoanProductTestBuilder {
|
||||
private String rescheduleStrategyMethod = "1";
|
||||
private String recalculationRestFrequencyType = "1";
|
||||
private String recalculationRestFrequencyInterval = "0";
|
||||
private String recalculationRestFrequencyDate = null;
|
||||
private String recalculationCompoundingFrequencyType = null;
|
||||
private String recalculationCompoundingFrequencyInterval = null;
|
||||
private String recalculationCompoundingFrequencyDate = null;
|
||||
private String minimumDaysBetweenDisbursalAndFirstRepayment = null;
|
||||
private Boolean holdGuaranteeFunds = null;
|
||||
private String mandatoryGuarantee = null;
|
||||
@@ -122,6 +120,10 @@ public class LoanProductTestBuilder {
|
||||
private Boolean allowVariableInstallments = Boolean.FALSE;
|
||||
private Integer minimumGap;
|
||||
private Integer maximumGap;
|
||||
private Integer recalculationCompoundingFrequencyOnDayType = null;
|
||||
private Integer recalculationRestFrequencyOnDayType = null;
|
||||
private Integer recalculationCompoundingFrequencyDayOfWeekType = null;
|
||||
private Integer recalculationRestFrequencyDayOfWeekType = null;
|
||||
|
||||
public String build(final String chargeId) {
|
||||
final HashMap<String, Object> map = new HashMap<>();
|
||||
@@ -177,16 +179,18 @@ public class LoanProductTestBuilder {
|
||||
map.put("rescheduleStrategyMethod", this.rescheduleStrategyMethod);
|
||||
map.put("recalculationRestFrequencyType", recalculationRestFrequencyType);
|
||||
map.put("recalculationRestFrequencyInterval", recalculationRestFrequencyInterval);
|
||||
map.put("recalculationRestFrequencyDate", recalculationRestFrequencyDate);
|
||||
if (!RECALCULATION_COMPOUNDING_METHOD_NONE.equals(this.interestRecalculationCompoundingMethod)) {
|
||||
map.put("recalculationCompoundingFrequencyType", recalculationCompoundingFrequencyType);
|
||||
map.put("recalculationCompoundingFrequencyInterval", recalculationCompoundingFrequencyInterval);
|
||||
map.put("recalculationCompoundingFrequencyDate", recalculationCompoundingFrequencyDate);
|
||||
}
|
||||
map.put("preClosureInterestCalculationStrategy", preCloseInterestCalculationStrategy);
|
||||
if (isArrearsBasedOnOriginalSchedule != null) {
|
||||
map.put("isArrearsBasedOnOriginalSchedule", isArrearsBasedOnOriginalSchedule);
|
||||
}
|
||||
map.put("recalculationCompoundingFrequencyOnDayType", this.recalculationCompoundingFrequencyOnDayType);
|
||||
map.put("recalculationCompoundingFrequencyDayOfWeekType", this.recalculationCompoundingFrequencyDayOfWeekType);
|
||||
map.put("recalculationRestFrequencyOnDayType", this.recalculationRestFrequencyOnDayType);
|
||||
map.put("recalculationRestFrequencyDayOfWeekType", this.recalculationRestFrequencyDayOfWeekType);
|
||||
}
|
||||
if (holdGuaranteeFunds != null) {
|
||||
map.put("holdGuaranteeFunds", this.holdGuaranteeFunds);
|
||||
@@ -437,20 +441,24 @@ public class LoanProductTestBuilder {
|
||||
}
|
||||
|
||||
public LoanProductTestBuilder withInterestRecalculationRestFrequencyDetails(final String recalculationRestFrequencyType,
|
||||
final String recalculationRestFrequencyInterval, final String recalculationRestFrequencyDate) {
|
||||
final String recalculationRestFrequencyInterval, final Integer recalculationRestFrequencyOnDayType,
|
||||
final Integer recalculationRestFrequencyDayOfWeekType) {
|
||||
this.isInterestRecalculationEnabled = true;
|
||||
this.recalculationRestFrequencyType = recalculationRestFrequencyType;
|
||||
this.recalculationRestFrequencyInterval = recalculationRestFrequencyInterval;
|
||||
this.recalculationRestFrequencyDate = recalculationRestFrequencyDate;
|
||||
this.recalculationRestFrequencyOnDayType = recalculationRestFrequencyOnDayType;
|
||||
this.recalculationRestFrequencyDayOfWeekType = recalculationRestFrequencyDayOfWeekType;
|
||||
return this;
|
||||
}
|
||||
|
||||
public LoanProductTestBuilder withInterestRecalculationCompoundingFrequencyDetails(final String recalculationCompoundingFrequencyType,
|
||||
final String recalculationCompoundingFrequencyInterval, final String recalculationCompoundingFrequencyDate) {
|
||||
final String recalculationCompoundingFrequencyInterval, final Integer recalculationCompoundingFrequencyOnDayType,
|
||||
final Integer recalculationCompoundingFrequencyDayOfWeekType) {
|
||||
this.isInterestRecalculationEnabled = true;
|
||||
this.recalculationCompoundingFrequencyType = recalculationCompoundingFrequencyType;
|
||||
this.recalculationCompoundingFrequencyInterval = recalculationCompoundingFrequencyInterval;
|
||||
this.recalculationCompoundingFrequencyDate = recalculationCompoundingFrequencyDate;
|
||||
this.recalculationCompoundingFrequencyOnDayType = recalculationCompoundingFrequencyOnDayType;
|
||||
this.recalculationCompoundingFrequencyDayOfWeekType = recalculationCompoundingFrequencyDayOfWeekType;
|
||||
return this;
|
||||
}
|
||||
|
||||
|
||||
+3
@@ -173,6 +173,9 @@ public class JournalEntry extends AbstractAuditableCustom<AppUser, Long> {
|
||||
return this.amount;
|
||||
}
|
||||
|
||||
public void setAmount(BigDecimal amount) {
|
||||
this.amount = amount;
|
||||
}
|
||||
public void setReversalJournalEntry(final JournalEntry reversalJournalEntry) {
|
||||
this.reversalJournalEntry = reversalJournalEntry;
|
||||
}
|
||||
|
||||
+9
-3
@@ -18,6 +18,7 @@
|
||||
*/
|
||||
package org.apache.fineract.accounting.journalentry.domain;
|
||||
|
||||
import java.util.Date;
|
||||
import java.util.List;
|
||||
|
||||
import org.springframework.data.jpa.repository.JpaRepository;
|
||||
@@ -39,8 +40,13 @@ public interface JournalEntryRepository extends JpaRepository<JournalEntry, Long
|
||||
|
||||
@Query("from JournalEntry journalEntry where journalEntry.entityId= :entityId and journalEntry.entityType = :entityType")
|
||||
List<JournalEntry> findProvisioningJournalEntriesByEntityId(@Param("entityId") Long entityId, @Param("entityType") Integer entityType) ;
|
||||
|
||||
|
||||
@Query("from JournalEntry journalEntry where journalEntry.transactionId= :transactionId and journalEntry.reversed is false and journalEntry.entityType = :entityType")
|
||||
List<JournalEntry> findJournalEntries(@Param("transactionId") String transactionId, @Param("entityType") Integer entityType) ;
|
||||
|
||||
List<JournalEntry> findJournalEntries(@Param("transactionId") String transactionId, @Param("entityType") Integer entityType);
|
||||
|
||||
@Query("from JournalEntry journalEntry where glAccount.id= :accountId and transactionId= :transactionId and transactionDate= :transactionDate"
|
||||
+ " and type= :journalEntryType and entityType=1 and entityId= :loanId and loanTransaction.id= :loanTransactionId")
|
||||
JournalEntry findLOANJournalEntryWith(@Param("accountId") Long accountId, @Param("transactionId") String transactionId,
|
||||
@Param("transactionDate") Date transactionDate, @Param("journalEntryType") Integer journalEntryType,
|
||||
@Param("loanId") Long loanId, @Param("loanTransactionId") Long loanTransactionId);
|
||||
}
|
||||
|
||||
+7
-1
@@ -781,6 +781,12 @@ public class AccountingProcessorHelper {
|
||||
final Long loanProductId, final Long paymentTypeId, final Long loanId, final String transactionId, final Date transactionDate,
|
||||
final BigDecimal amount, final Boolean isReversal) {
|
||||
final GLAccount account = getLinkedGLAccountForLoanProduct(loanProductId, accountMappingTypeId, paymentTypeId);
|
||||
createCreditJournalEntryOrReversalForLoan(office, currencyCode, loanId, transactionId, transactionDate, amount, isReversal, account);
|
||||
}
|
||||
|
||||
public void createCreditJournalEntryOrReversalForLoan(final Office office, final String currencyCode, final Long loanId,
|
||||
final String transactionId, final Date transactionDate, final BigDecimal amount, final Boolean isReversal,
|
||||
final GLAccount account) {
|
||||
if (isReversal) {
|
||||
createDebitJournalEntryForLoan(office, currencyCode, account, loanId, transactionId, transactionDate, amount);
|
||||
} else {
|
||||
@@ -1070,7 +1076,7 @@ public class AccountingProcessorHelper {
|
||||
this.glJournalEntryRepository.save(journalEntry);
|
||||
}
|
||||
|
||||
private GLAccount getLinkedGLAccountForLoanProduct(final Long loanProductId, final int accountMappingTypeId, final Long paymentTypeId) {
|
||||
public GLAccount getLinkedGLAccountForLoanProduct(final Long loanProductId, final int accountMappingTypeId, final Long paymentTypeId) {
|
||||
GLAccount glAccount = null;
|
||||
if (isOrganizationAccount(accountMappingTypeId)) {
|
||||
FinancialActivityAccount financialActivityAccount = this.financialActivityAccountRepository
|
||||
|
||||
+80
-31
@@ -21,12 +21,16 @@ package org.apache.fineract.accounting.journalentry.service;
|
||||
import java.math.BigDecimal;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Date;
|
||||
import java.util.HashMap;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.Map.Entry;
|
||||
|
||||
import org.apache.fineract.accounting.closure.domain.GLClosure;
|
||||
import org.apache.fineract.accounting.common.AccountingConstants.ACCRUAL_ACCOUNTS_FOR_LOAN;
|
||||
import org.apache.fineract.accounting.common.AccountingConstants.CASH_ACCOUNTS_FOR_LOAN;
|
||||
import org.apache.fineract.accounting.common.AccountingConstants.FINANCIAL_ACTIVITY;
|
||||
import org.apache.fineract.accounting.glaccount.domain.GLAccount;
|
||||
import org.apache.fineract.accounting.journalentry.data.ChargePaymentDTO;
|
||||
import org.apache.fineract.accounting.journalentry.data.LoanDTO;
|
||||
import org.apache.fineract.accounting.journalentry.data.LoanTransactionDTO;
|
||||
@@ -88,7 +92,7 @@ public class AccrualBasedAccountingProcessorForLoan implements AccountingProcess
|
||||
.getTransactionType().isWaiveCharges())) {
|
||||
createJournalEntriesForRepaymentsAndWriteOffs(loanDTO, loanTransactionDTO, office, true, false);
|
||||
}
|
||||
|
||||
|
||||
/** Logic for Refunds of Active Loans **/
|
||||
else if (loanTransactionDTO.getTransactionType().isRefundForActiveLoans()) {
|
||||
createJournalEntriesForRefundForActiveLoan(loanDTO, loanTransactionDTO, office);
|
||||
@@ -193,18 +197,27 @@ public class AccrualBasedAccountingProcessorForLoan implements AccountingProcess
|
||||
|
||||
BigDecimal totalDebitAmount = new BigDecimal(0);
|
||||
|
||||
Map<GLAccount, BigDecimal> accountMap = new HashMap<>();
|
||||
|
||||
// handle principal payment or writeOff (and reversals)
|
||||
if (principalAmount != null && !(principalAmount.compareTo(BigDecimal.ZERO) == 0)) {
|
||||
totalDebitAmount = totalDebitAmount.add(principalAmount);
|
||||
this.helper.createCreditJournalEntryOrReversalForLoan(office, currencyCode, ACCRUAL_ACCOUNTS_FOR_LOAN.LOAN_PORTFOLIO,
|
||||
loanProductId, paymentTypeId, loanId, transactionId, transactionDate, principalAmount, isReversal);
|
||||
GLAccount account = this.helper.getLinkedGLAccountForLoanProduct(loanProductId,
|
||||
ACCRUAL_ACCOUNTS_FOR_LOAN.LOAN_PORTFOLIO.getValue(), paymentTypeId);
|
||||
accountMap.put(account, principalAmount);
|
||||
}
|
||||
|
||||
// handle interest payment of writeOff (and reversals)
|
||||
if (interestAmount != null && !(interestAmount.compareTo(BigDecimal.ZERO) == 0)) {
|
||||
totalDebitAmount = totalDebitAmount.add(interestAmount);
|
||||
this.helper.createCreditJournalEntryOrReversalForLoan(office, currencyCode, ACCRUAL_ACCOUNTS_FOR_LOAN.INTEREST_RECEIVABLE,
|
||||
loanProductId, paymentTypeId, loanId, transactionId, transactionDate, interestAmount, isReversal);
|
||||
GLAccount account = this.helper.getLinkedGLAccountForLoanProduct(loanProductId,
|
||||
ACCRUAL_ACCOUNTS_FOR_LOAN.INTEREST_RECEIVABLE.getValue(), paymentTypeId);
|
||||
if (accountMap.containsKey(account)) {
|
||||
BigDecimal amount = accountMap.get(account).add(interestAmount);
|
||||
accountMap.put(account, amount);
|
||||
} else {
|
||||
accountMap.put(account, interestAmount);
|
||||
}
|
||||
}
|
||||
|
||||
// handle fees payment of writeOff (and reversals)
|
||||
@@ -212,12 +225,23 @@ public class AccrualBasedAccountingProcessorForLoan implements AccountingProcess
|
||||
totalDebitAmount = totalDebitAmount.add(feesAmount);
|
||||
|
||||
if (isIncomeFromFee) {
|
||||
this.helper.createCreditJournalEntryOrReversalForLoanCharges(office, currencyCode,
|
||||
ACCRUAL_ACCOUNTS_FOR_LOAN.INCOME_FROM_FEES.getValue(), loanProductId, loanId, transactionId, transactionDate,
|
||||
feesAmount, isReversal, loanTransactionDTO.getFeePayments());
|
||||
GLAccount account = this.helper.getLinkedGLAccountForLoanProduct(loanProductId,
|
||||
ACCRUAL_ACCOUNTS_FOR_LOAN.INCOME_FROM_FEES.getValue(), paymentTypeId);
|
||||
if (accountMap.containsKey(account)) {
|
||||
BigDecimal amount = accountMap.get(account).add(feesAmount);
|
||||
accountMap.put(account, amount);
|
||||
} else {
|
||||
accountMap.put(account, feesAmount);
|
||||
}
|
||||
} else {
|
||||
this.helper.createCreditJournalEntryOrReversalForLoan(office, currencyCode, ACCRUAL_ACCOUNTS_FOR_LOAN.FEES_RECEIVABLE,
|
||||
loanProductId, paymentTypeId, loanId, transactionId, transactionDate, feesAmount, isReversal);
|
||||
GLAccount account = this.helper.getLinkedGLAccountForLoanProduct(loanProductId,
|
||||
ACCRUAL_ACCOUNTS_FOR_LOAN.FEES_RECEIVABLE.getValue(), paymentTypeId);
|
||||
if (accountMap.containsKey(account)) {
|
||||
BigDecimal amount = accountMap.get(account).add(feesAmount);
|
||||
accountMap.put(account, amount);
|
||||
} else {
|
||||
accountMap.put(account, feesAmount);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -225,19 +249,41 @@ public class AccrualBasedAccountingProcessorForLoan implements AccountingProcess
|
||||
if (penaltiesAmount != null && !(penaltiesAmount.compareTo(BigDecimal.ZERO) == 0)) {
|
||||
totalDebitAmount = totalDebitAmount.add(penaltiesAmount);
|
||||
if (isIncomeFromFee) {
|
||||
this.helper.createCreditJournalEntryOrReversalForLoanCharges(office, currencyCode,
|
||||
ACCRUAL_ACCOUNTS_FOR_LOAN.INCOME_FROM_PENALTIES.getValue(), loanProductId, loanId, transactionId, transactionDate,
|
||||
penaltiesAmount, isReversal, loanTransactionDTO.getPenaltyPayments());
|
||||
GLAccount account = this.helper.getLinkedGLAccountForLoanProduct(loanProductId,
|
||||
ACCRUAL_ACCOUNTS_FOR_LOAN.INCOME_FROM_PENALTIES.getValue(), paymentTypeId);
|
||||
if (accountMap.containsKey(account)) {
|
||||
BigDecimal amount = accountMap.get(account).add(penaltiesAmount);
|
||||
accountMap.put(account, amount);
|
||||
} else {
|
||||
accountMap.put(account, penaltiesAmount);
|
||||
}
|
||||
} else {
|
||||
this.helper.createCreditJournalEntryOrReversalForLoan(office, currencyCode, ACCRUAL_ACCOUNTS_FOR_LOAN.PENALTIES_RECEIVABLE,
|
||||
loanProductId, paymentTypeId, loanId, transactionId, transactionDate, penaltiesAmount, isReversal);
|
||||
GLAccount account = this.helper.getLinkedGLAccountForLoanProduct(loanProductId,
|
||||
ACCRUAL_ACCOUNTS_FOR_LOAN.PENALTIES_RECEIVABLE.getValue(), paymentTypeId);
|
||||
if (accountMap.containsKey(account)) {
|
||||
BigDecimal amount = accountMap.get(account).add(penaltiesAmount);
|
||||
accountMap.put(account, amount);
|
||||
} else {
|
||||
accountMap.put(account, penaltiesAmount);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
if (overPaymentAmount != null && !(overPaymentAmount.compareTo(BigDecimal.ZERO) == 0)) {
|
||||
totalDebitAmount = totalDebitAmount.add(overPaymentAmount);
|
||||
this.helper.createCreditJournalEntryOrReversalForLoan(office, currencyCode, ACCRUAL_ACCOUNTS_FOR_LOAN.OVERPAYMENT, loanProductId,
|
||||
paymentTypeId, loanId, transactionId, transactionDate, overPaymentAmount, isReversal);
|
||||
GLAccount account = this.helper.getLinkedGLAccountForLoanProduct(loanProductId,
|
||||
ACCRUAL_ACCOUNTS_FOR_LOAN.OVERPAYMENT.getValue(), paymentTypeId);
|
||||
if (accountMap.containsKey(account)) {
|
||||
BigDecimal amount = accountMap.get(account).add(overPaymentAmount);
|
||||
accountMap.put(account, amount);
|
||||
} else {
|
||||
accountMap.put(account, overPaymentAmount);
|
||||
}
|
||||
}
|
||||
|
||||
for (Entry<GLAccount, BigDecimal> entry : accountMap.entrySet()) {
|
||||
this.helper.createCreditJournalEntryOrReversalForLoan(office, currencyCode, loanId, transactionId, transactionDate,
|
||||
entry.getValue(), isReversal, entry.getKey());
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -367,6 +413,7 @@ public class AccrualBasedAccountingProcessorForLoan implements AccountingProcess
|
||||
paymentTypeId, loanId, transactionId, transactionDate, refundAmount, isReversal);
|
||||
}
|
||||
}
|
||||
|
||||
private void createJournalEntriesForRefundForActiveLoan(LoanDTO loanDTO, LoanTransactionDTO loanTransactionDTO, Office office) {
|
||||
// TODO Auto-generated method stub
|
||||
// loan properties
|
||||
@@ -401,12 +448,13 @@ public class AccrualBasedAccountingProcessorForLoan implements AccountingProcess
|
||||
|
||||
if (feesAmount != null && !(feesAmount.compareTo(BigDecimal.ZERO) == 0)) {
|
||||
totalDebitAmount = totalDebitAmount.add(feesAmount);
|
||||
|
||||
|
||||
List<ChargePaymentDTO> chargePaymentDTOs = new ArrayList<>();
|
||||
|
||||
for(ChargePaymentDTO chargePaymentDTO : loanTransactionDTO.getFeePayments()) {
|
||||
chargePaymentDTOs.add(new ChargePaymentDTO(chargePaymentDTO.getChargeId(), chargePaymentDTO.getLoanChargeId(),
|
||||
chargePaymentDTO.getAmount().floatValue() < 0 ? chargePaymentDTO.getAmount().multiply(new BigDecimal(-1)):chargePaymentDTO.getAmount() ));
|
||||
|
||||
for (ChargePaymentDTO chargePaymentDTO : loanTransactionDTO.getFeePayments()) {
|
||||
chargePaymentDTOs.add(new ChargePaymentDTO(chargePaymentDTO.getChargeId(), chargePaymentDTO.getLoanChargeId(),
|
||||
chargePaymentDTO.getAmount().floatValue() < 0 ? chargePaymentDTO.getAmount().multiply(new BigDecimal(-1))
|
||||
: chargePaymentDTO.getAmount()));
|
||||
}
|
||||
this.helper.createCreditJournalEntryOrReversalForLoanCharges(office, currencyCode,
|
||||
CASH_ACCOUNTS_FOR_LOAN.INCOME_FROM_FEES.getValue(), loanProductId, loanId, transactionId, transactionDate, feesAmount,
|
||||
@@ -416,12 +464,13 @@ public class AccrualBasedAccountingProcessorForLoan implements AccountingProcess
|
||||
if (penaltiesAmount != null && !(penaltiesAmount.compareTo(BigDecimal.ZERO) == 0)) {
|
||||
totalDebitAmount = totalDebitAmount.add(penaltiesAmount);
|
||||
List<ChargePaymentDTO> chargePaymentDTOs = new ArrayList<>();
|
||||
|
||||
for(ChargePaymentDTO chargePaymentDTO : loanTransactionDTO.getPenaltyPayments()) {
|
||||
chargePaymentDTOs.add(new ChargePaymentDTO(chargePaymentDTO.getChargeId(), chargePaymentDTO.getLoanChargeId(),
|
||||
chargePaymentDTO.getAmount().floatValue() < 0 ? chargePaymentDTO.getAmount().multiply(new BigDecimal(-1)):chargePaymentDTO.getAmount() ));
|
||||
|
||||
for (ChargePaymentDTO chargePaymentDTO : loanTransactionDTO.getPenaltyPayments()) {
|
||||
chargePaymentDTOs.add(new ChargePaymentDTO(chargePaymentDTO.getChargeId(), chargePaymentDTO.getLoanChargeId(),
|
||||
chargePaymentDTO.getAmount().floatValue() < 0 ? chargePaymentDTO.getAmount().multiply(new BigDecimal(-1))
|
||||
: chargePaymentDTO.getAmount()));
|
||||
}
|
||||
|
||||
|
||||
this.helper.createCreditJournalEntryOrReversalForLoanCharges(office, currencyCode,
|
||||
CASH_ACCOUNTS_FOR_LOAN.INCOME_FROM_PENALTIES.getValue(), loanProductId, loanId, transactionId, transactionDate,
|
||||
penaltiesAmount, !isReversal, chargePaymentDTOs);
|
||||
@@ -434,8 +483,8 @@ public class AccrualBasedAccountingProcessorForLoan implements AccountingProcess
|
||||
}
|
||||
|
||||
/*** create a single debit entry (or reversal) for the entire amount **/
|
||||
this.helper.createDebitJournalEntryOrReversalForLoan(office, currencyCode, CASH_ACCOUNTS_FOR_LOAN.FUND_SOURCE.getValue(), loanProductId,
|
||||
paymentTypeId, loanId, transactionId, transactionDate, totalDebitAmount, !isReversal);
|
||||
|
||||
this.helper.createDebitJournalEntryOrReversalForLoan(office, currencyCode, CASH_ACCOUNTS_FOR_LOAN.FUND_SOURCE.getValue(),
|
||||
loanProductId, paymentTypeId, loanId, transactionId, transactionDate, totalDebitAmount, !isReversal);
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
+3
-2
@@ -39,8 +39,9 @@ public enum JobName {
|
||||
RECALCULATE_INTEREST_FOR_LOAN("Recalculate Interest For Loans"), //
|
||||
GENERATE_RD_SCEHDULE("Generate Mandatory Savings Schedule"), //
|
||||
GENERATE_LOANLOSS_PROVISIONING("Generate Loan Loss Provisioning"), //
|
||||
POST_DIVIDENTS_FOR_SHARES("Post Dividends For Shares"),
|
||||
UPDATE_SAVINGS_DORMANT_ACCOUNTS("Update Savings Dormant Accounts");
|
||||
POST_DIVIDENTS_FOR_SHARES("Post Dividends For Shares"), //
|
||||
UPDATE_SAVINGS_DORMANT_ACCOUNTS("Update Savings Dormant Accounts"), //
|
||||
ADD_PERIODIC_ACCRUAL_ENTRIES_FOR_LOANS_WITH_INCOME_POSTED_AS_TRANSACTIONS("Add Accrual Transactions For Loans With Income Posted As Transactions");
|
||||
|
||||
private final String name;
|
||||
|
||||
|
||||
+2
-1
@@ -31,7 +31,8 @@ public class CalendarConstants {
|
||||
"typeId"), REPEATING("repeating"), REMIND_BY_ID("remindById"), FIRST_REMINDER("firstReminder"), SECOND_REMINDER(
|
||||
"secondReminder"), LOCALE("locale"), DATE_FORMAT("dateFormat"), FREQUENCY("frequency"), INTERVAL("interval"), REPEATS_ON_DAY(
|
||||
"repeatsOnDay"), RESCHEDULE_BASED_ON_MEETING_DATES("reschedulebasedOnMeetingDates"), PRESENT_MEETING_DATE(
|
||||
"presentMeetingDate"), NEW_MEETING_DATE("newMeetingDate"),MEETING_TIME("meetingtime"),Time_Format("timeFormat"), ;
|
||||
"presentMeetingDate"), NEW_MEETING_DATE("newMeetingDate"),MEETING_TIME("meetingtime"),Time_Format("timeFormat"), REPEATS_ON_NTH_DAY_OF_MONTH("repeatsOnNthDayOfMonth"),
|
||||
REPEATS_ON_LAST_WEEKDAY_OF_MONTH("repeatsOnLastWeekdayOfMonth"), REPEATS_ON_DAY_OF_MONTH("repeatsOnDayOfMonth");
|
||||
|
||||
private final String value;
|
||||
|
||||
|
||||
+2
-1
@@ -230,8 +230,9 @@ public class CalendarsApiResource {
|
||||
final List<EnumOptionData> remindByOptions = this.dropdownReadPlatformService.retrieveCalendarRemindByOptions();
|
||||
final List<EnumOptionData> frequencyOptions = this.dropdownReadPlatformService.retrieveCalendarFrequencyTypeOptions();
|
||||
final List<EnumOptionData> repeatsOnDayOptions = this.dropdownReadPlatformService.retrieveCalendarWeekDaysTypeOptions();
|
||||
final List<EnumOptionData> frequencyNthDayTypeOptions = this.dropdownReadPlatformService.retrieveCalendarFrequencyNthDayTypeOptions();
|
||||
return CalendarData.withTemplateOptions(calendarData, entityTypeOptions, calendarTypeOptions, remindByOptions, frequencyOptions,
|
||||
repeatsOnDayOptions);
|
||||
repeatsOnDayOptions, frequencyNthDayTypeOptions);
|
||||
}
|
||||
|
||||
private CommandWrapper getResourceDetails(final CalendarEntityType type, final Long entityId) {
|
||||
|
||||
+54
-30
@@ -28,6 +28,7 @@ import org.apache.fineract.portfolio.calendar.domain.CalendarType;
|
||||
import org.apache.fineract.portfolio.calendar.domain.CalendarWeekDaysType;
|
||||
import org.apache.fineract.portfolio.calendar.service.CalendarEnumerations;
|
||||
import org.apache.fineract.portfolio.calendar.service.CalendarUtils;
|
||||
import org.apache.fineract.portfolio.common.domain.NthDayType;
|
||||
import org.joda.time.LocalDate;
|
||||
import org.joda.time.LocalTime;
|
||||
|
||||
@@ -53,6 +54,7 @@ public class CalendarData {
|
||||
private final EnumOptionData frequency;
|
||||
private final Integer interval;
|
||||
private final EnumOptionData repeatsOnDay;
|
||||
private final EnumOptionData repeatsOnNthDayOfMonth;
|
||||
private final EnumOptionData remindBy;
|
||||
private final Integer firstReminder;
|
||||
private final Integer secondReminder;
|
||||
@@ -67,20 +69,24 @@ public class CalendarData {
|
||||
private final String createdByUsername;
|
||||
private final Long lastUpdatedByUserId;
|
||||
private final String lastUpdatedByUsername;
|
||||
private final Integer repeatsOnDayOfMonth;
|
||||
|
||||
// template related
|
||||
final List<EnumOptionData> entityTypeOptions;
|
||||
final List<EnumOptionData> calendarTypeOptions;
|
||||
final List<EnumOptionData> remindByOptions;
|
||||
final List<EnumOptionData> frequencyOptions;
|
||||
final List<EnumOptionData> repeatsOnDayOptions;
|
||||
final List<EnumOptionData> frequencyNthDayTypeOptions;
|
||||
|
||||
public static CalendarData instance(final Long id, final Long calendarInstanceId, final Long entityId, final EnumOptionData entityType,
|
||||
final String title, final String description, final String location, final LocalDate startDate, final LocalDate endDate,
|
||||
final Integer duration, final EnumOptionData type, final boolean repeating, final String recurrence,
|
||||
final EnumOptionData frequency, final Integer interval, final EnumOptionData repeatsOnDay, final EnumOptionData remindBy,
|
||||
final Integer firstReminder, final Integer secondReminder, final String humanReadable, final LocalDate createdDate,
|
||||
final LocalDate lastUpdatedDate, final Long createdByUserId, final String createdByUsername, final Long lastUpdatedByUserId,
|
||||
final String lastUpdatedByUsername, final LocalTime meetingTime) {
|
||||
final EnumOptionData frequency, final Integer interval, final EnumOptionData repeatsOnDay,
|
||||
final EnumOptionData repeatsOnNthDayOfMonth, final EnumOptionData remindBy, final Integer firstReminder,
|
||||
final Integer secondReminder, final String humanReadable, final LocalDate createdDate, final LocalDate lastUpdatedDate,
|
||||
final Long createdByUserId, final String createdByUsername, final Long lastUpdatedByUserId, final String lastUpdatedByUsername,
|
||||
final LocalTime meetingTime, final Integer repeatsOnDayOfMonth) {
|
||||
|
||||
final Collection<LocalDate> recurringDates = null;
|
||||
final Collection<LocalDate> nextTenRecurringDates = null;
|
||||
@@ -91,12 +97,14 @@ public class CalendarData {
|
||||
final List<EnumOptionData> remindByOptions = null;
|
||||
final List<EnumOptionData> frequencyOptions = null;
|
||||
final List<EnumOptionData> repeatsOnDayOptions = null;
|
||||
final List<EnumOptionData> frequencyNthDayTypeOptions = null;
|
||||
|
||||
return new CalendarData(id, calendarInstanceId, entityId, entityType, title, description, location, startDate, endDate, duration,
|
||||
type, repeating, recurrence, frequency, interval, repeatsOnDay, remindBy, firstReminder, secondReminder, recurringDates,
|
||||
nextTenRecurringDates, humanReadable, recentEligibleMeetingDate, createdDate, lastUpdatedDate, createdByUserId,
|
||||
createdByUsername, lastUpdatedByUserId, lastUpdatedByUsername, entityTypeOptions, calendarTypeOptions, remindByOptions,
|
||||
frequencyOptions, repeatsOnDayOptions, meetingTime);
|
||||
type, repeating, recurrence, frequency, interval, repeatsOnDay, repeatsOnNthDayOfMonth, remindBy, firstReminder,
|
||||
secondReminder, recurringDates, nextTenRecurringDates, humanReadable, recentEligibleMeetingDate, createdDate,
|
||||
lastUpdatedDate, createdByUserId, createdByUsername, lastUpdatedByUserId, lastUpdatedByUsername, repeatsOnDayOfMonth,
|
||||
entityTypeOptions, calendarTypeOptions, remindByOptions, frequencyOptions, repeatsOnDayOptions, meetingTime,
|
||||
frequencyNthDayTypeOptions);
|
||||
}
|
||||
|
||||
public static CalendarData withRecurringDates(final CalendarData calendarData, final Collection<LocalDate> recurringDates,
|
||||
@@ -104,24 +112,24 @@ public class CalendarData {
|
||||
return new CalendarData(calendarData.id, calendarData.calendarInstanceId, calendarData.entityId, calendarData.entityType,
|
||||
calendarData.title, calendarData.description, calendarData.location, calendarData.startDate, calendarData.endDate,
|
||||
calendarData.duration, calendarData.type, calendarData.repeating, calendarData.recurrence, calendarData.frequency,
|
||||
calendarData.interval, calendarData.repeatsOnDay, calendarData.remindBy, calendarData.firstReminder,
|
||||
calendarData.interval, calendarData.repeatsOnDay, calendarData.repeatsOnNthDayOfMonth, calendarData.remindBy, calendarData.firstReminder,
|
||||
calendarData.secondReminder, recurringDates, nextTenRecurringDates, calendarData.humanReadable, recentEligibleMeetingDate,
|
||||
calendarData.createdDate, calendarData.lastUpdatedDate, calendarData.createdByUserId, calendarData.createdByUsername,
|
||||
calendarData.lastUpdatedByUserId, calendarData.lastUpdatedByUsername, calendarData.entityTypeOptions,
|
||||
calendarData.lastUpdatedByUserId, calendarData.lastUpdatedByUsername, calendarData.repeatsOnDayOfMonth, calendarData.entityTypeOptions,
|
||||
calendarData.calendarTypeOptions, calendarData.remindByOptions, calendarData.frequencyOptions,
|
||||
calendarData.repeatsOnDayOptions,calendarData.meetingTime);
|
||||
calendarData.repeatsOnDayOptions, calendarData.meetingTime, calendarData.frequencyNthDayTypeOptions);
|
||||
}
|
||||
|
||||
public static CalendarData withRecentEligibleMeetingDate(final CalendarData calendarData, final LocalDate recentEligibleMeetingDate) {
|
||||
return new CalendarData(calendarData.id, calendarData.calendarInstanceId, calendarData.entityId, calendarData.entityType,
|
||||
calendarData.title, calendarData.description, calendarData.location, calendarData.startDate, calendarData.endDate,
|
||||
calendarData.duration, calendarData.type, calendarData.repeating, calendarData.recurrence, calendarData.frequency,
|
||||
calendarData.interval, calendarData.repeatsOnDay, calendarData.remindBy, calendarData.firstReminder,
|
||||
calendarData.interval, calendarData.repeatsOnDay, calendarData.repeatsOnNthDayOfMonth, calendarData.remindBy, calendarData.firstReminder,
|
||||
calendarData.secondReminder, calendarData.recurringDates, calendarData.nextTenRecurringDates, calendarData.humanReadable,
|
||||
recentEligibleMeetingDate, calendarData.createdDate, calendarData.lastUpdatedDate, calendarData.createdByUserId,
|
||||
calendarData.createdByUsername, calendarData.lastUpdatedByUserId, calendarData.lastUpdatedByUsername,
|
||||
calendarData.entityTypeOptions, calendarData.calendarTypeOptions, calendarData.remindByOptions,
|
||||
calendarData.frequencyOptions, calendarData.repeatsOnDayOptions,calendarData.meetingTime);
|
||||
calendarData.repeatsOnDayOfMonth, calendarData.entityTypeOptions, calendarData.calendarTypeOptions, calendarData.remindByOptions,
|
||||
calendarData.frequencyOptions, calendarData.repeatsOnDayOptions,calendarData.meetingTime, calendarData.frequencyNthDayTypeOptions);
|
||||
}
|
||||
|
||||
public static CalendarData sensibleDefaultsForNewCalendarCreation() {
|
||||
@@ -141,6 +149,7 @@ public class CalendarData {
|
||||
final EnumOptionData frequency = CalendarEnumerations.calendarFrequencyType(CalendarFrequencyType.DAILY);
|
||||
final Integer interval = new Integer(1);
|
||||
final EnumOptionData repeatsOnDay = CalendarEnumerations.calendarWeekDaysType(CalendarWeekDaysType.MO);
|
||||
final EnumOptionData repeatsOnNthDayOfMonth = CalendarEnumerations.calendarFrequencyNthDayType(NthDayType.ONE);
|
||||
final EnumOptionData remindBy = CalendarEnumerations.calendarRemindBy(CalendarRemindBy.EMAIL);
|
||||
final Integer firstReminder = new Integer(0);
|
||||
final Integer secondReminder = new Integer(0);
|
||||
@@ -154,6 +163,7 @@ public class CalendarData {
|
||||
final List<EnumOptionData> remindByOptions = null;
|
||||
final List<EnumOptionData> frequencyOptions = null;
|
||||
final List<EnumOptionData> repeatsOnDayOptions = null;
|
||||
final List<EnumOptionData> frequencyNthDayTypeOptions = null;
|
||||
|
||||
final LocalDate createdDate = null;
|
||||
final LocalDate lastUpdatedDate = null;
|
||||
@@ -162,39 +172,44 @@ public class CalendarData {
|
||||
final Long lastUpdatedByUserId = null;
|
||||
final String lastUpdatedByUsername = null;
|
||||
final LocalTime meetingTime = null;
|
||||
final Integer repeatsOnDayOfMonth = null;
|
||||
|
||||
return new CalendarData(id, calendarInstanceId, entityId, entityType, title, description, location, startDate, endDate, duration,
|
||||
type, repeating, recurrence, frequency, interval, repeatsOnDay, remindBy, firstReminder, secondReminder, recurringDates,
|
||||
nextTenRecurringDates, humanReadable, recentEligibleMeetingDate, createdDate, lastUpdatedDate, createdByUserId,
|
||||
createdByUsername, lastUpdatedByUserId, lastUpdatedByUsername, entityTypeOptions, calendarTypeOptions, remindByOptions,
|
||||
frequencyOptions, repeatsOnDayOptions, meetingTime);
|
||||
type, repeating, recurrence, frequency, interval, repeatsOnDay, repeatsOnNthDayOfMonth, remindBy, firstReminder,
|
||||
secondReminder, recurringDates, nextTenRecurringDates, humanReadable, recentEligibleMeetingDate, createdDate,
|
||||
lastUpdatedDate, createdByUserId, createdByUsername, lastUpdatedByUserId, lastUpdatedByUsername, repeatsOnDayOfMonth,
|
||||
entityTypeOptions, calendarTypeOptions, remindByOptions, frequencyOptions, repeatsOnDayOptions, meetingTime,
|
||||
frequencyNthDayTypeOptions);
|
||||
}
|
||||
|
||||
public static CalendarData withTemplateOptions(final CalendarData calendarData, final List<EnumOptionData> entityTypeOptions,
|
||||
final List<EnumOptionData> calendarTypeOptions, final List<EnumOptionData> remindByOptions,
|
||||
final List<EnumOptionData> repeatsOptions, final List<EnumOptionData> repeatsOnDayOptions) {
|
||||
final List<EnumOptionData> repeatsOptions, final List<EnumOptionData> repeatsOnDayOptions,
|
||||
final List<EnumOptionData> frequencyNthDayTypeOptions) {
|
||||
|
||||
return new CalendarData(calendarData.id, calendarData.calendarInstanceId, calendarData.entityId, calendarData.entityType,
|
||||
calendarData.title, calendarData.description, calendarData.location, calendarData.startDate, calendarData.endDate,
|
||||
calendarData.duration, calendarData.type, calendarData.repeating, calendarData.recurrence, calendarData.frequency,
|
||||
calendarData.interval, calendarData.repeatsOnDay, calendarData.remindBy, calendarData.firstReminder,
|
||||
calendarData.secondReminder, calendarData.recurringDates, calendarData.nextTenRecurringDates, calendarData.humanReadable,
|
||||
calendarData.recentEligibleMeetingDate, calendarData.createdDate, calendarData.lastUpdatedDate,
|
||||
calendarData.interval, calendarData.repeatsOnDay, calendarData.repeatsOnNthDayOfMonth, calendarData.remindBy,
|
||||
calendarData.firstReminder, calendarData.secondReminder, calendarData.recurringDates, calendarData.nextTenRecurringDates,
|
||||
calendarData.humanReadable, calendarData.recentEligibleMeetingDate, calendarData.createdDate, calendarData.lastUpdatedDate,
|
||||
calendarData.createdByUserId, calendarData.createdByUsername, calendarData.lastUpdatedByUserId,
|
||||
calendarData.lastUpdatedByUsername, entityTypeOptions, calendarTypeOptions, remindByOptions, repeatsOptions,
|
||||
repeatsOnDayOptions,calendarData.meetingTime);
|
||||
calendarData.lastUpdatedByUsername, calendarData.repeatsOnDayOfMonth, entityTypeOptions, calendarTypeOptions,
|
||||
remindByOptions, repeatsOptions, repeatsOnDayOptions, calendarData.meetingTime, frequencyNthDayTypeOptions);
|
||||
}
|
||||
|
||||
private CalendarData(final Long id, final Long calendarInstanceId, final Long entityId, final EnumOptionData entityType,
|
||||
final String title, final String description, final String location, final LocalDate startDate, final LocalDate endDate,
|
||||
final Integer duration, final EnumOptionData type, final boolean repeating, final String recurrence,
|
||||
final EnumOptionData frequency, final Integer interval, final EnumOptionData repeatsOnDay, final EnumOptionData remindBy,
|
||||
final Integer firstReminder, final Integer secondReminder, final Collection<LocalDate> recurringDates,
|
||||
final Collection<LocalDate> nextTenRecurringDates, final String humanReadable, final LocalDate recentEligibleMeetingDate,
|
||||
final LocalDate createdDate, final LocalDate lastUpdatedDate, final Long createdByUserId, final String createdByUsername,
|
||||
final Long lastUpdatedByUserId, final String lastUpdatedByUsername, final List<EnumOptionData> entityTypeOptions,
|
||||
final EnumOptionData frequency, final Integer interval, final EnumOptionData repeatsOnDay,
|
||||
final EnumOptionData repeatsOnNthDayOfMonth, final EnumOptionData remindBy, final Integer firstReminder,
|
||||
final Integer secondReminder, final Collection<LocalDate> recurringDates, final Collection<LocalDate> nextTenRecurringDates,
|
||||
final String humanReadable, final LocalDate recentEligibleMeetingDate, final LocalDate createdDate,
|
||||
final LocalDate lastUpdatedDate, final Long createdByUserId, final String createdByUsername, final Long lastUpdatedByUserId,
|
||||
final String lastUpdatedByUsername, final Integer repeatsOnDayOfMonth, final List<EnumOptionData> entityTypeOptions,
|
||||
final List<EnumOptionData> calendarTypeOptions, final List<EnumOptionData> remindByOptions,
|
||||
final List<EnumOptionData> repeatsOptions, final List<EnumOptionData> repeatsOnDayOptions,final LocalTime meetingTime) {
|
||||
final List<EnumOptionData> repeatsOptions, final List<EnumOptionData> repeatsOnDayOptions,final LocalTime meetingTime,
|
||||
final List<EnumOptionData> frequencyNthDayTypeOptions) {
|
||||
this.id = id;
|
||||
this.calendarInstanceId = calendarInstanceId;
|
||||
this.entityId = entityId;
|
||||
@@ -211,6 +226,7 @@ public class CalendarData {
|
||||
this.frequency = frequency;
|
||||
this.interval = interval;
|
||||
this.repeatsOnDay = repeatsOnDay;
|
||||
this.repeatsOnNthDayOfMonth = repeatsOnNthDayOfMonth;
|
||||
this.remindBy = remindBy;
|
||||
this.firstReminder = firstReminder;
|
||||
this.secondReminder = secondReminder;
|
||||
@@ -224,12 +240,14 @@ public class CalendarData {
|
||||
this.createdByUsername = createdByUsername;
|
||||
this.lastUpdatedByUserId = lastUpdatedByUserId;
|
||||
this.lastUpdatedByUsername = lastUpdatedByUsername;
|
||||
this.repeatsOnDayOfMonth = repeatsOnDayOfMonth;
|
||||
this.entityTypeOptions = entityTypeOptions;
|
||||
this.calendarTypeOptions = calendarTypeOptions;
|
||||
this.remindByOptions = remindByOptions;
|
||||
this.frequencyOptions = repeatsOptions;
|
||||
this.repeatsOnDayOptions = repeatsOnDayOptions;
|
||||
this.meetingTime = meetingTime;
|
||||
this.frequencyNthDayTypeOptions = frequencyNthDayTypeOptions;
|
||||
}
|
||||
|
||||
public Long getId() {
|
||||
@@ -350,4 +368,10 @@ public class CalendarData {
|
||||
public EnumOptionData frequencyType(){
|
||||
return this.frequency;
|
||||
}
|
||||
public EnumOptionData getRepeatsOnDay() {
|
||||
return this.repeatsOnDay;
|
||||
}
|
||||
public EnumOptionData getRepeatsOnNthDayOfMonth() {
|
||||
return this.repeatsOnNthDayOfMonth;
|
||||
}
|
||||
}
|
||||
|
||||
+59
-18
@@ -48,6 +48,7 @@ import org.apache.fineract.portfolio.calendar.CalendarConstants.CALENDAR_SUPPORT
|
||||
import org.apache.fineract.portfolio.calendar.exception.CalendarDateException;
|
||||
import org.apache.fineract.portfolio.calendar.exception.CalendarParameterUpdateNotSupportedException;
|
||||
import org.apache.fineract.portfolio.calendar.service.CalendarUtils;
|
||||
import org.apache.fineract.portfolio.common.domain.NthDayType;
|
||||
import org.apache.fineract.useradministration.domain.AppUser;
|
||||
import org.apache.poi.openxml4j.util.Nullable;
|
||||
import org.joda.time.LocalDate;
|
||||
@@ -152,8 +153,9 @@ public class Calendar extends AbstractAuditableCustom<AppUser, Long> {
|
||||
}
|
||||
|
||||
public static Calendar createRepeatingCalendar(final String title, final LocalDate startDate, final Integer typeId,
|
||||
final CalendarFrequencyType frequencyType, final Integer interval, final Integer repeatsOnDay) {
|
||||
final String recurrence = constructRecurrence(frequencyType, interval, repeatsOnDay);
|
||||
final CalendarFrequencyType frequencyType, final Integer interval, final Integer repeatsOnDay,
|
||||
final Integer repeatsOnNthDayOfMonth) {
|
||||
final String recurrence = constructRecurrence(frequencyType, interval, repeatsOnDay, repeatsOnNthDayOfMonth);
|
||||
return createRepeatingCalendar(title, startDate, typeId, recurrence);
|
||||
}
|
||||
|
||||
@@ -245,7 +247,7 @@ public class Calendar extends AbstractAuditableCustom<AppUser, Long> {
|
||||
|
||||
// TODO cover other recurrence also
|
||||
|
||||
this.recurrence = constructRecurrence(calendarFrequencyType, interval, repeatsOnDay);
|
||||
this.recurrence = constructRecurrence(calendarFrequencyType, interval, repeatsOnDay, null);
|
||||
|
||||
}
|
||||
|
||||
@@ -422,7 +424,7 @@ public class Calendar extends AbstractAuditableCustom<AppUser, Long> {
|
||||
|
||||
@SuppressWarnings("null")
|
||||
public Map<String, Object> updateRepeatingCalendar(final LocalDate calendarStartDate, final CalendarFrequencyType frequencyType,
|
||||
final Integer interval, final Integer repeatsOnDay) {
|
||||
final Integer interval, final Integer repeatsOnDay, final Integer repeatsOnNthDay) {
|
||||
final Map<String, Object> actualChanges = new LinkedHashMap<>(9);
|
||||
|
||||
if (calendarStartDate != null & this.startDate != null) {
|
||||
@@ -432,7 +434,7 @@ public class Calendar extends AbstractAuditableCustom<AppUser, Long> {
|
||||
}
|
||||
}
|
||||
|
||||
final String newRecurrence = Calendar.constructRecurrence(frequencyType, interval, repeatsOnDay);
|
||||
final String newRecurrence = Calendar.constructRecurrence(frequencyType, interval, repeatsOnDay, repeatsOnNthDay);
|
||||
if (!StringUtils.isBlank(this.recurrence) && !newRecurrence.equalsIgnoreCase(this.recurrence)) {
|
||||
actualChanges.put("recurrence", newRecurrence);
|
||||
this.recurrence = newRecurrence;
|
||||
@@ -568,13 +570,27 @@ public class Calendar extends AbstractAuditableCustom<AppUser, Long> {
|
||||
if (frequencyType.isWeekly()) {
|
||||
repeatsOnDay = command.integerValueOfParameterNamed(CALENDAR_SUPPORTED_PARAMETERS.REPEATS_ON_DAY.getValue());
|
||||
}
|
||||
Integer repeatsOnNthDayOfMonth = null;
|
||||
if (frequencyType.isMonthly()) {
|
||||
repeatsOnNthDayOfMonth = command.integerValueOfParameterNamed(CALENDAR_SUPPORTED_PARAMETERS.REPEATS_ON_NTH_DAY_OF_MONTH
|
||||
.getValue());
|
||||
final NthDayType nthDay = NthDayType.fromInt(repeatsOnNthDayOfMonth);
|
||||
repeatsOnDay = command.integerValueOfParameterNamed(CALENDAR_SUPPORTED_PARAMETERS.REPEATS_ON_LAST_WEEKDAY_OF_MONTH
|
||||
.getValue());
|
||||
if (nthDay.isOnDay()) {
|
||||
repeatsOnNthDayOfMonth = command.integerValueOfParameterNamed(CALENDAR_SUPPORTED_PARAMETERS.REPEATS_ON_DAY_OF_MONTH
|
||||
.getValue());
|
||||
repeatsOnDay = null;
|
||||
}
|
||||
}
|
||||
|
||||
return constructRecurrence(frequencyType, interval, repeatsOnDay);
|
||||
return constructRecurrence(frequencyType, interval, repeatsOnDay, repeatsOnNthDayOfMonth);
|
||||
}
|
||||
return "";
|
||||
}
|
||||
|
||||
private static String constructRecurrence(final CalendarFrequencyType frequencyType, final Integer interval, final Integer repeatsOnDay) {
|
||||
private static String constructRecurrence(final CalendarFrequencyType frequencyType, final Integer interval,
|
||||
final Integer repeatsOnDay, final Integer repeatsOnNthDayOfMonth) {
|
||||
final StringBuilder recurrenceBuilder = new StringBuilder(200);
|
||||
|
||||
recurrenceBuilder.append("FREQ=");
|
||||
@@ -584,10 +600,31 @@ public class Calendar extends AbstractAuditableCustom<AppUser, Long> {
|
||||
recurrenceBuilder.append(interval);
|
||||
}
|
||||
if (frequencyType.isWeekly()) {
|
||||
final CalendarWeekDaysType weekDays = CalendarWeekDaysType.fromInt(repeatsOnDay);
|
||||
if (!weekDays.isInvalid()) {
|
||||
recurrenceBuilder.append(";BYDAY=");
|
||||
recurrenceBuilder.append(weekDays.toString().toUpperCase());
|
||||
if (repeatsOnDay != null) {
|
||||
final CalendarWeekDaysType weekDays = CalendarWeekDaysType.fromInt(repeatsOnDay);
|
||||
if (!weekDays.isInvalid()) {
|
||||
recurrenceBuilder.append(";BYDAY=");
|
||||
recurrenceBuilder.append(weekDays.toString().toUpperCase());
|
||||
}
|
||||
}
|
||||
}
|
||||
if (frequencyType.isMonthly()) {
|
||||
if (repeatsOnNthDayOfMonth != null && (repeatsOnDay == null || repeatsOnDay == CalendarWeekDaysType.INVALID.getValue())) {
|
||||
if (repeatsOnNthDayOfMonth >= -1 && repeatsOnNthDayOfMonth <= 28) {
|
||||
recurrenceBuilder.append(";BYMONTHDAY=");
|
||||
recurrenceBuilder.append(repeatsOnNthDayOfMonth);
|
||||
}
|
||||
} else if (repeatsOnNthDayOfMonth != null && repeatsOnDay != null && repeatsOnDay != CalendarWeekDaysType.INVALID.getValue()) {
|
||||
final NthDayType nthDay = NthDayType.fromInt(repeatsOnNthDayOfMonth);
|
||||
if (!nthDay.isInvalid()) {
|
||||
recurrenceBuilder.append(";BYSETPOS=");
|
||||
recurrenceBuilder.append(nthDay.getValue());
|
||||
}
|
||||
final CalendarWeekDaysType weekday = CalendarWeekDaysType.fromInt(repeatsOnDay);
|
||||
if (!weekday.isInvalid()) {
|
||||
recurrenceBuilder.append(";BYDAY=");
|
||||
recurrenceBuilder.append(weekday.toString().toUpperCase());
|
||||
}
|
||||
}
|
||||
}
|
||||
return recurrenceBuilder.toString();
|
||||
@@ -611,18 +648,22 @@ public class Calendar extends AbstractAuditableCustom<AppUser, Long> {
|
||||
|
||||
final CalendarFrequencyType frequencyType = CalendarUtils.getFrequency(this.recurrence);
|
||||
final Integer interval = new Integer(CalendarUtils.getInterval(this.recurrence));
|
||||
final String newRecurrence = Calendar.constructRecurrence(frequencyType, interval, startDate.getDayOfWeek());
|
||||
final String newRecurrence = Calendar.constructRecurrence(frequencyType, interval, startDate.getDayOfWeek(), null);
|
||||
|
||||
this.recurrence = newRecurrence;
|
||||
this.startDate = startDate.toDate();
|
||||
this.endDate = endDate.toDate();
|
||||
}
|
||||
|
||||
public Set<CalendarHistory> getCalendarHistory(){
|
||||
return this.calendarHistory;
|
||||
|
||||
public Set<CalendarHistory> getCalendarHistory() {
|
||||
return this.calendarHistory;
|
||||
}
|
||||
|
||||
public void updateCalendarHistory(final Set<CalendarHistory> calendarHistory){
|
||||
this.calendarHistory = calendarHistory;
|
||||
|
||||
public void updateCalendarHistory(final Set<CalendarHistory> calendarHistory) {
|
||||
this.calendarHistory = calendarHistory;
|
||||
}
|
||||
|
||||
public void setRecurrence(String recurrence) {
|
||||
this.recurrence = recurrence;
|
||||
}
|
||||
}
|
||||
|
||||
+1
-1
@@ -31,7 +31,7 @@ import org.springframework.data.jpa.domain.AbstractPersistable;
|
||||
@Table(name = "m_calendar_instance")
|
||||
public class CalendarInstance extends AbstractPersistable<Long> {
|
||||
|
||||
@ManyToOne(cascade = CascadeType.ALL)
|
||||
@ManyToOne(cascade = CascadeType.PERSIST)
|
||||
@JoinColumn(name = "calendar_id", nullable = false)
|
||||
private Calendar calendar;
|
||||
|
||||
|
||||
+11
@@ -37,6 +37,7 @@ import org.apache.fineract.portfolio.calendar.domain.CalendarEntityType;
|
||||
import org.apache.fineract.portfolio.calendar.domain.CalendarFrequencyType;
|
||||
import org.apache.fineract.portfolio.calendar.domain.CalendarRemindBy;
|
||||
import org.apache.fineract.portfolio.calendar.domain.CalendarWeekDaysType;
|
||||
import org.apache.fineract.portfolio.calendar.service.CalendarUtils;
|
||||
import org.joda.time.LocalDate;
|
||||
import org.joda.time.LocalDateTime;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
@@ -173,6 +174,10 @@ public class CalendarCommandFromApiJsonDeserializer extends AbstractFromApiJsonD
|
||||
CALENDAR_SUPPORTED_PARAMETERS.REPEATS_ON_DAY.getValue(), element);
|
||||
baseDataValidator.reset().parameter(CALENDAR_SUPPORTED_PARAMETERS.REPEATS_ON_DAY.getValue()).value(repeatsOnDay)
|
||||
.notBlank().inMinMaxRange(CalendarWeekDaysType.getMinValue(), CalendarWeekDaysType.getMaxValue());
|
||||
} else if (CalendarFrequencyType.fromInt(frequency).isMonthly()) {
|
||||
CalendarUtils.validateNthDayOfMonthFrequency(baseDataValidator,
|
||||
CALENDAR_SUPPORTED_PARAMETERS.REPEATS_ON_NTH_DAY_OF_MONTH.getValue(),
|
||||
CALENDAR_SUPPORTED_PARAMETERS.REPEATS_ON_LAST_WEEKDAY_OF_MONTH.getValue(), element, this.fromApiJsonHelper);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -305,11 +310,17 @@ public class CalendarCommandFromApiJsonDeserializer extends AbstractFromApiJsonD
|
||||
.integerGreaterThanZero();
|
||||
}
|
||||
|
||||
if (CalendarFrequencyType.fromInt(frequency).isWeekly()) {
|
||||
if (this.fromApiJsonHelper.parameterExists(CALENDAR_SUPPORTED_PARAMETERS.REPEATS_ON_DAY.getValue(), element)) {
|
||||
final Integer repeatsOnDay = this.fromApiJsonHelper.extractIntegerSansLocaleNamed(
|
||||
CALENDAR_SUPPORTED_PARAMETERS.REPEATS_ON_DAY.getValue(), element);
|
||||
baseDataValidator.reset().parameter(CALENDAR_SUPPORTED_PARAMETERS.REPEATS_ON_DAY.getValue()).value(repeatsOnDay)
|
||||
.notBlank().inMinMaxRange(CalendarWeekDaysType.getMinValue(), CalendarWeekDaysType.getMaxValue());
|
||||
}
|
||||
} else if (CalendarFrequencyType.fromInt(frequency).isMonthly()) {
|
||||
CalendarUtils.validateNthDayOfMonthFrequency(baseDataValidator,
|
||||
CALENDAR_SUPPORTED_PARAMETERS.REPEATS_ON_NTH_DAY_OF_MONTH.getValue(),
|
||||
CALENDAR_SUPPORTED_PARAMETERS.REPEATS_ON_LAST_WEEKDAY_OF_MONTH.getValue(), element, this.fromApiJsonHelper);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
+1
@@ -33,5 +33,6 @@ public interface CalendarDropdownReadPlatformService {
|
||||
List<EnumOptionData> retrieveCalendarFrequencyTypeOptions();
|
||||
|
||||
List<EnumOptionData> retrieveCalendarWeekDaysTypeOptions();
|
||||
List<EnumOptionData> retrieveCalendarFrequencyNthDayTypeOptions();
|
||||
|
||||
}
|
||||
+4
@@ -55,4 +55,8 @@ public class CalendarDropdownReadPlatformServiceImpl implements CalendarDropdown
|
||||
public List<EnumOptionData> retrieveCalendarWeekDaysTypeOptions() {
|
||||
return CalendarEnumerations.calendarWeekDaysType(CalendarWeekDaysType.values());
|
||||
}
|
||||
@Override
|
||||
public List<EnumOptionData> retrieveCalendarFrequencyNthDayTypeOptions() {
|
||||
return CalendarEnumerations.calendarFrequencyNthDayType();
|
||||
}
|
||||
}
|
||||
|
||||
+25
-2
@@ -19,6 +19,7 @@
|
||||
package org.apache.fineract.portfolio.calendar.service;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.Arrays;
|
||||
import java.util.List;
|
||||
|
||||
import org.apache.fineract.infrastructure.core.data.EnumOptionData;
|
||||
@@ -27,6 +28,7 @@ import org.apache.fineract.portfolio.calendar.domain.CalendarFrequencyType;
|
||||
import org.apache.fineract.portfolio.calendar.domain.CalendarRemindBy;
|
||||
import org.apache.fineract.portfolio.calendar.domain.CalendarType;
|
||||
import org.apache.fineract.portfolio.calendar.domain.CalendarWeekDaysType;
|
||||
import org.apache.fineract.portfolio.common.domain.NthDayType;
|
||||
|
||||
public class CalendarEnumerations {
|
||||
|
||||
@@ -86,8 +88,11 @@ public class CalendarEnumerations {
|
||||
}
|
||||
|
||||
public static EnumOptionData calendarFrequencyType(final CalendarFrequencyType calendarFrequencyType) {
|
||||
final EnumOptionData optionData = new EnumOptionData(calendarFrequencyType.getValue().longValue(), calendarFrequencyType.getCode(),
|
||||
EnumOptionData optionData = null;
|
||||
if (!calendarFrequencyType.isInvalid()) {
|
||||
optionData = new EnumOptionData(calendarFrequencyType.getValue().longValue(), calendarFrequencyType.getCode(),
|
||||
calendarFrequencyType.toString());
|
||||
}
|
||||
return optionData;
|
||||
}
|
||||
|
||||
@@ -106,8 +111,11 @@ public class CalendarEnumerations {
|
||||
}
|
||||
|
||||
public static EnumOptionData calendarWeekDaysType(final CalendarWeekDaysType calendarWeekDaysType) {
|
||||
final EnumOptionData optionData = new EnumOptionData(calendarWeekDaysType.getValue().longValue(), calendarWeekDaysType.getCode(),
|
||||
EnumOptionData optionData = null;
|
||||
if (!calendarWeekDaysType.isInvalid()) {
|
||||
optionData = new EnumOptionData(calendarWeekDaysType.getValue().longValue(), calendarWeekDaysType.getCode(),
|
||||
calendarWeekDaysType.toString());
|
||||
}
|
||||
return optionData;
|
||||
}
|
||||
|
||||
@@ -120,4 +128,19 @@ public class CalendarEnumerations {
|
||||
}
|
||||
return optionDatas;
|
||||
}
|
||||
public static EnumOptionData calendarFrequencyNthDayType(final int id) {
|
||||
return calendarFrequencyNthDayType(NthDayType.fromInt(id));
|
||||
}
|
||||
public static EnumOptionData calendarFrequencyNthDayType(final NthDayType calendarFrequencyNthDayType) {
|
||||
final EnumOptionData optionData = new EnumOptionData(calendarFrequencyNthDayType.getValue().longValue(), calendarFrequencyNthDayType.getCode(),
|
||||
calendarFrequencyNthDayType.toString());
|
||||
return optionData;
|
||||
}
|
||||
public static List<EnumOptionData> calendarFrequencyNthDayType() {
|
||||
final List<EnumOptionData> optionDatas = Arrays.asList(calendarFrequencyNthDayType(NthDayType.ONE),
|
||||
calendarFrequencyNthDayType(NthDayType.TWO), calendarFrequencyNthDayType(NthDayType.THREE),
|
||||
calendarFrequencyNthDayType(NthDayType.FOUR), calendarFrequencyNthDayType(NthDayType.LAST),
|
||||
calendarFrequencyNthDayType(NthDayType.ONDAY));
|
||||
return optionDatas;
|
||||
}
|
||||
}
|
||||
|
||||
+10
-6
@@ -89,6 +89,7 @@ public class CalendarReadPlatformServiceImpl implements CalendarReadPlatformServ
|
||||
final EnumOptionData frequency = CalendarEnumerations.calendarFrequencyType(CalendarUtils.getFrequency(recurrence));
|
||||
final Integer interval = new Integer(CalendarUtils.getInterval(recurrence));
|
||||
final EnumOptionData repeatsOnDay = CalendarEnumerations.calendarWeekDaysType(CalendarUtils.getRepeatsOnDay(recurrence));
|
||||
final EnumOptionData repeatsOnNthDayOfMonth = CalendarEnumerations.calendarFrequencyNthDayType(CalendarUtils.getRepeatsOnNthDayOfMonth(recurrence));
|
||||
final Integer remindById = rs.getInt("remindById");
|
||||
EnumOptionData remindBy = null;
|
||||
if (remindById != null && remindById != 0) {
|
||||
@@ -100,7 +101,7 @@ public class CalendarReadPlatformServiceImpl implements CalendarReadPlatformServ
|
||||
if (startDate != null && recurrence != null) {
|
||||
humanReadable = CalendarUtils.getRRuleReadable(startDate, recurrence);
|
||||
}
|
||||
|
||||
Integer monthOnDay = CalendarUtils.getMonthOnDay(recurrence);
|
||||
final LocalDate createdDate = JdbcSupport.getLocalDate(rs, "createdDate");
|
||||
final LocalDate lastUpdatedDate = JdbcSupport.getLocalDate(rs, "updatedDate");
|
||||
final Long createdByUserId = rs.getLong("creatingUserId");
|
||||
@@ -110,9 +111,9 @@ public class CalendarReadPlatformServiceImpl implements CalendarReadPlatformServ
|
||||
final LocalTime meetingTime = JdbcSupport.getLocalTime(rs,"meetingTime");
|
||||
|
||||
return CalendarData.instance(id, calendarInstanceId, entityId, entityType, title, description, location, startDate, endDate,
|
||||
duration, type, repeating, recurrence, frequency, interval, repeatsOnDay, remindBy, firstReminder, secondReminder,
|
||||
duration, type, repeating, recurrence, frequency, interval, repeatsOnDay, repeatsOnNthDayOfMonth, remindBy, firstReminder, secondReminder,
|
||||
humanReadable, createdDate, lastUpdatedDate, createdByUserId, createdByUserName, lastUpdatedByUserId,
|
||||
lastUpdatedByUserName,meetingTime);
|
||||
lastUpdatedByUserName,meetingTime, monthOnDay);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -479,6 +480,8 @@ public class CalendarReadPlatformServiceImpl implements CalendarReadPlatformServ
|
||||
final EnumOptionData frequency = CalendarEnumerations.calendarFrequencyType(CalendarUtils.getFrequency(recurrence));
|
||||
final Integer interval = new Integer(CalendarUtils.getInterval(recurrence));
|
||||
final EnumOptionData repeatsOnDay = CalendarEnumerations.calendarWeekDaysType(CalendarUtils.getRepeatsOnDay(recurrence));
|
||||
final EnumOptionData repeatsOnNthDayOfMonth = CalendarEnumerations.calendarFrequencyNthDayType(CalendarUtils
|
||||
.getRepeatsOnNthDayOfMonth(recurrence));
|
||||
final Integer remindById = rs.getInt("remindById");
|
||||
EnumOptionData remindBy = null;
|
||||
if (remindById != null && remindById != 0) {
|
||||
@@ -498,11 +501,12 @@ public class CalendarReadPlatformServiceImpl implements CalendarReadPlatformServ
|
||||
final Long lastUpdatedByUserId = null;
|
||||
final String lastUpdatedByUserName = null;
|
||||
final LocalTime meetingTime = null;
|
||||
Integer monthOnDay = CalendarUtils.getMonthOnDay(recurrence);
|
||||
|
||||
return CalendarData.instance(id, calendarInstanceId, entityId, entityType, title, description, location, startDate, endDate,
|
||||
duration, type, repeating, recurrence, frequency, interval, repeatsOnDay, remindBy, firstReminder, secondReminder,
|
||||
humanReadable, createdDate, lastUpdatedDate, createdByUserId, createdByUserName, lastUpdatedByUserId,
|
||||
lastUpdatedByUserName, meetingTime);
|
||||
duration, type, repeating, recurrence, frequency, interval, repeatsOnDay, repeatsOnNthDayOfMonth, remindBy,
|
||||
firstReminder, secondReminder, humanReadable, createdDate, lastUpdatedDate, createdByUserId, createdByUserName,
|
||||
lastUpdatedByUserId, lastUpdatedByUserName, meetingTime, monthOnDay);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
+112
-1
@@ -30,6 +30,7 @@ import java.util.StringTokenizer;
|
||||
import net.fortuna.ical4j.model.Date;
|
||||
import net.fortuna.ical4j.model.DateList;
|
||||
import net.fortuna.ical4j.model.DateTime;
|
||||
import net.fortuna.ical4j.model.NumberList;
|
||||
import net.fortuna.ical4j.model.Recur;
|
||||
import net.fortuna.ical4j.model.ValidationException;
|
||||
import net.fortuna.ical4j.model.WeekDay;
|
||||
@@ -37,18 +38,23 @@ import net.fortuna.ical4j.model.WeekDayList;
|
||||
import net.fortuna.ical4j.model.parameter.Value;
|
||||
import net.fortuna.ical4j.model.property.RRule;
|
||||
|
||||
import org.apache.fineract.infrastructure.core.data.DataValidatorBuilder;
|
||||
import org.apache.fineract.infrastructure.core.exception.PlatformDataIntegrityException;
|
||||
import org.apache.fineract.infrastructure.core.serialization.FromJsonHelper;
|
||||
import org.apache.fineract.infrastructure.core.service.DateUtils;
|
||||
import org.apache.fineract.organisation.workingdays.domain.WorkingDays;
|
||||
import org.apache.fineract.organisation.workingdays.service.WorkingDaysUtil;
|
||||
import org.apache.fineract.portfolio.calendar.domain.Calendar;
|
||||
import org.apache.fineract.portfolio.calendar.domain.CalendarFrequencyType;
|
||||
import org.apache.fineract.portfolio.calendar.domain.CalendarWeekDaysType;
|
||||
import org.apache.fineract.portfolio.common.domain.NthDayType;
|
||||
import org.apache.fineract.portfolio.common.domain.PeriodFrequencyType;
|
||||
import org.joda.time.LocalDate;
|
||||
import org.joda.time.format.DateTimeFormat;
|
||||
import org.joda.time.format.DateTimeFormatter;
|
||||
|
||||
import com.google.gson.JsonElement;
|
||||
|
||||
public class CalendarUtils {
|
||||
|
||||
static {
|
||||
@@ -260,10 +266,48 @@ public class CalendarUtils {
|
||||
}
|
||||
|
||||
} else if (recur.getFrequency().equals(Recur.MONTHLY)) {
|
||||
if (recur.getInterval() == 1) {
|
||||
NumberList nthDays = recur.getSetPosList();
|
||||
Integer nthDay = null;
|
||||
if (!nthDays.isEmpty())
|
||||
nthDay = (Integer) nthDays.get(0);
|
||||
NumberList monthDays = recur.getMonthDayList();
|
||||
Integer monthDay = null;
|
||||
if (!monthDays.isEmpty())
|
||||
monthDay = (Integer) monthDays.get(0);
|
||||
WeekDayList weekdays = recur.getDayList();
|
||||
WeekDay weekDay = null;
|
||||
if (!weekdays.isEmpty())
|
||||
weekDay = (WeekDay) weekdays.get(0);
|
||||
if (nthDay != null && weekDay != null) {
|
||||
NthDayType nthDayType = NthDayType.fromInt(nthDay);
|
||||
NthDayNameEnum nthDayName = NthDayNameEnum.from(nthDayType.toString());
|
||||
DayNameEnum weekdayType = DayNameEnum.from(weekDay.getDay());
|
||||
if (recur.getInterval() == 1 || recur.getInterval() == -1) {
|
||||
humanReadable = "Monthly on " + nthDayName.getCode().toLowerCase() + " " + weekdayType.getCode().toLowerCase();
|
||||
} else {
|
||||
humanReadable = "Every " + recur.getInterval() + " months on " + nthDayName.getCode().toLowerCase() + " "
|
||||
+ weekdayType.getCode().toLowerCase();
|
||||
}
|
||||
} else if (monthDay != null) {
|
||||
if (monthDay == -1) {
|
||||
if (recur.getInterval() == 1 || recur.getInterval() == -1) {
|
||||
humanReadable = "Monthly on last day";
|
||||
} else {
|
||||
humanReadable = "Every " + recur.getInterval() + " months on last day";
|
||||
}
|
||||
} else {
|
||||
if (recur.getInterval() == 1 || recur.getInterval() == -1) {
|
||||
humanReadable = "Monthly on day " + monthDay;
|
||||
} else {
|
||||
humanReadable = "Every " + recur.getInterval() + " months on day " + monthDay;
|
||||
}
|
||||
}
|
||||
} else {
|
||||
if (recur.getInterval() == 1 || recur.getInterval() == -1) {
|
||||
humanReadable = "Monthly on day " + startDate.getDayOfMonth();
|
||||
} else {
|
||||
humanReadable = "Every " + recur.getInterval() + " months on day " + startDate.getDayOfMonth();
|
||||
}
|
||||
}
|
||||
} else if (recur.getFrequency().equals(Recur.YEARLY)) {
|
||||
if (recur.getInterval() == 1) {
|
||||
@@ -347,6 +391,28 @@ public class CalendarUtils {
|
||||
return DayNameEnum.MO;// Default it to Monday
|
||||
}
|
||||
}
|
||||
public static enum NthDayNameEnum {
|
||||
ONE(1, "First"), TWO(2, "Second"), THREE(3, "Third"), FOUR(4, "Fourth"), FIVE(5, "Fifth"), LAST(-1, "Last"), INVALID(0, "Invalid");
|
||||
private final String code;
|
||||
private final Integer value;
|
||||
|
||||
private NthDayNameEnum(final Integer value, final String code) {
|
||||
this.value = value;
|
||||
this.code = code;
|
||||
}
|
||||
public String getCode() {
|
||||
return this.code;
|
||||
}
|
||||
public int getValue() {
|
||||
return this.value;
|
||||
}
|
||||
public static NthDayNameEnum from(final String name) {
|
||||
for (final NthDayNameEnum nthDayName : NthDayNameEnum.values()) {
|
||||
if (nthDayName.toString().equals(name)) { return nthDayName; }
|
||||
}
|
||||
return NthDayNameEnum.INVALID;
|
||||
}
|
||||
}
|
||||
|
||||
public static PeriodFrequencyType getMeetingPeriodFrequencyType(final String recurringRule) {
|
||||
final Recur recur = CalendarUtils.getICalRecur(recurringRule);
|
||||
@@ -399,6 +465,18 @@ public class CalendarUtils {
|
||||
WeekDay weekDay = (WeekDay) weekDays.get(0);
|
||||
return CalendarWeekDaysType.fromString(weekDay.getDay());
|
||||
}
|
||||
public static NthDayType getRepeatsOnNthDayOfMonth(final String recurringRule) {
|
||||
final Recur recur = CalendarUtils.getICalRecur(recurringRule);
|
||||
NumberList monthDays = null;
|
||||
if(recur.getDayList().isEmpty())
|
||||
monthDays = recur.getMonthDayList();
|
||||
else
|
||||
monthDays = recur.getSetPosList();
|
||||
if (monthDays.isEmpty()) return NthDayType.INVALID;
|
||||
if (!recur.getMonthDayList().isEmpty() && recur.getSetPosList().isEmpty()) return NthDayType.ONDAY;
|
||||
Integer monthDay = (Integer) monthDays.get(0);
|
||||
return NthDayType.fromInt(monthDay);
|
||||
}
|
||||
|
||||
public static LocalDate getFirstRepaymentMeetingDate(final Calendar calendar, final LocalDate disbursementDate,
|
||||
final Integer loanRepaymentInterval, final String frequency, boolean isSkipRepaymentOnFirstDayOfMonth,
|
||||
@@ -589,4 +667,37 @@ public class CalendarUtils {
|
||||
|
||||
return scheduleDate;
|
||||
}
|
||||
public static void validateNthDayOfMonthFrequency(DataValidatorBuilder baseDataValidator, final String repeatsOnNthDayOfMonthParamName,
|
||||
final String repeatsOnDayParamName, final JsonElement element, final FromJsonHelper fromApiJsonHelper) {
|
||||
final Integer repeatsOnNthDayOfMonth = fromApiJsonHelper.extractIntegerSansLocaleNamed(repeatsOnNthDayOfMonthParamName, element);
|
||||
baseDataValidator.reset().parameter(repeatsOnNthDayOfMonthParamName).value(repeatsOnNthDayOfMonth).ignoreIfNull()
|
||||
.isOneOfTheseValues(NthDayType.ONE.getValue(), NthDayType.TWO.getValue(), NthDayType.THREE.getValue(),
|
||||
NthDayType.FOUR.getValue(), NthDayType.LAST.getValue(), NthDayType.ONDAY.getValue());
|
||||
final Integer repeatsOnDay = fromApiJsonHelper.extractIntegerSansLocaleNamed(repeatsOnDayParamName, element);
|
||||
baseDataValidator.reset().parameter(repeatsOnDayParamName).value(repeatsOnDay).ignoreIfNull()
|
||||
.inMinMaxRange(CalendarWeekDaysType.getMinValue(), CalendarWeekDaysType.getMaxValue());
|
||||
NthDayType nthDayType = null;
|
||||
if (repeatsOnNthDayOfMonth != null) {
|
||||
nthDayType = NthDayType.fromInt(repeatsOnNthDayOfMonth);
|
||||
}
|
||||
if (nthDayType != null && nthDayType != NthDayType.INVALID) {
|
||||
if (nthDayType == NthDayType.ONE || nthDayType == NthDayType.TWO || nthDayType == NthDayType.THREE
|
||||
|| nthDayType == NthDayType.FOUR) {
|
||||
baseDataValidator.reset().parameter(repeatsOnDayParamName).value(repeatsOnDay).cantBeBlankWhenParameterProvidedIs(
|
||||
repeatsOnNthDayOfMonthParamName, NthDayNameEnum.from(nthDayType.toString()).getCode().toLowerCase());
|
||||
}
|
||||
}
|
||||
}
|
||||
public static Integer getMonthOnDay(String recurringRule) {
|
||||
final Recur recur = CalendarUtils.getICalRecur(recurringRule);
|
||||
NumberList monthDayList = null;
|
||||
Integer monthOnDay = null;
|
||||
if (getMeetingPeriodFrequencyType(recur).isMonthly()) {
|
||||
monthDayList = recur.getMonthDayList();
|
||||
if (!monthDayList.isEmpty()) {
|
||||
monthOnDay = (Integer) monthDayList.get(0);
|
||||
}
|
||||
}
|
||||
return monthOnDay;
|
||||
}
|
||||
}
|
||||
|
||||
+4
-3
@@ -33,7 +33,6 @@ import org.apache.fineract.infrastructure.core.data.CommandProcessingResult;
|
||||
import org.apache.fineract.infrastructure.core.data.CommandProcessingResultBuilder;
|
||||
import org.apache.fineract.infrastructure.core.data.DataValidatorBuilder;
|
||||
import org.apache.fineract.infrastructure.core.exception.PlatformApiDataValidationException;
|
||||
import org.apache.fineract.infrastructure.core.service.DateUtils;
|
||||
import org.apache.fineract.portfolio.calendar.CalendarConstants.CALENDAR_SUPPORTED_PARAMETERS;
|
||||
import org.apache.fineract.portfolio.calendar.domain.Calendar;
|
||||
import org.apache.fineract.portfolio.calendar.domain.CalendarEntityType;
|
||||
@@ -291,8 +290,10 @@ public class CalendarWritePlatformServiceJpaRepositoryImpl implements CalendarWr
|
||||
if (reschedulebasedOnMeetingDates == null){
|
||||
presentMeetingDate = command.localDateValueOfParameterNamed(CALENDAR_SUPPORTED_PARAMETERS.START_DATE.getValue());
|
||||
}
|
||||
final Date endDate = presentMeetingDate.minusDays(1).toDate();
|
||||
calendarHistory.updateEndDate(endDate);
|
||||
if (null != newMeetingDate) {
|
||||
final Date endDate = presentMeetingDate.minusDays(1).toDate();
|
||||
calendarHistory.updateEndDate(endDate);
|
||||
}
|
||||
this.calendarHistoryRepository.save(calendarHistory);
|
||||
Set<CalendarHistory> history = calendarForUpdate.getCalendarHistory();
|
||||
history.add(calendarHistory);
|
||||
|
||||
+17
@@ -25,6 +25,8 @@ public enum NthDayType {
|
||||
THREE(3,"nthDayType.three"),
|
||||
FOUR(4,"nthDayType.four"),
|
||||
FIVE(5,"nthDayType.five"),
|
||||
LAST(-1,"nthDayType.last"),
|
||||
ONDAY(-2,"nthDayType.onday"),
|
||||
INVALID(0,"nthDayType.invalid");
|
||||
|
||||
private final Integer value;
|
||||
@@ -62,6 +64,12 @@ public enum NthDayType {
|
||||
case 5:
|
||||
repaymentFrequencyNthDayType = NthDayType.FIVE;
|
||||
break;
|
||||
case -1:
|
||||
repaymentFrequencyNthDayType = NthDayType.LAST;
|
||||
break;
|
||||
case -2:
|
||||
repaymentFrequencyNthDayType = NthDayType.ONDAY;
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
@@ -69,4 +77,13 @@ public enum NthDayType {
|
||||
return repaymentFrequencyNthDayType;
|
||||
}
|
||||
|
||||
public boolean isInvalid() {
|
||||
return this.value.equals(NthDayType.INVALID.value);
|
||||
}
|
||||
public boolean isLastDay() {
|
||||
return this.value.equals(NthDayType.LAST.value);
|
||||
}
|
||||
public boolean isOnDay() {
|
||||
return this.value.equals(NthDayType.ONDAY.value);
|
||||
}
|
||||
}
|
||||
|
||||
+4
-1
@@ -52,6 +52,7 @@ import org.apache.fineract.organisation.staff.service.StaffReadPlatformService;
|
||||
import org.apache.fineract.portfolio.calendar.data.CalendarData;
|
||||
import org.apache.fineract.portfolio.calendar.service.CalendarEnumerations;
|
||||
import org.apache.fineract.portfolio.calendar.service.CalendarReadPlatformService;
|
||||
import org.apache.fineract.portfolio.calendar.service.CalendarUtils;
|
||||
import org.apache.fineract.portfolio.client.data.ClientData;
|
||||
import org.apache.fineract.portfolio.client.domain.ClientEnumerations;
|
||||
import org.apache.fineract.portfolio.client.service.ClientReadPlatformService;
|
||||
@@ -271,10 +272,12 @@ public class CenterReadPlatformServiceImpl implements CenterReadPlatformService
|
||||
final LocalDate endDate = JdbcSupport.getLocalDate(rs, "endDate");
|
||||
final String recurrence = rs.getString("recurrence");
|
||||
final LocalTime meetingTime = JdbcSupport.getLocalTime(rs,"meetingTime");
|
||||
Integer monthOnDay = CalendarUtils.getMonthOnDay(recurrence);
|
||||
|
||||
CalendarData calendarData = CalendarData.instance(calendarId, calendarInstanceId, entityId, entityType, title, description,
|
||||
location, startDate, endDate, null, null, false, recurrence, null, null, null, null, null, null, null, null, null,
|
||||
null, null, null, null,meetingTime);
|
||||
null, null, null, null, null, meetingTime, monthOnDay);
|
||||
|
||||
return CenterData.instance(id, accountNo, name, externalId, status, activationDate, officeId, null, staffId, staffName, hierarchy, null,
|
||||
calendarData);
|
||||
}
|
||||
|
||||
+39
-2
@@ -40,12 +40,49 @@ public interface LoanApiConstants {
|
||||
public static final String rejectedOnDateParameterName = "rejectedOnDate";
|
||||
public static final String withdrawnOnDateParameterName = "withdrawnOnDate";
|
||||
|
||||
// Interest recalculation related
|
||||
public static final String isInterestRecalculationEnabledParameterName = "isInterestRecalculationEnabled";
|
||||
public static final String transactionProcessingStrategyIdParameterName = "transactionProcessingStrategyId";
|
||||
public static final String loanPurposeIdParameterName = "loanPurposeId";
|
||||
public static final String loanOfficerIdParameterName = "loanOfficerId";
|
||||
public static final String fundIdParameterName = "fundId";
|
||||
public static final String externalIdParameterName = "externalId";
|
||||
public static final String accountNoParameterName = "accountNo";
|
||||
public static final String productIdParameterName = "productId";
|
||||
public static final String calendarIdParameterName = "calendarId";
|
||||
public static final String loanTypeParameterName = "loanType";
|
||||
public static final String groupIdParameterName = "groupId";
|
||||
public static final String clientIdParameterName = "clientId";
|
||||
public static final String idParameterName = "id";
|
||||
public static final String graceOnInterestChargedParameterName = "graceOnInterestCharged";
|
||||
public static final String graceOnInterestPaymentParameterName = "graceOnInterestPayment";
|
||||
public static final String graceOnPrincipalPaymentParameterName = "graceOnPrincipalPayment";
|
||||
public static final String repaymentsStartingFromDateParameterName = "repaymentsStartingFromDate";
|
||||
public static final String interestRateFrequencyTypeParameterName = "interestRateFrequencyType";
|
||||
public static final String interestCalculationPeriodTypeParameterName = "interestCalculationPeriodType";
|
||||
public static final String interestTypeParameterName = "interestType";
|
||||
public static final String amortizationTypeParameterName = "amortizationType";
|
||||
public static final String repaymentFrequencyTypeParameterName = "repaymentFrequencyType";
|
||||
public static final String loanTermFrequencyTypeParameterName = "loanTermFrequencyType";
|
||||
public static final String loanTermFrequencyParameterName = "loanTermFrequency";
|
||||
public static final String numberOfRepaymentsParameterName = "numberOfRepayments";
|
||||
public static final String repaymentEveryParameterName = "repaymentEvery";
|
||||
public static final String interestRatePerPeriodParameterName = "interestRatePerPeriod";
|
||||
public static final String inArrearsToleranceParameterName = "inArrearsTolerance";
|
||||
public static final String interestChargedFromDateParameterName = "interestChargedFromDate";
|
||||
public static final String submittedOnDateParameterName = "submittedOnDate";
|
||||
public static final String submittedOnNoteParameterName = "interestChargedFromDate";
|
||||
public static final String collateralParameterName = "collateral";
|
||||
public static final String syncDisbursementWithMeetingParameterName = "syncDisbursementWithMeeting";
|
||||
public static final String linkAccountIdParameterName = "linkAccountId";
|
||||
public static final String createStandingInstructionAtDisbursementParameterName = "createStandingInstructionAtDisbursement";
|
||||
public static final String daysInYearTypeParameterName = "daysInYearType";
|
||||
public static final String daysInMonthTypeParameterName = "daysInMonthType";
|
||||
|
||||
// Interest recalculation related
|
||||
public static final String isInterestRecalculationEnabledParameterName = "isInterestRecalculationEnabled";
|
||||
public static final String interestRecalculationCompoundingMethodParameterName = "interestRecalculationCompoundingMethod";
|
||||
public static final String rescheduleStrategyMethodParameterName = "rescheduleStrategyMethod";
|
||||
public static final String repaymentFrequencyNthDayTypeParameterName = "repaymentFrequencyNthDayType";
|
||||
public static final String repaymentFrequencyDayOfWeekTypeParameterName = "repaymentFrequencyDayOfWeekType";
|
||||
|
||||
// Floating interest rate related
|
||||
public static final String interestRateDifferentialParameterName = "interestRateDifferential";
|
||||
|
||||
+19
-3
@@ -372,6 +372,17 @@ public class LoansApiResource {
|
||||
loanBasicDetails = LoanAccountData.withInterestRecalculationCalendarData(loanBasicDetails, calendarData,
|
||||
compoundingCalendarData);
|
||||
}
|
||||
if (loanBasicDetails.isMonthlyRepaymentFrequencyType()) {
|
||||
Collection<CalendarData> loanCalendarDatas = this.calendarReadPlatformService
|
||||
.retrieveCalendarsByEntity(loanId,
|
||||
CalendarEntityType.LOANS.getValue(), null);
|
||||
CalendarData calendarData = null;
|
||||
if (!CollectionUtils.isEmpty(loanCalendarDatas)) {
|
||||
calendarData = loanCalendarDatas.iterator().next();
|
||||
}
|
||||
if(calendarData != null)
|
||||
loanBasicDetails = LoanAccountData.withLoanCalendarData(loanBasicDetails, calendarData);
|
||||
}
|
||||
|
||||
Collection<InterestRatePeriodData> interestRatesPeriods = this.loanReadPlatformService.retrieveLoanInterestRatePeriodData(loanId);
|
||||
|
||||
@@ -484,6 +495,8 @@ public class LoansApiResource {
|
||||
LoanProductData product = null;
|
||||
Collection<EnumOptionData> loanTermFrequencyTypeOptions = null;
|
||||
Collection<EnumOptionData> repaymentFrequencyTypeOptions = null;
|
||||
Collection<EnumOptionData> repaymentFrequencyNthDayTypeOptions = null;
|
||||
Collection<EnumOptionData> repaymentFrequencyDayOfWeekTypeOptions = null;
|
||||
Collection<TransactionProcessingStrategyData> repaymentStrategyOptions = null;
|
||||
Collection<EnumOptionData> interestRateFrequencyTypeOptions = null;
|
||||
Collection<EnumOptionData> amortizationTypeOptions = null;
|
||||
@@ -506,6 +519,8 @@ public class LoansApiResource {
|
||||
loanBasicDetails.setProduct(product);
|
||||
loanTermFrequencyTypeOptions = this.dropdownReadPlatformService.retrieveLoanTermFrequencyTypeOptions();
|
||||
repaymentFrequencyTypeOptions = this.dropdownReadPlatformService.retrieveRepaymentFrequencyTypeOptions();
|
||||
repaymentFrequencyNthDayTypeOptions = this.dropdownReadPlatformService.retrieveRepaymentFrequencyOptionsForNthDayOfMonth();
|
||||
repaymentFrequencyDayOfWeekTypeOptions = this.dropdownReadPlatformService.retrieveRepaymentFrequencyOptionsForDaysOfWeek();
|
||||
interestRateFrequencyTypeOptions = this.dropdownReadPlatformService.retrieveInterestRateFrequencyTypeOptions();
|
||||
|
||||
amortizationTypeOptions = this.dropdownReadPlatformService.retrieveLoanAmortizationTypeOptions();
|
||||
@@ -559,9 +574,10 @@ public class LoansApiResource {
|
||||
|
||||
final LoanAccountData loanAccount = LoanAccountData.associationsAndTemplate(loanBasicDetails, repaymentSchedule, loanRepayments,
|
||||
charges, collateral, guarantors, meeting, productOptions, loanTermFrequencyTypeOptions, repaymentFrequencyTypeOptions,
|
||||
null, null, repaymentStrategyOptions, interestRateFrequencyTypeOptions, amortizationTypeOptions, interestTypeOptions,
|
||||
interestCalculationPeriodTypeOptions, fundOptions, chargeOptions, chargeTemplate, allowedLoanOfficers, loanPurposeOptions,
|
||||
loanCollateralOptions, calendarOptions, notes, accountLinkingOptions, linkedAccount, disbursementData, emiAmountVariations,
|
||||
repaymentFrequencyNthDayTypeOptions, repaymentFrequencyDayOfWeekTypeOptions, repaymentStrategyOptions,
|
||||
interestRateFrequencyTypeOptions, amortizationTypeOptions, interestTypeOptions, interestCalculationPeriodTypeOptions,
|
||||
fundOptions, chargeOptions, chargeTemplate, allowedLoanOfficers, loanPurposeOptions, loanCollateralOptions,
|
||||
calendarOptions, notes, accountLinkingOptions, linkedAccount, disbursementData, emiAmountVariations,
|
||||
overdueCharges, paidInAdvanceTemplate, interestRatesPeriods);
|
||||
|
||||
final ApiRequestJsonSerializationSettings settings = this.apiRequestParameterHelper.process(uriInfo.getQueryParameters(),
|
||||
|
||||
+32
@@ -34,6 +34,7 @@ import org.apache.fineract.portfolio.account.data.PortfolioAccountData;
|
||||
import org.apache.fineract.portfolio.calendar.data.CalendarData;
|
||||
import org.apache.fineract.portfolio.charge.data.ChargeData;
|
||||
import org.apache.fineract.portfolio.collateral.data.CollateralData;
|
||||
import org.apache.fineract.portfolio.common.domain.PeriodFrequencyType;
|
||||
import org.apache.fineract.portfolio.floatingrates.data.InterestRatePeriodData;
|
||||
import org.apache.fineract.portfolio.fund.data.FundData;
|
||||
import org.apache.fineract.portfolio.group.data.GroupGeneralData;
|
||||
@@ -1143,6 +1144,33 @@ public class LoanAccountData {
|
||||
acc.isVariableInstallmentsAllowed, acc.minimumGap, acc.maximumGap);
|
||||
}
|
||||
|
||||
public static LoanAccountData withLoanCalendarData(final LoanAccountData acc, final CalendarData calendarData) {
|
||||
return new LoanAccountData(acc.id, acc.accountNo, acc.status, acc.externalId, acc.clientId, acc.clientAccountNo, acc.clientName,
|
||||
acc.clientOfficeId, acc.group, acc.loanType, acc.loanProductId, acc.loanProductName, acc.loanProductDescription,
|
||||
acc.isLoanProductLinkedToFloatingRate, acc.fundId, acc.fundName, acc.loanPurposeId, acc.loanPurposeName, acc.loanOfficerId,
|
||||
acc.loanOfficerName, acc.currency, acc.proposedPrincipal, acc.principal, acc.approvedPrincipal, acc.totalOverpaid,
|
||||
acc.inArrearsTolerance, acc.termFrequency, acc.termPeriodFrequencyType, acc.numberOfRepayments, acc.repaymentEvery,
|
||||
acc.repaymentFrequencyType, calendarData.getRepeatsOnNthDayOfMonth(), calendarData.getRepeatsOnDay(),
|
||||
acc.transactionProcessingStrategyId, acc.transactionProcessingStrategyName, acc.amortizationType,
|
||||
acc.interestRatePerPeriod, acc.interestRateFrequencyType, acc.annualInterestRate, acc.interestType,
|
||||
acc.isFloatingInterestRate, acc.interestRateDifferential, acc.interestCalculationPeriodType,
|
||||
acc.allowPartialPeriodInterestCalcualtion, acc.expectedFirstRepaymentOnDate, acc.graceOnPrincipalPayment,
|
||||
acc.recurringMoratoriumOnPrincipalPeriods, acc.graceOnInterestPayment, acc.graceOnInterestCharged,
|
||||
acc.interestChargedFromDate, acc.timeline, acc.summary, acc.feeChargesAtDisbursementCharged, acc.repaymentSchedule,
|
||||
acc.transactions, acc.charges, acc.collateral, acc.guarantors, acc.meeting, acc.productOptions,
|
||||
acc.termFrequencyTypeOptions, acc.repaymentFrequencyTypeOptions, acc.repaymentFrequencyNthDayTypeOptions,
|
||||
acc.repaymentFrequencyDaysOfWeekTypeOptions, acc.transactionProcessingStrategyOptions,
|
||||
acc.interestRateFrequencyTypeOptions, acc.amortizationTypeOptions, acc.interestTypeOptions,
|
||||
acc.interestCalculationPeriodTypeOptions, acc.fundOptions, acc.chargeOptions, null, acc.loanOfficerOptions,
|
||||
acc.loanPurposeOptions, acc.loanCollateralOptions, acc.calendarOptions, acc.syncDisbursementWithMeeting, acc.loanCounter,
|
||||
acc.loanProductCounter, acc.notes, acc.accountLinkingOptions, acc.linkedAccount, acc.disbursementDetails,
|
||||
acc.multiDisburseLoan, acc.canDefineInstallmentAmount, acc.fixedEmiAmount, acc.maxOutstandingLoanBalance,
|
||||
acc.emiAmountVariations, acc.memberVariations, acc.product, acc.inArrears, acc.graceOnArrearsAgeing, acc.overdueCharges,
|
||||
acc.isNPA, acc.daysInMonthType, acc.daysInYearType, acc.isInterestRecalculationEnabled, acc.interestRecalculationData,
|
||||
acc.originalSchedule, acc.createStandingInstructionAtDisbursement, acc.paidInAdvance, acc.interestRatesPeriods,
|
||||
acc.isVariableInstallmentsAllowed, acc.minimumGap, acc.maximumGap);
|
||||
}
|
||||
|
||||
public static LoanAccountData withOriginalSchedule(final LoanAccountData acc, final LoanScheduleData originalSchedule) {
|
||||
|
||||
return new LoanAccountData(acc.id, acc.accountNo, acc.status, acc.externalId, acc.clientId, acc.clientAccountNo, acc.clientName,
|
||||
@@ -1518,4 +1546,8 @@ public class LoanAccountData {
|
||||
return BigDecimal.ZERO;
|
||||
}
|
||||
|
||||
public boolean isMonthlyRepaymentFrequencyType() {
|
||||
return (this.repaymentFrequencyType.getId().intValue() == PeriodFrequencyType.MONTHS.getValue());
|
||||
}
|
||||
|
||||
}
|
||||
+27
-9
@@ -20,7 +20,6 @@ package org.apache.fineract.portfolio.loanaccount.data;
|
||||
|
||||
import org.apache.fineract.infrastructure.core.data.EnumOptionData;
|
||||
import org.apache.fineract.portfolio.calendar.data.CalendarData;
|
||||
import org.joda.time.LocalDate;
|
||||
|
||||
public class LoanInterestRecalculationData {
|
||||
|
||||
@@ -32,19 +31,29 @@ public class LoanInterestRecalculationData {
|
||||
private final CalendarData calendarData;
|
||||
private final EnumOptionData recalculationRestFrequencyType;
|
||||
private final Integer recalculationRestFrequencyInterval;
|
||||
private final LocalDate recalculationRestFrequencyDate;
|
||||
/* private final LocalDate recalculationRestFrequencyDate; */
|
||||
private final EnumOptionData recalculationRestFrequencyNthDay;
|
||||
private final EnumOptionData recalculationRestFrequencyWeekday;
|
||||
private final Integer recalculationRestFrequencyOnDay;
|
||||
private final EnumOptionData recalculationCompoundingFrequencyType;
|
||||
private final Integer recalculationCompoundingFrequencyInterval;
|
||||
private final LocalDate recalculationCompoundingFrequencyDate;
|
||||
/* private final LocalDate recalculationCompoundingFrequencyDate; */
|
||||
private final EnumOptionData recalculationCompoundingFrequencyNthDay;
|
||||
private final EnumOptionData recalculationCompoundingFrequencyWeekday;
|
||||
private final Integer recalculationCompoundingFrequencyOnDay;
|
||||
private final Boolean isCompoundingToBePostedAsTransaction;
|
||||
@SuppressWarnings("unused")
|
||||
private final CalendarData compoundingCalendarData;
|
||||
private final Boolean allowCompoundingOnEod;
|
||||
|
||||
public LoanInterestRecalculationData(final Long id, final Long loanId, final EnumOptionData interestRecalculationCompoundingType,
|
||||
final EnumOptionData rescheduleStrategyType, final CalendarData calendarData,
|
||||
final EnumOptionData recalculationRestFrequencyType, final Integer recalculationRestFrequencyInterval,
|
||||
final LocalDate recalculationRestFrequencyDate, final CalendarData compoundingCalendarData,
|
||||
final EnumOptionData recalculationRestFrequencyNthDay, final EnumOptionData recalculationRestFrequencyWeekday,
|
||||
final Integer recalculationRestFrequencyOnDay, final CalendarData compoundingCalendarData,
|
||||
final EnumOptionData recalculationCompoundingFrequencyType, final Integer recalculationCompoundingFrequencyInterval,
|
||||
final LocalDate recalculationCompoundingFrequencyDate) {
|
||||
final EnumOptionData recalculationCompoundingFrequencyNthDay, final EnumOptionData recalculationCompoundingFrequencyWeekday,
|
||||
final Integer recalculationCompoundingFrequencyOnDay, final Boolean isCompoundingToBePostedAsTransaction, final Boolean allowCompoundingOnEod) {
|
||||
this.id = id;
|
||||
this.loanId = loanId;
|
||||
this.interestRecalculationCompoundingType = interestRecalculationCompoundingType;
|
||||
@@ -52,11 +61,17 @@ public class LoanInterestRecalculationData {
|
||||
this.calendarData = calendarData;
|
||||
this.recalculationRestFrequencyType = recalculationRestFrequencyType;
|
||||
this.recalculationRestFrequencyInterval = recalculationRestFrequencyInterval;
|
||||
this.recalculationRestFrequencyDate = recalculationRestFrequencyDate;
|
||||
this.recalculationRestFrequencyNthDay = recalculationRestFrequencyNthDay;
|
||||
this.recalculationRestFrequencyWeekday = recalculationRestFrequencyWeekday;
|
||||
this.recalculationRestFrequencyOnDay = recalculationRestFrequencyOnDay;
|
||||
this.recalculationCompoundingFrequencyType = recalculationCompoundingFrequencyType;
|
||||
this.recalculationCompoundingFrequencyInterval = recalculationCompoundingFrequencyInterval;
|
||||
this.recalculationCompoundingFrequencyDate = recalculationCompoundingFrequencyDate;
|
||||
this.recalculationCompoundingFrequencyNthDay = recalculationCompoundingFrequencyNthDay;
|
||||
this.recalculationCompoundingFrequencyWeekday = recalculationCompoundingFrequencyWeekday;
|
||||
this.recalculationCompoundingFrequencyOnDay = recalculationCompoundingFrequencyOnDay;
|
||||
this.compoundingCalendarData = compoundingCalendarData;
|
||||
this.isCompoundingToBePostedAsTransaction = isCompoundingToBePostedAsTransaction;
|
||||
this.allowCompoundingOnEod = allowCompoundingOnEod;
|
||||
}
|
||||
|
||||
public static LoanInterestRecalculationData withCalendarData(final LoanInterestRecalculationData recalculationData,
|
||||
@@ -64,9 +79,12 @@ public class LoanInterestRecalculationData {
|
||||
return new LoanInterestRecalculationData(recalculationData.id, recalculationData.loanId,
|
||||
recalculationData.interestRecalculationCompoundingType, recalculationData.rescheduleStrategyType, calendarData,
|
||||
recalculationData.recalculationRestFrequencyType, recalculationData.recalculationRestFrequencyInterval,
|
||||
recalculationData.recalculationRestFrequencyDate, compoundingCalendarData,
|
||||
recalculationData.recalculationRestFrequencyNthDay, recalculationData.recalculationRestFrequencyWeekday,
|
||||
recalculationData.recalculationRestFrequencyOnDay, compoundingCalendarData,
|
||||
recalculationData.recalculationCompoundingFrequencyType, recalculationData.recalculationCompoundingFrequencyInterval,
|
||||
recalculationData.recalculationCompoundingFrequencyDate);
|
||||
recalculationData.recalculationCompoundingFrequencyNthDay, recalculationData.recalculationCompoundingFrequencyWeekday,
|
||||
recalculationData.recalculationCompoundingFrequencyOnDay, recalculationData.isCompoundingToBePostedAsTransaction,
|
||||
recalculationData.allowCompoundingOnEod);
|
||||
}
|
||||
|
||||
public Long getId() {
|
||||
|
||||
+327
-116
@@ -24,6 +24,7 @@ import java.math.RoundingMode;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Collection;
|
||||
import java.util.Collections;
|
||||
import java.util.Comparator;
|
||||
import java.util.Date;
|
||||
import java.util.HashMap;
|
||||
import java.util.HashSet;
|
||||
@@ -76,6 +77,7 @@ import org.apache.fineract.portfolio.calendar.data.CalendarHistoryDataWrapper;
|
||||
import org.apache.fineract.portfolio.calendar.domain.Calendar;
|
||||
import org.apache.fineract.portfolio.calendar.domain.CalendarHistory;
|
||||
import org.apache.fineract.portfolio.calendar.domain.CalendarInstance;
|
||||
import org.apache.fineract.portfolio.calendar.domain.CalendarWeekDaysType;
|
||||
import org.apache.fineract.portfolio.calendar.service.CalendarUtils;
|
||||
import org.apache.fineract.portfolio.charge.domain.Charge;
|
||||
import org.apache.fineract.portfolio.charge.domain.ChargeCalculationType;
|
||||
@@ -115,7 +117,6 @@ import org.apache.fineract.portfolio.loanaccount.loanschedule.domain.LoanApplica
|
||||
import org.apache.fineract.portfolio.loanaccount.loanschedule.domain.LoanScheduleGenerator;
|
||||
import org.apache.fineract.portfolio.loanaccount.loanschedule.domain.LoanScheduleModel;
|
||||
import org.apache.fineract.portfolio.loanaccount.loanschedule.domain.LoanScheduleModelPeriod;
|
||||
import org.apache.fineract.portfolio.loanproduct.LoanProductConstants;
|
||||
import org.apache.fineract.portfolio.loanproduct.domain.AmortizationMethod;
|
||||
import org.apache.fineract.portfolio.loanproduct.domain.InterestCalculationPeriodMethod;
|
||||
import org.apache.fineract.portfolio.loanproduct.domain.InterestMethod;
|
||||
@@ -192,12 +193,6 @@ public class Loan extends AbstractPersistable<Long> {
|
||||
@Embedded
|
||||
private LoanProductRelatedDetail loanRepaymentScheduleDetail;
|
||||
|
||||
@Column(name = "repayment_frequency_nth_day_enum", nullable = true)
|
||||
private Integer repaymentFrequencyNthDayType;
|
||||
|
||||
@Column(name = "repayment_frequency_day_of_week_enum", nullable = true)
|
||||
private Integer repaymentFrequencyDayOfWeekType;
|
||||
|
||||
@Column(name = "term_frequency", nullable = false)
|
||||
private Integer termFrequency;
|
||||
|
||||
@@ -858,7 +853,7 @@ public class Loan extends AbstractPersistable<Long> {
|
||||
if (loanCharge.isOverdueInstallmentCharge()) { return loanCharge.getAmountPercentageAppliedTo(); }
|
||||
switch (loanCharge.getChargeCalculation()) {
|
||||
case PERCENT_OF_AMOUNT:
|
||||
amount = getDerivedAmountForCharge(loanCharge);
|
||||
amount = getDerivedAmountForCharge(loanCharge);
|
||||
break;
|
||||
case PERCENT_OF_AMOUNT_AND_INTEREST:
|
||||
final BigDecimal totalInterestCharged = getTotalInterest();
|
||||
@@ -1135,7 +1130,8 @@ public class Loan extends AbstractPersistable<Long> {
|
||||
scheduledLoanInstallment.periodNumber(), scheduledLoanInstallment.periodFromDate(),
|
||||
scheduledLoanInstallment.periodDueDate(), scheduledLoanInstallment.principalDue(),
|
||||
scheduledLoanInstallment.interestDue(), scheduledLoanInstallment.feeChargesDue(),
|
||||
scheduledLoanInstallment.penaltyChargesDue(), scheduledLoanInstallment.isRecalculatedInterestComponent());
|
||||
scheduledLoanInstallment.penaltyChargesDue(), scheduledLoanInstallment.isRecalculatedInterestComponent(),
|
||||
scheduledLoanInstallment.getLoanCompoundingDetails());
|
||||
addRepaymentScheduleInstallment(installment);
|
||||
}
|
||||
}
|
||||
@@ -1194,6 +1190,13 @@ public class Loan extends AbstractPersistable<Long> {
|
||||
}
|
||||
installment.updateAccrualPortion(interest, fee, penality);
|
||||
}
|
||||
LoanRepaymentScheduleInstallment lastInstallment = this.repaymentScheduleInstallments
|
||||
.get(this.repaymentScheduleInstallments.size() - 1);
|
||||
for (LoanTransaction loanTransaction : accruals) {
|
||||
if (loanTransaction.getTransactionDate().isAfter(lastInstallment.getDueDate()) && !loanTransaction.isReversed()) {
|
||||
loanTransaction.reverse();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private void updateAccrualsForNonPeriodicAccruals(final Collection<LoanTransaction> accruals, final AppUser currentUser) {
|
||||
@@ -1265,12 +1268,6 @@ public class Loan extends AbstractPersistable<Long> {
|
||||
|
||||
final String dateFormatAsInput = command.dateFormat();
|
||||
final String localeAsInput = command.locale();
|
||||
final LocalDate recalculationRestFrequencyDate = command
|
||||
.localDateValueOfParameterNamed(LoanProductConstants.recalculationRestFrequencyDateParamName);
|
||||
final LocalDate recalculationCompoundingFrequencyDate = command
|
||||
.localDateValueOfParameterNamed(LoanProductConstants.recalculationCompoundingFrequencyDateParamName);
|
||||
updateLoanInterestRecalculationSettings(recalculationRestFrequencyDate, recalculationCompoundingFrequencyDate, command,
|
||||
actualChanges);
|
||||
|
||||
final String accountNoParamName = "accountNo";
|
||||
if (command.isChangeInStringParameterNamed(accountNoParamName, this.accountNumber)) {
|
||||
@@ -1556,37 +1553,6 @@ public class Loan extends AbstractPersistable<Long> {
|
||||
/**
|
||||
* Update interest recalculation settings if product configuration changes
|
||||
*/
|
||||
public void updateLoanInterestRecalculationSettings(final LocalDate recalculationRestFrequencyDate,
|
||||
final LocalDate recalculationCompoundingFrequencyDate, final JsonCommand command, final Map<String, Object> actualChanges) {
|
||||
|
||||
if (isInterestRecalculationEnabledForProduct()) {
|
||||
Date restFrequencyDate = null;
|
||||
if (recalculationRestFrequencyDate != null) {
|
||||
restFrequencyDate = recalculationRestFrequencyDate.toDate();
|
||||
}
|
||||
|
||||
Date compoundingFrequencyDate = null;
|
||||
if (recalculationCompoundingFrequencyDate != null) {
|
||||
compoundingFrequencyDate = recalculationCompoundingFrequencyDate.toDate();
|
||||
}
|
||||
if (this.loanInterestRecalculationDetails == null) {
|
||||
actualChanges.put(LoanProductConstants.isInterestRecalculationEnabledParameterName, true);
|
||||
this.loanInterestRecalculationDetails = LoanInterestRecalculationDetails.createFrom(this.loanProduct
|
||||
.getProductInterestRecalculationDetails().getInterestRecalculationCompoundingMethod(), this.loanProduct
|
||||
.getProductInterestRecalculationDetails().getRescheduleStrategyMethod(), this.loanProduct
|
||||
.getProductInterestRecalculationDetails().getRestFrequencyType().getValue(), this.loanProduct
|
||||
.getProductInterestRecalculationDetails().getRestInterval(), restFrequencyDate, this.loanProduct
|
||||
.getProductInterestRecalculationDetails().getCompoundingFrequencyType().getValue(), this.loanProduct
|
||||
.getProductInterestRecalculationDetails().getCompoundingInterval(), compoundingFrequencyDate);
|
||||
this.loanInterestRecalculationDetails.updateLoan(this);
|
||||
} else {
|
||||
|
||||
this.loanInterestRecalculationDetails.update(command, actualChanges);
|
||||
}
|
||||
} else {
|
||||
this.loanInterestRecalculationDetails = null;
|
||||
}
|
||||
}
|
||||
|
||||
private void updateOverdueScheduleInstallment(final LoanCharge loanCharge) {
|
||||
if (loanCharge.isOverdueInstallmentCharge() && loanCharge.isActive()) {
|
||||
@@ -1911,8 +1877,7 @@ public class Loan extends AbstractPersistable<Long> {
|
||||
public void loanApplicationSubmittal(final AppUser currentUser, final LoanScheduleModel loanSchedule,
|
||||
final LoanApplicationTerms loanApplicationTerms, final LoanLifecycleStateMachine lifecycleStateMachine,
|
||||
final LocalDate submittedOn, final String externalId, final boolean allowTransactionsOnHoliday, final List<Holiday> holidays,
|
||||
final WorkingDays workingDays, final boolean allowTransactionsOnNonWorkingDay, final LocalDate recalculationRestFrequencyDate,
|
||||
final LocalDate recalculationCompoundingFrequencyDate) {
|
||||
final WorkingDays workingDays, final boolean allowTransactionsOnNonWorkingDay) {
|
||||
|
||||
updateLoanSchedule(loanSchedule, currentUser);
|
||||
|
||||
@@ -1933,14 +1898,6 @@ public class Loan extends AbstractPersistable<Long> {
|
||||
this.expectedFirstRepaymentOnDate = loanApplicationTerms.getRepaymentStartFromDate();
|
||||
this.interestChargedFromDate = loanApplicationTerms.getInterestChargedFromDate();
|
||||
|
||||
if (loanApplicationTerms.getRepaymentPeriodFrequencyType() == PeriodFrequencyType.MONTHS) {
|
||||
this.repaymentFrequencyNthDayType = loanApplicationTerms.getNthDay();
|
||||
this.repaymentFrequencyDayOfWeekType = loanApplicationTerms.getWeekDayType().getValue();
|
||||
} else {
|
||||
this.repaymentFrequencyNthDayType = NthDayType.INVALID.getValue();
|
||||
this.repaymentFrequencyDayOfWeekType = DayOfWeekType.INVALID.getValue();
|
||||
}
|
||||
|
||||
updateLoanScheduleDependentDerivedFields();
|
||||
|
||||
if (submittedOn.isAfter(DateUtils.getLocalDateOfTenant())) {
|
||||
@@ -1984,22 +1941,9 @@ public class Loan extends AbstractPersistable<Long> {
|
||||
* enabled
|
||||
*/
|
||||
if (this.loanRepaymentScheduleDetail.isInterestRecalculationEnabled()) {
|
||||
Date restFrequencyDate = null;
|
||||
if (recalculationRestFrequencyDate != null) {
|
||||
restFrequencyDate = recalculationRestFrequencyDate.toDate();
|
||||
}
|
||||
|
||||
Date compoundingFrequencyDate = null;
|
||||
if (recalculationCompoundingFrequencyDate != null) {
|
||||
compoundingFrequencyDate = recalculationCompoundingFrequencyDate.toDate();
|
||||
}
|
||||
this.loanInterestRecalculationDetails = LoanInterestRecalculationDetails.createFrom(this.loanProduct
|
||||
.getProductInterestRecalculationDetails().getInterestRecalculationCompoundingMethod(), this.loanProduct
|
||||
.getProductInterestRecalculationDetails().getRescheduleStrategyMethod(), this.loanProduct
|
||||
.getProductInterestRecalculationDetails().getRestFrequencyType().getValue(), this.loanProduct
|
||||
.getProductInterestRecalculationDetails().getRestInterval(), restFrequencyDate, this.loanProduct
|
||||
.getProductInterestRecalculationDetails().getCompoundingFrequencyType().getValue(), this.loanProduct
|
||||
.getProductInterestRecalculationDetails().getCompoundingInterval(), compoundingFrequencyDate);
|
||||
.getProductInterestRecalculationDetails());
|
||||
this.loanInterestRecalculationDetails.updateLoan(this);
|
||||
}
|
||||
|
||||
@@ -2299,7 +2243,7 @@ public class Loan extends AbstractPersistable<Long> {
|
||||
}
|
||||
|
||||
public ChangedTransactionDetail disburse(final AppUser currentUser, final JsonCommand command, final Map<String, Object> actualChanges,
|
||||
final ScheduleGeneratorDTO scheduleGeneratorDTO,final PaymentDetail paymentDetail) {
|
||||
final ScheduleGeneratorDTO scheduleGeneratorDTO, final PaymentDetail paymentDetail) {
|
||||
|
||||
final LoanStatus statusEnum = this.loanLifecycleStateMachine.transition(LoanEvent.LOAN_DISBURSED,
|
||||
LoanStatus.fromInt(this.loanStatus));
|
||||
@@ -2330,7 +2274,7 @@ public class Loan extends AbstractPersistable<Long> {
|
||||
updateSummaryWithTotalFeeChargesDueAtDisbursement(deriveSumTotalOfChargesDueAtDisbursement());
|
||||
updateLoanRepaymentPeriodsDerivedFields(actualDisbursementDate);
|
||||
LocalDateTime createdDate = DateUtils.getLocalDateTimeOfTenant();
|
||||
handleDisbursementTransaction(actualDisbursementDate, createdDate, currentUser,paymentDetail);
|
||||
handleDisbursementTransaction(actualDisbursementDate, createdDate, currentUser, paymentDetail);
|
||||
updateLoanSummaryDerivedFields();
|
||||
final Money interestApplied = Money.of(getCurrency(), this.summary.getTotalInterestCharged());
|
||||
|
||||
@@ -2380,8 +2324,13 @@ public class Loan extends AbstractPersistable<Long> {
|
||||
this.loanTermVariations.add(loanVariationTerms);
|
||||
}
|
||||
|
||||
if (isRepaymentScheduleRegenerationRequiredForDisbursement(actualDisbursementDate) || recalculateSchedule || isEmiAmountChanged || rescheduledRepaymentDate != null) {
|
||||
regenerateRepaymentSchedule(scheduleGeneratorDTO, currentUser);
|
||||
if (isRepaymentScheduleRegenerationRequiredForDisbursement(actualDisbursementDate) || recalculateSchedule || isEmiAmountChanged
|
||||
|| rescheduledRepaymentDate != null) {
|
||||
if (this.repaymentScheduleDetail().isInterestRecalculationEnabled()) {
|
||||
regenerateRepaymentScheduleWithInterestRecalculation(scheduleGeneratorDTO, currentUser);
|
||||
} else {
|
||||
regenerateRepaymentSchedule(scheduleGeneratorDTO, currentUser);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -2592,7 +2541,7 @@ public class Loan extends AbstractPersistable<Long> {
|
||||
updateLoanSchedule(loanSchedule, currentUser);
|
||||
Set<LoanCharge> charges = this.charges();
|
||||
for (LoanCharge loanCharge : charges) {
|
||||
recalculateLoanCharge(loanCharge, scheduleGeneratorDTO.getPenaltyWaitPeriod());
|
||||
recalculateLoanCharge(loanCharge, scheduleGeneratorDTO.getPenaltyWaitPeriod());
|
||||
}
|
||||
}
|
||||
|
||||
@@ -2633,7 +2582,8 @@ public class Loan extends AbstractPersistable<Long> {
|
||||
return interestRate;
|
||||
}
|
||||
|
||||
private void handleDisbursementTransaction(final LocalDate disbursedOn, final LocalDateTime createdDate, final AppUser currentUser, final PaymentDetail paymentDetail) {
|
||||
private void handleDisbursementTransaction(final LocalDate disbursedOn, final LocalDateTime createdDate, final AppUser currentUser,
|
||||
final PaymentDetail paymentDetail) {
|
||||
|
||||
// add repayment transaction to track incoming money from client to mfi
|
||||
// for (charges due at time of disbursement)
|
||||
@@ -2651,14 +2601,14 @@ public class Loan extends AbstractPersistable<Long> {
|
||||
**/
|
||||
|
||||
Money disbursentMoney = Money.zero(getCurrency());
|
||||
final LoanTransaction chargesPayment = LoanTransaction.repaymentAtDisbursement(getOffice(), disbursentMoney, paymentDetail, disbursedOn,
|
||||
null, createdDate, currentUser);
|
||||
final LoanTransaction chargesPayment = LoanTransaction.repaymentAtDisbursement(getOffice(), disbursentMoney, paymentDetail,
|
||||
disbursedOn, null, createdDate, currentUser);
|
||||
final Integer installmentNumber = null;
|
||||
for (final LoanCharge charge : charges()) {
|
||||
Date actualDisbursementDate = getActualDisbursementDate(charge);
|
||||
if ((charge.getCharge().getChargeTimeType() == ChargeTimeType.DISBURSEMENT.getValue()
|
||||
&& disbursedOn.equals(new LocalDate(actualDisbursementDate)) && actualDisbursementDate != null
|
||||
&& !charge.isWaived() && !charge.isFullyPaid())
|
||||
if ((charge.getCharge().getChargeTimeType() == ChargeTimeType.DISBURSEMENT.getValue()
|
||||
&& disbursedOn.equals(new LocalDate(actualDisbursementDate)) && actualDisbursementDate != null && !charge.isWaived() && !charge
|
||||
.isFullyPaid())
|
||||
|| (charge.getCharge().getChargeTimeType() == ChargeTimeType.TRANCHE_DISBURSEMENT.getValue()
|
||||
&& disbursedOn.equals(new LocalDate(actualDisbursementDate)) && actualDisbursementDate != null
|
||||
&& !charge.isWaived() && !charge.isFullyPaid())) {
|
||||
@@ -3088,6 +3038,18 @@ public class Loan extends AbstractPersistable<Long> {
|
||||
return installment;
|
||||
}
|
||||
|
||||
private List<LoanTransaction> retreiveListOfIncomePostingTransactions() {
|
||||
final List<LoanTransaction> incomePostTransactions = new ArrayList<>();
|
||||
for (final LoanTransaction transaction : this.loanTransactions) {
|
||||
if (transaction.isNotReversed() && transaction.isIncomePosting()) {
|
||||
incomePostTransactions.add(transaction);
|
||||
}
|
||||
}
|
||||
final LoanTransactionComparator transactionComparator = new LoanTransactionComparator();
|
||||
Collections.sort(incomePostTransactions, transactionComparator);
|
||||
return incomePostTransactions;
|
||||
}
|
||||
|
||||
private List<LoanTransaction> retreiveListOfTransactionsPostDisbursement() {
|
||||
final List<LoanTransaction> repaymentsOrWaivers = new ArrayList<>();
|
||||
for (final LoanTransaction transaction : this.loanTransactions) {
|
||||
@@ -3104,8 +3066,8 @@ public class Loan extends AbstractPersistable<Long> {
|
||||
final List<LoanTransaction> repaymentsOrWaivers = new ArrayList<>();
|
||||
for (final LoanTransaction transaction : this.loanTransactions) {
|
||||
if (transaction.isNotReversed()
|
||||
&& !(transaction.isDisbursement() || transaction.isAccrual() || transaction.isRepaymentAtDisbursement() || transaction
|
||||
.isNonMonetaryTransaction())) {
|
||||
&& !(transaction.isDisbursement() || transaction.isAccrual() || transaction.isRepaymentAtDisbursement()
|
||||
|| transaction.isNonMonetaryTransaction() || transaction.isIncomePosting())) {
|
||||
repaymentsOrWaivers.add(transaction);
|
||||
}
|
||||
}
|
||||
@@ -3169,6 +3131,71 @@ public class Loan extends AbstractPersistable<Long> {
|
||||
LoanStatus.fromInt(this.loanStatus));
|
||||
this.loanStatus = statusEnum.getValue();
|
||||
}
|
||||
processIncomeAccrualTransactionOnLoanClosure();
|
||||
}
|
||||
|
||||
private void processIncomeAccrualTransactionOnLoanClosure() {
|
||||
if (this.loanInterestRecalculationDetails != null && this.loanInterestRecalculationDetails.isCompoundingToBePostedAsTransaction()
|
||||
&& this.status().isClosedObligationsMet()) {
|
||||
Date closedDate = this.getClosedOnDate();
|
||||
LocalDate closedLocalDate = new LocalDate(closedDate);
|
||||
reverseTransactionsOnOrAfter(retreiveListOfIncomePostingTransactions(), closedDate);
|
||||
reverseTransactionsOnOrAfter(retreiveListOfAccrualTransactions(), closedDate);
|
||||
HashMap<String, BigDecimal> cumulativeIncomeFromInstallments = new HashMap<>();
|
||||
determineCumulativeIncomeFromInstallments(cumulativeIncomeFromInstallments);
|
||||
HashMap<String, BigDecimal> cumulativeIncomeFromIncomePosting = new HashMap<>();
|
||||
determineCumulativeIncomeDetails(retreiveListOfIncomePostingTransactions(), cumulativeIncomeFromIncomePosting);
|
||||
BigDecimal interestToPost = cumulativeIncomeFromInstallments.get("interest").subtract(
|
||||
cumulativeIncomeFromIncomePosting.get("interest"));
|
||||
BigDecimal feeToPost = cumulativeIncomeFromInstallments.get("fee").subtract(cumulativeIncomeFromIncomePosting.get("fee"));
|
||||
BigDecimal penaltyToPost = cumulativeIncomeFromInstallments.get("penalty").subtract(
|
||||
cumulativeIncomeFromIncomePosting.get("penalty"));
|
||||
BigDecimal amountToPost = interestToPost.add(feeToPost).add(penaltyToPost);
|
||||
LoanTransaction finalIncomeTransaction = LoanTransaction.incomePosting(this, this.getOffice(), closedDate, amountToPost,
|
||||
interestToPost, feeToPost, penaltyToPost, null);
|
||||
this.loanTransactions.add(finalIncomeTransaction);
|
||||
if (isPeriodicAccrualAccountingEnabledOnLoanProduct()) {
|
||||
List<LoanTransaction> updatedAccrualTransactions = retreiveListOfAccrualTransactions();
|
||||
LocalDate lastAccruedDate = this.getDisbursementDate();
|
||||
if (updatedAccrualTransactions != null && updatedAccrualTransactions.size() > 0) {
|
||||
lastAccruedDate = updatedAccrualTransactions.get(updatedAccrualTransactions.size() - 1).getTransactionDate();
|
||||
}
|
||||
HashMap<String, Object> feeDetails = new HashMap<>();
|
||||
determineFeeDetails(lastAccruedDate, closedLocalDate, feeDetails);
|
||||
LoanTransaction finalAccrual = LoanTransaction.accrueTransaction(this, this.getOffice(), closedLocalDate, amountToPost,
|
||||
interestToPost, feeToPost, penaltyToPost, null);
|
||||
updateLoanChargesPaidBy(finalAccrual, feeDetails, null);
|
||||
this.loanTransactions.add(finalAccrual);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private void determineCumulativeIncomeFromInstallments(HashMap<String, BigDecimal> cumulativeIncomeFromInstallments) {
|
||||
BigDecimal interest = BigDecimal.ZERO;
|
||||
BigDecimal fee = BigDecimal.ZERO;
|
||||
BigDecimal penalty = BigDecimal.ZERO;
|
||||
for (LoanRepaymentScheduleInstallment installment : this.repaymentScheduleInstallments) {
|
||||
interest = interest.add(installment.getInterestCharged(getCurrency()).getAmount());
|
||||
fee = fee.add(installment.getFeeChargesCharged(getCurrency()).getAmount());
|
||||
penalty = penalty.add(installment.getPenaltyChargesCharged(getCurrency()).getAmount());
|
||||
}
|
||||
cumulativeIncomeFromInstallments.put("interest", interest);
|
||||
cumulativeIncomeFromInstallments.put("fee", fee);
|
||||
cumulativeIncomeFromInstallments.put("penalty", penalty);
|
||||
}
|
||||
|
||||
private void determineCumulativeIncomeDetails(Collection<LoanTransaction> transactions, HashMap<String, BigDecimal> incomeDetailsMap) {
|
||||
BigDecimal interest = BigDecimal.ZERO;
|
||||
BigDecimal fee = BigDecimal.ZERO;
|
||||
BigDecimal penalty = BigDecimal.ZERO;
|
||||
for (LoanTransaction transaction : transactions) {
|
||||
interest = interest.add(transaction.getInterestPortion(getCurrency()).getAmount());
|
||||
fee = fee.add(transaction.getFeeChargesPortion(getCurrency()).getAmount());
|
||||
penalty = penalty.add(transaction.getPenaltyChargesPortion(getCurrency()).getAmount());
|
||||
}
|
||||
incomeDetailsMap.put("interest", interest);
|
||||
incomeDetailsMap.put("fee", fee);
|
||||
incomeDetailsMap.put("penalty", penalty);
|
||||
}
|
||||
|
||||
private void handleLoanOverpayment(final LoanLifecycleStateMachine loanLifecycleStateMachine) {
|
||||
@@ -4566,7 +4593,7 @@ public class Loan extends AbstractPersistable<Long> {
|
||||
private LocalDate getLastUserTransactionDate() {
|
||||
LocalDate currentTransactionDate = getDisbursementDate();
|
||||
for (final LoanTransaction previousTransaction : this.loanTransactions) {
|
||||
if (!(previousTransaction.isReversed() || previousTransaction.isAccrual())) {
|
||||
if (!(previousTransaction.isReversed() || previousTransaction.isAccrual() || previousTransaction.isIncomePosting())) {
|
||||
if (currentTransactionDate.isBefore(previousTransaction.getTransactionDate())) {
|
||||
currentTransactionDate = previousTransaction.getTransactionDate();
|
||||
}
|
||||
@@ -4982,6 +5009,179 @@ public class Loan extends AbstractPersistable<Long> {
|
||||
}
|
||||
|
||||
processPostDisbursementTransactions();
|
||||
processIncomeTransactions(currentUser);
|
||||
}
|
||||
|
||||
private void updateLoanChargesPaidBy(LoanTransaction accrual, HashMap<String, Object> feeDetails,
|
||||
LoanRepaymentScheduleInstallment installment) {
|
||||
@SuppressWarnings("unchecked")
|
||||
List<LoanCharge> loanCharges = (List<LoanCharge>) feeDetails.get("loanCharges");
|
||||
@SuppressWarnings("unchecked")
|
||||
List<LoanInstallmentCharge> loanInstallmentCharges = (List<LoanInstallmentCharge>) feeDetails.get("loanInstallmentCharges");
|
||||
if (loanCharges != null) {
|
||||
for (LoanCharge loanCharge : loanCharges) {
|
||||
Integer installmentNumber = null == installment ? null : installment.getInstallmentNumber();
|
||||
final LoanChargePaidBy loanChargePaidBy = new LoanChargePaidBy(accrual, loanCharge, loanCharge.getAmount(getCurrency())
|
||||
.getAmount(), installmentNumber);
|
||||
accrual.getLoanChargesPaid().add(loanChargePaidBy);
|
||||
}
|
||||
}
|
||||
if (loanInstallmentCharges != null) {
|
||||
for (LoanInstallmentCharge loanInstallmentCharge : loanInstallmentCharges) {
|
||||
Integer installmentNumber = null == loanInstallmentCharge.getInstallment() ? null : loanInstallmentCharge.getInstallment()
|
||||
.getInstallmentNumber();
|
||||
final LoanChargePaidBy loanChargePaidBy = new LoanChargePaidBy(accrual, loanInstallmentCharge.getLoancharge(),
|
||||
loanInstallmentCharge.getAmount(getCurrency()).getAmount(), installmentNumber);
|
||||
accrual.getLoanChargesPaid().add(loanChargePaidBy);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public void processIncomeTransactions(AppUser currentUser) {
|
||||
if (this.loanInterestRecalculationDetails != null && this.loanInterestRecalculationDetails.isCompoundingToBePostedAsTransaction()) {
|
||||
LocalDate lastCompoundingDate = this.getDisbursementDate();
|
||||
List<LoanInterestRecalcualtionAdditionalDetails> compoundingDetails = extractInterestRecalculationAdditionalDetails();
|
||||
List<LoanTransaction> incomeTransactions = retreiveListOfIncomePostingTransactions();
|
||||
List<LoanTransaction> accrualTransactions = retreiveListOfAccrualTransactions();
|
||||
for (LoanInterestRecalcualtionAdditionalDetails compoundingDetail : compoundingDetails) {
|
||||
if (!compoundingDetail.getEffectiveDate().isBefore(DateUtils.getLocalDateOfTenant())) {
|
||||
break;
|
||||
}
|
||||
LoanTransaction incomeTransaction = getTransactionForDate(incomeTransactions, compoundingDetail.getEffectiveDate());
|
||||
LoanTransaction accrualTransaction = getTransactionForDate(accrualTransactions, compoundingDetail.getEffectiveDate());
|
||||
addUpdateIncomeAndAccrualTransaction(compoundingDetail, lastCompoundingDate, currentUser, incomeTransaction,
|
||||
accrualTransaction);
|
||||
lastCompoundingDate = compoundingDetail.getEffectiveDate();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private void reverseTransactionsOnOrAfter(List<LoanTransaction> transactions, Date date) {
|
||||
LocalDate refDate = new LocalDate(date);
|
||||
for (LoanTransaction loanTransaction : transactions) {
|
||||
if (!loanTransaction.getTransactionDate().isBefore(refDate)) {
|
||||
loanTransaction.reverse();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private void addUpdateIncomeAndAccrualTransaction(LoanInterestRecalcualtionAdditionalDetails compoundingDetail,
|
||||
LocalDate lastCompoundingDate, AppUser currentUser, LoanTransaction existingIncomeTransaction,
|
||||
LoanTransaction existingAccrualTransaction) {
|
||||
BigDecimal interest = BigDecimal.ZERO;
|
||||
BigDecimal fee = BigDecimal.ZERO;
|
||||
BigDecimal penalties = BigDecimal.ZERO;
|
||||
HashMap<String, Object> feeDetails = new HashMap<>();
|
||||
|
||||
if (this.loanInterestRecalculationDetails.getInterestRecalculationCompoundingMethod().equals(
|
||||
InterestRecalculationCompoundingMethod.INTEREST)) {
|
||||
interest = compoundingDetail.getAmount();
|
||||
} else if (this.loanInterestRecalculationDetails.getInterestRecalculationCompoundingMethod().equals(
|
||||
InterestRecalculationCompoundingMethod.FEE)) {
|
||||
determineFeeDetails(lastCompoundingDate, compoundingDetail.getEffectiveDate(), feeDetails);
|
||||
fee = (BigDecimal) feeDetails.get("fee");
|
||||
penalties = (BigDecimal) feeDetails.get("penalties");
|
||||
} else if (this.loanInterestRecalculationDetails.getInterestRecalculationCompoundingMethod().equals(
|
||||
InterestRecalculationCompoundingMethod.INTEREST_AND_FEE)) {
|
||||
determineFeeDetails(lastCompoundingDate, compoundingDetail.getEffectiveDate(), feeDetails);
|
||||
fee = (BigDecimal) feeDetails.get("fee");
|
||||
penalties = (BigDecimal) feeDetails.get("penalties");
|
||||
interest = compoundingDetail.getAmount().subtract(fee).subtract(penalties);
|
||||
}
|
||||
|
||||
if (existingIncomeTransaction == null) {
|
||||
LoanTransaction transaction = LoanTransaction.incomePosting(this, this.getOffice(), compoundingDetail.getEffectiveDate()
|
||||
.toDate(), compoundingDetail.getAmount(), interest, fee, penalties, currentUser);
|
||||
this.loanTransactions.add(transaction);
|
||||
} else if (existingIncomeTransaction.getAmount(getCurrency()).getAmount().compareTo(compoundingDetail.getAmount()) != 0) {
|
||||
existingIncomeTransaction.reverse();
|
||||
LoanTransaction transaction = LoanTransaction.incomePosting(this, this.getOffice(), compoundingDetail.getEffectiveDate()
|
||||
.toDate(), compoundingDetail.getAmount(), interest, fee, penalties, currentUser);
|
||||
this.loanTransactions.add(transaction);
|
||||
}
|
||||
|
||||
if (isPeriodicAccrualAccountingEnabledOnLoanProduct()) {
|
||||
if (existingAccrualTransaction == null) {
|
||||
LoanTransaction accrual = LoanTransaction.accrueTransaction(this, this.getOffice(), compoundingDetail.getEffectiveDate(),
|
||||
compoundingDetail.getAmount(), interest, fee, penalties, currentUser);
|
||||
updateLoanChargesPaidBy(accrual, feeDetails, null);
|
||||
this.loanTransactions.add(accrual);
|
||||
} else if (existingAccrualTransaction.getAmount(getCurrency()).getAmount().compareTo(compoundingDetail.getAmount()) != 0) {
|
||||
existingAccrualTransaction.reverse();
|
||||
LoanTransaction accrual = LoanTransaction.accrueTransaction(this, this.getOffice(), compoundingDetail.getEffectiveDate(),
|
||||
compoundingDetail.getAmount(), interest, fee, penalties, currentUser);
|
||||
updateLoanChargesPaidBy(accrual, feeDetails, null);
|
||||
this.loanTransactions.add(accrual);
|
||||
}
|
||||
}
|
||||
updateLoanOutstandingBalaces();
|
||||
}
|
||||
|
||||
private void determineFeeDetails(LocalDate fromDate, LocalDate toDate, HashMap<String, Object> feeDetails) {
|
||||
BigDecimal fee = BigDecimal.ZERO;
|
||||
BigDecimal penalties = BigDecimal.ZERO;
|
||||
|
||||
List<Integer> installments = new ArrayList<>();
|
||||
for (LoanRepaymentScheduleInstallment loanRepaymentScheduleInstallment : this.repaymentScheduleInstallments) {
|
||||
if (loanRepaymentScheduleInstallment.getDueDate().isAfter(fromDate)
|
||||
&& !loanRepaymentScheduleInstallment.getDueDate().isAfter(toDate)) {
|
||||
installments.add(loanRepaymentScheduleInstallment.getInstallmentNumber());
|
||||
}
|
||||
}
|
||||
|
||||
List<LoanCharge> loanCharges = new ArrayList<>();
|
||||
List<LoanInstallmentCharge> loanInstallmentCharges = new ArrayList<>();
|
||||
for (LoanCharge loanCharge : this.charges()) {
|
||||
if (loanCharge.isDueForCollectionFromAndUpToAndIncluding(fromDate, toDate)) {
|
||||
if (loanCharge.isPenaltyCharge() && !loanCharge.isInstalmentFee()) {
|
||||
penalties = penalties.add(loanCharge.amount());
|
||||
loanCharges.add(loanCharge);
|
||||
} else if (!loanCharge.isInstalmentFee()) {
|
||||
fee = fee.add(loanCharge.amount());
|
||||
loanCharges.add(loanCharge);
|
||||
}
|
||||
} else if (loanCharge.isInstalmentFee()) {
|
||||
for (LoanInstallmentCharge installmentCharge : loanCharge.installmentCharges()) {
|
||||
if (installments.contains(installmentCharge.getRepaymentInstallment().getInstallmentNumber())) {
|
||||
fee = fee.add(installmentCharge.getAmount());
|
||||
loanInstallmentCharges.add(installmentCharge);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
feeDetails.put("fee", fee);
|
||||
feeDetails.put("penalties", penalties);
|
||||
feeDetails.put("loanCharges", loanCharges);
|
||||
feeDetails.put("loanInstallmentCharges", loanInstallmentCharges);
|
||||
}
|
||||
|
||||
private LoanTransaction getTransactionForDate(List<LoanTransaction> transactions, LocalDate effectiveDate) {
|
||||
for (LoanTransaction loanTransaction : transactions) {
|
||||
if (loanTransaction.getTransactionDate().isEqual(effectiveDate)) { return loanTransaction; }
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
private List<LoanInterestRecalcualtionAdditionalDetails> extractInterestRecalculationAdditionalDetails() {
|
||||
List<LoanInterestRecalcualtionAdditionalDetails> retDetails = new ArrayList<>();
|
||||
if (null != this.repaymentScheduleInstallments && this.repaymentScheduleInstallments.size() > 0) {
|
||||
Iterator<LoanRepaymentScheduleInstallment> installmentsItr = this.repaymentScheduleInstallments.iterator();
|
||||
while (installmentsItr.hasNext()) {
|
||||
LoanRepaymentScheduleInstallment installment = installmentsItr.next();
|
||||
if (null != installment.getLoanCompoundingDetails()) {
|
||||
retDetails.addAll(installment.getLoanCompoundingDetails());
|
||||
}
|
||||
}
|
||||
}
|
||||
Collections.sort(retDetails, new Comparator<LoanInterestRecalcualtionAdditionalDetails>() {
|
||||
|
||||
@Override
|
||||
public int compare(LoanInterestRecalcualtionAdditionalDetails first, LoanInterestRecalcualtionAdditionalDetails second) {
|
||||
return first.getEffectiveDate().compareTo(second.getEffectiveDate());
|
||||
}
|
||||
});
|
||||
return retDetails;
|
||||
}
|
||||
|
||||
public void processPostDisbursementTransactions() {
|
||||
@@ -5044,21 +5244,27 @@ public class Loan extends AbstractPersistable<Long> {
|
||||
public LoanApplicationTerms constructLoanApplicationTerms(final ScheduleGeneratorDTO scheduleGeneratorDTO) {
|
||||
final Integer loanTermFrequency = this.termFrequency;
|
||||
final PeriodFrequencyType loanTermPeriodFrequencyType = PeriodFrequencyType.fromInt(this.termPeriodFrequencyType);
|
||||
final NthDayType nthDayType = NthDayType.fromInt(this.repaymentFrequencyNthDayType);
|
||||
final DayOfWeekType dayOfWeekType = DayOfWeekType.fromInt(this.repaymentFrequencyDayOfWeekType);
|
||||
NthDayType nthDayType = null;
|
||||
DayOfWeekType dayOfWeekType = null;
|
||||
final List<DisbursementData> disbursementData = new ArrayList<>();
|
||||
for (LoanDisbursementDetails disbursementDetails : this.disbursementDetails) {
|
||||
disbursementData.add(disbursementDetails.toData());
|
||||
}
|
||||
|
||||
Calendar calendar = scheduleGeneratorDTO.getCalendar();
|
||||
if (calendar != null) {
|
||||
nthDayType = CalendarUtils.getRepeatsOnNthDayOfMonth(calendar.getRecurrence());
|
||||
dayOfWeekType = DayOfWeekType.fromInt(CalendarUtils.getRepeatsOnDay(calendar.getRecurrence()).getValue());
|
||||
}
|
||||
HolidayDetailDTO holidayDetailDTO = scheduleGeneratorDTO.getHolidayDetailDTO();
|
||||
CalendarInstance restCalendarInstance = null;
|
||||
CalendarInstance compoundingCalendarInstance = null;
|
||||
RecalculationFrequencyType recalculationFrequencyType = null;
|
||||
InterestRecalculationCompoundingMethod compoundingMethod = null;
|
||||
RecalculationFrequencyType compoundingFrequencyType = null;
|
||||
LoanRescheduleStrategyMethod rescheduleStrategyMethod = null;
|
||||
Calendar calendar = null;
|
||||
CalendarHistoryDataWrapper calendarHistoryDataWrapper = null;
|
||||
boolean allowCompoundingOnEod = false;
|
||||
if (this.repaymentScheduleDetail().isInterestRecalculationEnabled()) {
|
||||
restCalendarInstance = scheduleGeneratorDTO.getCalendarInstanceForInterestRecalculation();
|
||||
compoundingCalendarInstance = scheduleGeneratorDTO.getCompoundingCalendarInstance();
|
||||
@@ -5066,6 +5272,8 @@ public class Loan extends AbstractPersistable<Long> {
|
||||
compoundingMethod = this.loanInterestRecalculationDetails.getInterestRecalculationCompoundingMethod();
|
||||
compoundingFrequencyType = this.loanInterestRecalculationDetails.getCompoundingFrequencyType();
|
||||
rescheduleStrategyMethod = this.loanInterestRecalculationDetails.getRescheduleStrategyMethod();
|
||||
allowCompoundingOnEod = this.loanInterestRecalculationDetails.allowCompoundingOnEod();
|
||||
calendarHistoryDataWrapper = scheduleGeneratorDTO.getCalendarHistoryDataWrapper();
|
||||
}
|
||||
calendar = scheduleGeneratorDTO.getCalendar();
|
||||
calendarHistoryDataWrapper = scheduleGeneratorDTO.getCalendarHistoryDataWrapper();
|
||||
@@ -5075,7 +5283,7 @@ public class Loan extends AbstractPersistable<Long> {
|
||||
List<LoanTermVariationsData> loanTermVariations = new ArrayList<>();
|
||||
annualNominalInterestRate = constructLoanTermVariations(floatingRateDTO, annualNominalInterestRate, loanTermVariations);
|
||||
LocalDate interestChargedFromDate = getInterestChargedFromDate();
|
||||
if(interestChargedFromDate == null && scheduleGeneratorDTO.isInterestChargedFromDateAsDisbursementDateEnabled()){
|
||||
if (interestChargedFromDate == null && scheduleGeneratorDTO.isInterestChargedFromDateAsDisbursementDateEnabled()) {
|
||||
interestChargedFromDate = getDisbursementDate();
|
||||
}
|
||||
|
||||
@@ -5087,7 +5295,7 @@ public class Loan extends AbstractPersistable<Long> {
|
||||
this.loanProduct.getInstallmentAmountInMultiplesOf(), recalculationFrequencyType, restCalendarInstance, compoundingMethod,
|
||||
compoundingCalendarInstance, compoundingFrequencyType, this.loanProduct.preCloseInterestCalculationStrategy(),
|
||||
rescheduleStrategyMethod, calendar, getApprovedPrincipal(), annualNominalInterestRate, loanTermVariations, calendarHistoryDataWrapper,
|
||||
scheduleGeneratorDTO.getNumberOfdays(), scheduleGeneratorDTO.isSkipRepaymentOnFirstDayofMonth());
|
||||
scheduleGeneratorDTO.getNumberOfdays(), scheduleGeneratorDTO.isSkipRepaymentOnFirstDayofMonth(), holidayDetailDTO, allowCompoundingOnEod);
|
||||
return loanApplicationTerms;
|
||||
}
|
||||
|
||||
@@ -5105,6 +5313,7 @@ public class Loan extends AbstractPersistable<Long> {
|
||||
Money penaltyCharges = Money.zero(loanCurrency());
|
||||
Money totalPrincipal = Money.zero(loanCurrency());
|
||||
Money totalInterest = Money.zero(loanCurrency());
|
||||
final List<LoanInterestRecalcualtionAdditionalDetails> compoundingDetails = null;
|
||||
for (final LoanRepaymentScheduleInstallment scheduledRepayment : this.repaymentScheduleInstallments) {
|
||||
totalPrincipal = totalPrincipal.plus(scheduledRepayment.getPrincipalOutstanding(loanCurrency()));
|
||||
totalInterest = totalInterest.plus(scheduledRepayment.getInterestOutstanding(loanCurrency()));
|
||||
@@ -5112,7 +5321,7 @@ public class Loan extends AbstractPersistable<Long> {
|
||||
penaltyCharges = penaltyCharges.plus(scheduledRepayment.getPenaltyChargesOutstanding(loanCurrency()));
|
||||
}
|
||||
return new LoanRepaymentScheduleInstallment(null, 0, LocalDate.now(), LocalDate.now(), totalPrincipal.getAmount(),
|
||||
totalInterest.getAmount(), feeCharges.getAmount(), penaltyCharges.getAmount(), false);
|
||||
totalInterest.getAmount(), feeCharges.getAmount(), penaltyCharges.getAmount(), false, compoundingDetails);
|
||||
}
|
||||
|
||||
public List<LoanRepaymentScheduleInstallment> fetchRepaymentScheduleInstallments() {
|
||||
@@ -5141,11 +5350,17 @@ public class Loan extends AbstractPersistable<Long> {
|
||||
Money outstanding = Money.zero(getCurrency());
|
||||
List<LoanTransaction> loanTransactions = retreiveListOfTransactionsExcludeAccruals();
|
||||
for (LoanTransaction loanTransaction : loanTransactions) {
|
||||
if (loanTransaction.isDisbursement()) {
|
||||
if (loanTransaction.isDisbursement() || loanTransaction.isIncomePosting()) {
|
||||
outstanding = outstanding.plus(loanTransaction.getAmount(getCurrency()));
|
||||
loanTransaction.updateOutstandingLoanBalance(outstanding.getAmount());
|
||||
} else {
|
||||
outstanding = outstanding.minus(loanTransaction.getPrincipalPortion(getCurrency()));
|
||||
if (this.loanInterestRecalculationDetails != null
|
||||
&& this.loanInterestRecalculationDetails.isCompoundingToBePostedAsTransaction()
|
||||
&& !loanTransaction.isRepaymentAtDisbursement()) {
|
||||
outstanding = outstanding.minus(loanTransaction.getAmount(getCurrency()));
|
||||
} else {
|
||||
outstanding = outstanding.minus(loanTransaction.getPrincipalPortion(getCurrency()));
|
||||
}
|
||||
loanTransaction.updateOutstandingLoanBalance(outstanding.getAmount());
|
||||
}
|
||||
}
|
||||
@@ -5252,7 +5467,8 @@ public class Loan extends AbstractPersistable<Long> {
|
||||
@SuppressWarnings({ "unused" })
|
||||
public LoanApplicationTerms getLoanApplicationTerms(final ApplicationCurrency applicationCurrency,
|
||||
final CalendarInstance restCalendarInstance, CalendarInstance compoundingCalendarInstance, final Calendar loanCalendar,
|
||||
final FloatingRateDTO floatingRateDTO, final boolean isSkipRepaymentonmonthFirst, final Integer numberofdays) {
|
||||
final FloatingRateDTO floatingRateDTO, final boolean isSkipRepaymentonmonthFirst, final Integer numberofdays,
|
||||
final HolidayDetailDTO holidayDetailDTO) {
|
||||
LoanProduct loanProduct = loanProduct();
|
||||
// LoanProductRelatedDetail loanProductRelatedDetail =
|
||||
// getLoanRepaymentScheduleDetail();
|
||||
@@ -5260,8 +5476,15 @@ public class Loan extends AbstractPersistable<Long> {
|
||||
|
||||
final Integer loanTermFrequency = getTermFrequency();
|
||||
final PeriodFrequencyType loanTermPeriodFrequencyType = this.loanRepaymentScheduleDetail.getInterestPeriodFrequencyType();
|
||||
final NthDayType nthDayType = NthDayType.fromInt(this.repaymentFrequencyNthDayType);
|
||||
final DayOfWeekType dayOfWeekType = DayOfWeekType.fromInt(this.repaymentFrequencyDayOfWeekType);
|
||||
NthDayType nthDayType = null;
|
||||
DayOfWeekType dayOfWeekType = null;
|
||||
if (loanCalendar != null) {
|
||||
nthDayType = CalendarUtils.getRepeatsOnNthDayOfMonth(loanCalendar.getRecurrence());
|
||||
CalendarWeekDaysType getRepeatsOnDay = CalendarUtils.getRepeatsOnDay(loanCalendar.getRecurrence());
|
||||
Integer getRepeatsOnDayValue = null;
|
||||
if (getRepeatsOnDay != null) getRepeatsOnDayValue = getRepeatsOnDay.getValue();
|
||||
if (getRepeatsOnDayValue != null) dayOfWeekType = DayOfWeekType.fromInt(getRepeatsOnDayValue);
|
||||
}
|
||||
|
||||
final Integer numberOfRepayments = this.loanRepaymentScheduleDetail.getNumberOfRepayments();
|
||||
final Integer repaymentEvery = this.loanRepaymentScheduleDetail.getRepayEvery();
|
||||
@@ -5304,7 +5527,7 @@ public class Loan extends AbstractPersistable<Long> {
|
||||
final BigDecimal maxOutstandingBalance = getMaxOutstandingLoanBalance();
|
||||
|
||||
final List<DisbursementData> disbursementData = getDisbursmentData();
|
||||
|
||||
|
||||
CalendarHistoryDataWrapper calendarHistoryDataWrapper = null;
|
||||
if (loanCalendar != null) {
|
||||
Set<CalendarHistory> calendarHistory = loanCalendar.getCalendarHistory();
|
||||
@@ -5315,11 +5538,13 @@ public class Loan extends AbstractPersistable<Long> {
|
||||
InterestRecalculationCompoundingMethod compoundingMethod = null;
|
||||
RecalculationFrequencyType compoundingFrequencyType = null;
|
||||
LoanRescheduleStrategyMethod rescheduleStrategyMethod = null;
|
||||
boolean allowCompoundingOnEod = false;
|
||||
if (this.repaymentScheduleDetail().isInterestRecalculationEnabled()) {
|
||||
recalculationFrequencyType = this.loanInterestRecalculationDetails.getRestFrequencyType();
|
||||
compoundingMethod = this.loanInterestRecalculationDetails.getInterestRecalculationCompoundingMethod();
|
||||
compoundingFrequencyType = this.loanInterestRecalculationDetails.getCompoundingFrequencyType();
|
||||
rescheduleStrategyMethod = this.loanInterestRecalculationDetails.getRescheduleStrategyMethod();
|
||||
allowCompoundingOnEod = this.loanInterestRecalculationDetails.allowCompoundingOnEod();
|
||||
}
|
||||
|
||||
List<LoanTermVariationsData> loanTermVariations = new ArrayList<>();
|
||||
@@ -5332,7 +5557,7 @@ public class Loan extends AbstractPersistable<Long> {
|
||||
this.loanProduct.getInstallmentAmountInMultiplesOf(), recalculationFrequencyType, restCalendarInstance, compoundingMethod,
|
||||
compoundingCalendarInstance, compoundingFrequencyType, this.loanProduct.preCloseInterestCalculationStrategy(),
|
||||
rescheduleStrategyMethod, loanCalendar, getApprovedPrincipal(), annualNominalInterestRate, loanTermVariations,
|
||||
calendarHistoryDataWrapper, numberofdays, isSkipRepaymentonmonthFirst);
|
||||
calendarHistoryDataWrapper, numberofdays, isSkipRepaymentonmonthFirst, holidayDetailDTO, allowCompoundingOnEod);
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -5376,22 +5601,6 @@ public class Loan extends AbstractPersistable<Long> {
|
||||
return isEnabled;
|
||||
}
|
||||
|
||||
public Integer getRepaymentFrequencyNthDayType() {
|
||||
return this.repaymentFrequencyNthDayType;
|
||||
}
|
||||
|
||||
public void setRepaymentFrequencyNthDayType(Integer repaymentFrequencyNthDayType) {
|
||||
this.repaymentFrequencyNthDayType = repaymentFrequencyNthDayType;
|
||||
}
|
||||
|
||||
public Integer getRepaymentFrequencyDayOfWeekType() {
|
||||
return this.repaymentFrequencyDayOfWeekType;
|
||||
}
|
||||
|
||||
public void setRepaymentFrequencyDayOfWeekType(Integer repaymentFrequencyDayOfWeekType) {
|
||||
this.repaymentFrequencyDayOfWeekType = repaymentFrequencyDayOfWeekType;
|
||||
}
|
||||
|
||||
public String getAccountNumber() {
|
||||
return this.accountNumber;
|
||||
}
|
||||
@@ -5597,8 +5806,10 @@ public class Loan extends AbstractPersistable<Long> {
|
||||
updateLoanToLastDisbursalState(actualDisbursementDate);
|
||||
for (Iterator<LoanTermVariations> iterator = this.loanTermVariations.iterator(); iterator.hasNext();) {
|
||||
LoanTermVariations loanTermVariations = iterator.next();
|
||||
if (loanTermVariations.getTermType().isDueDateVariation() && loanTermVariations.fetchDateValue().isAfter(actualDisbursementDate) ||
|
||||
loanTermVariations.getTermType().isEMIAmountVariation() && loanTermVariations.getTermApplicableFrom().equals(actualDisbursementDate.toDate())
|
||||
if (loanTermVariations.getTermType().isDueDateVariation()
|
||||
&& loanTermVariations.fetchDateValue().isAfter(actualDisbursementDate)
|
||||
|| loanTermVariations.getTermType().isEMIAmountVariation()
|
||||
&& loanTermVariations.getTermApplicableFrom().equals(actualDisbursementDate.toDate())
|
||||
|| loanTermVariations.getTermApplicableFrom().after(actualDisbursementDate.toDate())) {
|
||||
iterator.remove();
|
||||
}
|
||||
@@ -5722,7 +5933,7 @@ public class Loan extends AbstractPersistable<Long> {
|
||||
}
|
||||
return nextRepaymentDate;
|
||||
}
|
||||
|
||||
|
||||
public BigDecimal getDerivedAmountForCharge(LoanCharge loanCharge) {
|
||||
BigDecimal amount = BigDecimal.ZERO;
|
||||
if (isMultiDisburmentLoan() && (loanCharge.getCharge().getChargeTimeType() == ChargeTimeType.DISBURSEMENT.getValue())) {
|
||||
|
||||
+6
@@ -288,4 +288,10 @@ public class LoanInstallmentCharge extends AbstractPersistable<Long> {
|
||||
return amountToDeductOnThisCharge;
|
||||
}
|
||||
|
||||
public LoanCharge getLoancharge() {
|
||||
return this.loancharge;
|
||||
}
|
||||
public LoanRepaymentScheduleInstallment getInstallment() {
|
||||
return this.installment;
|
||||
}
|
||||
}
|
||||
+62
@@ -0,0 +1,62 @@
|
||||
/**
|
||||
* Licensed to the Apache Software Foundation (ASF) under one
|
||||
* or more contributor license agreements. See the NOTICE file
|
||||
* distributed with this work for additional information
|
||||
* regarding copyright ownership. The ASF licenses this file
|
||||
* to you under the Apache License, Version 2.0 (the
|
||||
* "License"); you may not use this file except in compliance
|
||||
* with the License. You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing,
|
||||
* software distributed under the License is distributed on an
|
||||
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
|
||||
* KIND, either express or implied. See the License for the
|
||||
* specific language governing permissions and limitations
|
||||
* under the License.
|
||||
*/
|
||||
package org.apache.fineract.portfolio.loanaccount.domain;
|
||||
|
||||
import java.math.BigDecimal;
|
||||
import java.util.Date;
|
||||
|
||||
import javax.persistence.Column;
|
||||
import javax.persistence.Entity;
|
||||
import javax.persistence.Table;
|
||||
import javax.persistence.Temporal;
|
||||
import javax.persistence.TemporalType;
|
||||
|
||||
import org.joda.time.LocalDate;
|
||||
import org.springframework.data.jpa.domain.AbstractPersistable;
|
||||
|
||||
@Entity
|
||||
@Table(name = "m_loan_interest_recalculation_additional_details")
|
||||
public class LoanInterestRecalcualtionAdditionalDetails extends AbstractPersistable<Long> {
|
||||
|
||||
@Temporal(TemporalType.DATE)
|
||||
@Column(name = "effective_date")
|
||||
private Date effectiveDate;
|
||||
|
||||
@Column(name = "amount", scale = 6, precision = 19, nullable = false)
|
||||
private BigDecimal amount;
|
||||
|
||||
protected LoanInterestRecalcualtionAdditionalDetails() {
|
||||
|
||||
}
|
||||
|
||||
public LoanInterestRecalcualtionAdditionalDetails(final LocalDate effectiveDate, final BigDecimal amount) {
|
||||
if (effectiveDate != null) {
|
||||
this.effectiveDate = effectiveDate.toDate();
|
||||
}
|
||||
this.amount = amount;
|
||||
}
|
||||
|
||||
public LocalDate getEffectiveDate() {
|
||||
return new LocalDate(this.effectiveDate);
|
||||
}
|
||||
|
||||
public BigDecimal getAmount() {
|
||||
return this.amount;
|
||||
}
|
||||
}
|
||||
+78
-79
@@ -18,23 +18,16 @@
|
||||
*/
|
||||
package org.apache.fineract.portfolio.loanaccount.domain;
|
||||
|
||||
import java.util.Date;
|
||||
import java.util.Map;
|
||||
|
||||
import javax.persistence.Column;
|
||||
import javax.persistence.Entity;
|
||||
import javax.persistence.JoinColumn;
|
||||
import javax.persistence.OneToOne;
|
||||
import javax.persistence.Table;
|
||||
import javax.persistence.Temporal;
|
||||
import javax.persistence.TemporalType;
|
||||
|
||||
import org.apache.fineract.infrastructure.core.api.JsonCommand;
|
||||
import org.apache.fineract.portfolio.loanproduct.LoanProductConstants;
|
||||
import org.apache.fineract.portfolio.loanproduct.domain.InterestRecalculationCompoundingMethod;
|
||||
import org.apache.fineract.portfolio.loanproduct.domain.LoanProductInterestRecalculationDetails;
|
||||
import org.apache.fineract.portfolio.loanproduct.domain.LoanRescheduleStrategyMethod;
|
||||
import org.apache.fineract.portfolio.loanproduct.domain.RecalculationFrequencyType;
|
||||
import org.joda.time.LocalDate;
|
||||
import org.springframework.data.jpa.domain.AbstractPersistable;
|
||||
|
||||
/**
|
||||
@@ -70,9 +63,14 @@ public class LoanInterestRecalculationDetails extends AbstractPersistable<Long>
|
||||
@Column(name = "rest_frequency_interval", nullable = false)
|
||||
private Integer restInterval;
|
||||
|
||||
@Temporal(TemporalType.DATE)
|
||||
@Column(name = "rest_freqency_date")
|
||||
private Date restFrequencyDate;
|
||||
@Column(name = "rest_frequency_nth_day_enum", nullable = true)
|
||||
private Integer restFrequencyNthDay;
|
||||
|
||||
@Column(name = "rest_frequency_weekday_enum", nullable = true)
|
||||
private Integer restFrequencyWeekday;
|
||||
|
||||
@Column(name = "rest_frequency_on_day", nullable = true)
|
||||
private Integer restFrequencyOnDay;
|
||||
|
||||
@Column(name = "compounding_frequency_type_enum", nullable = true)
|
||||
private Integer compoundingFrequencyType;
|
||||
@@ -80,78 +78,63 @@ public class LoanInterestRecalculationDetails extends AbstractPersistable<Long>
|
||||
@Column(name = "compounding_frequency_interval", nullable = true)
|
||||
private Integer compoundingInterval;
|
||||
|
||||
@Temporal(TemporalType.DATE)
|
||||
@Column(name = "compounding_freqency_date")
|
||||
private Date compoundingFrequencyDate;
|
||||
@Column(name = "compounding_frequency_nth_day_enum", nullable = true)
|
||||
private Integer compoundingFrequencyNthDay;
|
||||
@Column(name = "compounding_frequency_weekday_enum", nullable = true)
|
||||
private Integer compoundingFrequencyWeekday;
|
||||
@Column(name = "compounding_frequency_on_day", nullable = true)
|
||||
private Integer compoundingFrequencyOnDay;
|
||||
|
||||
@Column(name = "is_compounding_to_be_posted_as_transaction")
|
||||
private Boolean isCompoundingToBePostedAsTransaction;
|
||||
@Column(name = "allow_compounding_on_eod")
|
||||
private Boolean allowCompoundingOnEod;
|
||||
|
||||
protected LoanInterestRecalculationDetails() {
|
||||
// Default constructor for jpa repository
|
||||
}
|
||||
|
||||
private LoanInterestRecalculationDetails(final Integer interestRecalculationCompoundingMethod, final Integer rescheduleStrategyMethod,
|
||||
final Integer restFrequencyType, final Integer restInterval, final Date restFrequencyDate, Integer compoundingFrequencyType,
|
||||
Integer compoundingInterval, Date compoundingFrequencyDate) {
|
||||
final Integer restFrequencyType, final Integer restInterval, final Integer restFrequencyNthDay, Integer restFrequencyWeekday,
|
||||
Integer restFrequencyOnDay, Integer compoundingFrequencyType, Integer compoundingInterval, Integer compoundingFrequencyNthDay,
|
||||
Integer compoundingFrequencyWeekday, Integer compoundingFrequencyOnDay, final boolean isCompoundingToBePostedAsTransaction,
|
||||
final boolean allowCompoundingOnEod) {
|
||||
this.interestRecalculationCompoundingMethod = interestRecalculationCompoundingMethod;
|
||||
this.rescheduleStrategyMethod = rescheduleStrategyMethod;
|
||||
this.restFrequencyDate = restFrequencyDate;
|
||||
this.restFrequencyNthDay = restFrequencyNthDay;
|
||||
this.restFrequencyWeekday = restFrequencyWeekday;
|
||||
this.restFrequencyOnDay = restFrequencyOnDay;
|
||||
this.restFrequencyType = restFrequencyType;
|
||||
this.restInterval = restInterval;
|
||||
this.compoundingFrequencyDate = compoundingFrequencyDate;
|
||||
this.compoundingFrequencyNthDay = compoundingFrequencyNthDay;
|
||||
this.compoundingFrequencyWeekday = compoundingFrequencyWeekday;
|
||||
this.compoundingFrequencyOnDay = compoundingFrequencyOnDay;
|
||||
this.compoundingFrequencyType = compoundingFrequencyType;
|
||||
this.compoundingInterval = compoundingInterval;
|
||||
this.isCompoundingToBePostedAsTransaction = isCompoundingToBePostedAsTransaction;
|
||||
this.allowCompoundingOnEod = allowCompoundingOnEod;
|
||||
}
|
||||
|
||||
public static LoanInterestRecalculationDetails createFrom(final Integer interestRecalculationCompoundingMethod,
|
||||
final Integer rescheduleStrategyMethod, final Integer restFrequencyType, final Integer restInterval,
|
||||
final Date restFrequencyDate, final Integer compoundingFrequencyType, final Integer compoundingInterval,
|
||||
final Date compoundingFrequencyDate) {
|
||||
return new LoanInterestRecalculationDetails(interestRecalculationCompoundingMethod, rescheduleStrategyMethod, restFrequencyType,
|
||||
restInterval, restFrequencyDate, compoundingFrequencyType, compoundingInterval, compoundingFrequencyDate);
|
||||
public static LoanInterestRecalculationDetails createFrom(
|
||||
final LoanProductInterestRecalculationDetails loanProductInterestRecalculationDetails) {
|
||||
return new LoanInterestRecalculationDetails(loanProductInterestRecalculationDetails.getInterestRecalculationCompoundingMethod(),
|
||||
loanProductInterestRecalculationDetails.getRescheduleStrategyMethod(), loanProductInterestRecalculationDetails
|
||||
.getRestFrequencyType().getValue(), loanProductInterestRecalculationDetails.getRestInterval(),
|
||||
loanProductInterestRecalculationDetails.getRestFrequencyNthDay(),
|
||||
loanProductInterestRecalculationDetails.getRestFrequencyWeekday(),
|
||||
loanProductInterestRecalculationDetails.getRestFrequencyOnDay(), loanProductInterestRecalculationDetails
|
||||
.getCompoundingFrequencyType().getValue(), loanProductInterestRecalculationDetails.getCompoundingInterval(),
|
||||
loanProductInterestRecalculationDetails.getCompoundingFrequencyNthDay(),
|
||||
loanProductInterestRecalculationDetails.getCompoundingFrequencyWeekday(),
|
||||
loanProductInterestRecalculationDetails.getCompoundingFrequencyOnDay(),
|
||||
loanProductInterestRecalculationDetails.getIsCompoundingToBePostedAsTransaction(),
|
||||
loanProductInterestRecalculationDetails.allowCompoundingOnEod());
|
||||
}
|
||||
|
||||
public void updateLoan(final Loan loan) {
|
||||
this.loan = loan;
|
||||
}
|
||||
|
||||
public void update(final JsonCommand command, final Map<String, Object> actualChanges) {
|
||||
if (command.isChangeInLocalDateParameterNamed(LoanProductConstants.recalculationRestFrequencyDateParamName,
|
||||
getRestFrequencyLocalDate())) {
|
||||
final String dateFormatAsInput = command.dateFormat();
|
||||
final String localeAsInput = command.locale();
|
||||
final String valueAsInput = command.stringValueOfParameterNamed(LoanProductConstants.recalculationRestFrequencyDateParamName);
|
||||
actualChanges.put(LoanProductConstants.recalculationRestFrequencyDateParamName, valueAsInput);
|
||||
actualChanges.put("dateFormat", dateFormatAsInput);
|
||||
actualChanges.put("locale", localeAsInput);
|
||||
|
||||
final LocalDate newValue = command.localDateValueOfParameterNamed(LoanProductConstants.recalculationRestFrequencyDateParamName);
|
||||
if (newValue == null || getRestFrequencyType().isSameAsRepayment()) {
|
||||
this.restFrequencyDate = null;
|
||||
} else {
|
||||
this.restFrequencyDate = newValue.toDate();
|
||||
}
|
||||
}
|
||||
|
||||
if (command.isChangeInLocalDateParameterNamed(LoanProductConstants.recalculationCompoundingFrequencyDateParamName,
|
||||
getCompoundingFrequencyLocalDate())) {
|
||||
final String dateFormatAsInput = command.dateFormat();
|
||||
final String localeAsInput = command.locale();
|
||||
final String valueAsInput = command
|
||||
.stringValueOfParameterNamed(LoanProductConstants.recalculationCompoundingFrequencyDateParamName);
|
||||
actualChanges.put(LoanProductConstants.recalculationCompoundingFrequencyDateParamName, valueAsInput);
|
||||
actualChanges.put("dateFormat", dateFormatAsInput);
|
||||
actualChanges.put("locale", localeAsInput);
|
||||
|
||||
final LocalDate newValue = command
|
||||
.localDateValueOfParameterNamed(LoanProductConstants.recalculationCompoundingFrequencyDateParamName);
|
||||
if (newValue == null || !getInterestRecalculationCompoundingMethod().isCompoundingEnabled()
|
||||
|| getCompoundingFrequencyType().isSameAsRepayment()) {
|
||||
this.compoundingFrequencyDate = null;
|
||||
} else {
|
||||
this.compoundingFrequencyDate = newValue.toDate();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public InterestRecalculationCompoundingMethod getInterestRecalculationCompoundingMethod() {
|
||||
return InterestRecalculationCompoundingMethod.fromInt(this.interestRecalculationCompoundingMethod);
|
||||
}
|
||||
@@ -160,14 +143,6 @@ public class LoanInterestRecalculationDetails extends AbstractPersistable<Long>
|
||||
return LoanRescheduleStrategyMethod.fromInt(this.rescheduleStrategyMethod);
|
||||
}
|
||||
|
||||
public LocalDate getRestFrequencyLocalDate() {
|
||||
LocalDate recurrenceOnLocalDate = null;
|
||||
if (this.restFrequencyDate != null) {
|
||||
recurrenceOnLocalDate = new LocalDate(this.restFrequencyDate);
|
||||
}
|
||||
return recurrenceOnLocalDate;
|
||||
}
|
||||
|
||||
public RecalculationFrequencyType getRestFrequencyType() {
|
||||
return RecalculationFrequencyType.fromInt(this.restFrequencyType);
|
||||
}
|
||||
@@ -176,14 +151,6 @@ public class LoanInterestRecalculationDetails extends AbstractPersistable<Long>
|
||||
return this.restInterval;
|
||||
}
|
||||
|
||||
public LocalDate getCompoundingFrequencyLocalDate() {
|
||||
LocalDate recurrenceOnLocalDate = null;
|
||||
if (this.compoundingFrequencyDate != null) {
|
||||
recurrenceOnLocalDate = new LocalDate(this.compoundingFrequencyDate);
|
||||
}
|
||||
return recurrenceOnLocalDate;
|
||||
}
|
||||
|
||||
public RecalculationFrequencyType getCompoundingFrequencyType() {
|
||||
return RecalculationFrequencyType.fromInt(this.compoundingFrequencyType);
|
||||
}
|
||||
@@ -191,4 +158,36 @@ public class LoanInterestRecalculationDetails extends AbstractPersistable<Long>
|
||||
public Integer getCompoundingInterval() {
|
||||
return this.compoundingInterval;
|
||||
}
|
||||
|
||||
public Integer getRestFrequencyNthDay() {
|
||||
return this.restFrequencyNthDay;
|
||||
}
|
||||
|
||||
public Integer getRestFrequencyWeekday() {
|
||||
return this.restFrequencyWeekday;
|
||||
}
|
||||
|
||||
public Integer getRestFrequencyOnDay() {
|
||||
return this.restFrequencyOnDay;
|
||||
}
|
||||
|
||||
public Integer getCompoundingFrequencyNthDay() {
|
||||
return this.compoundingFrequencyNthDay;
|
||||
}
|
||||
|
||||
public Integer getCompoundingFrequencyWeekday() {
|
||||
return this.compoundingFrequencyWeekday;
|
||||
}
|
||||
|
||||
public Integer getCompoundingFrequencyOnDay() {
|
||||
return this.compoundingFrequencyOnDay;
|
||||
}
|
||||
|
||||
public boolean isCompoundingToBePostedAsTransaction() {
|
||||
return null == this.isCompoundingToBePostedAsTransaction ? false : this.isCompoundingToBePostedAsTransaction;
|
||||
}
|
||||
|
||||
public boolean allowCompoundingOnEod() {
|
||||
return this.allowCompoundingOnEod;
|
||||
}
|
||||
}
|
||||
|
||||
+16
-1
@@ -19,13 +19,17 @@
|
||||
package org.apache.fineract.portfolio.loanaccount.domain;
|
||||
|
||||
import java.math.BigDecimal;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Comparator;
|
||||
import java.util.Date;
|
||||
import java.util.List;
|
||||
|
||||
import javax.persistence.CascadeType;
|
||||
import javax.persistence.Column;
|
||||
import javax.persistence.Entity;
|
||||
import javax.persistence.JoinColumn;
|
||||
import javax.persistence.ManyToOne;
|
||||
import javax.persistence.OneToMany;
|
||||
import javax.persistence.Table;
|
||||
import javax.persistence.Temporal;
|
||||
import javax.persistence.TemporalType;
|
||||
@@ -34,6 +38,8 @@ import org.apache.fineract.infrastructure.core.domain.AbstractAuditableCustom;
|
||||
import org.apache.fineract.organisation.monetary.domain.MonetaryCurrency;
|
||||
import org.apache.fineract.organisation.monetary.domain.Money;
|
||||
import org.apache.fineract.useradministration.domain.AppUser;
|
||||
import org.hibernate.annotations.LazyCollection;
|
||||
import org.hibernate.annotations.LazyCollectionOption;
|
||||
import org.joda.time.LocalDate;
|
||||
|
||||
@Entity
|
||||
@@ -125,6 +131,10 @@ public final class LoanRepaymentScheduleInstallment extends AbstractAuditableCus
|
||||
@Column(name = "recalculated_interest_component", nullable = false)
|
||||
private boolean recalculatedInterestComponent;
|
||||
|
||||
@LazyCollection(LazyCollectionOption.FALSE)
|
||||
@OneToMany(cascade = CascadeType.ALL, orphanRemoval = true)
|
||||
@JoinColumn(name = "loan_repayment_schedule_id", referencedColumnName = "id", nullable = false)
|
||||
private List<LoanInterestRecalcualtionAdditionalDetails> loanCompoundingDetails = new ArrayList<>();
|
||||
protected LoanRepaymentScheduleInstallment() {
|
||||
this.installmentNumber = null;
|
||||
this.fromDate = null;
|
||||
@@ -134,7 +144,8 @@ public final class LoanRepaymentScheduleInstallment extends AbstractAuditableCus
|
||||
|
||||
public LoanRepaymentScheduleInstallment(final Loan loan, final Integer installmentNumber, final LocalDate fromDate,
|
||||
final LocalDate dueDate, final BigDecimal principal, final BigDecimal interest, final BigDecimal feeCharges,
|
||||
final BigDecimal penaltyCharges, boolean recalculatedInterestComponent) {
|
||||
final BigDecimal penaltyCharges, final boolean recalculatedInterestComponent,
|
||||
final List<LoanInterestRecalcualtionAdditionalDetails> compoundingDetails) {
|
||||
this.loan = loan;
|
||||
this.installmentNumber = installmentNumber;
|
||||
this.fromDate = fromDate.toDateTimeAtStartOfDay().toDate();
|
||||
@@ -145,6 +156,7 @@ public final class LoanRepaymentScheduleInstallment extends AbstractAuditableCus
|
||||
this.penaltyCharges = defaultToNullIfZero(penaltyCharges);
|
||||
this.obligationsMet = false;
|
||||
this.recalculatedInterestComponent = recalculatedInterestComponent;
|
||||
this.loanCompoundingDetails = compoundingDetails;
|
||||
}
|
||||
|
||||
public LoanRepaymentScheduleInstallment(final Loan loan) {
|
||||
@@ -770,4 +782,7 @@ public final class LoanRepaymentScheduleInstallment extends AbstractAuditableCus
|
||||
public Money getDue(MonetaryCurrency currency) {
|
||||
return getPrincipal(currency).plus(getInterestCharged(currency)).plus(getFeeChargesCharged(currency)).plus(getPenaltyChargesCharged(currency));
|
||||
}
|
||||
public List<LoanInterestRecalcualtionAdditionalDetails> getLoanCompoundingDetails() {
|
||||
return this.loanCompoundingDetails;
|
||||
}
|
||||
}
|
||||
+29
@@ -146,6 +146,19 @@ public final class LoanTransaction extends AbstractPersistable<Long> {
|
||||
this.appUser = null;
|
||||
}
|
||||
|
||||
public static LoanTransaction incomePosting(final Loan loan, final Office office, final Date dateOf,
|
||||
final BigDecimal amount, final BigDecimal interestPortion, final BigDecimal feeChargesPortion,
|
||||
final BigDecimal penaltyChargesPortion, final AppUser appUser){
|
||||
final Integer typeOf = LoanTransactionType.INCOME_POSTING.getValue();
|
||||
final BigDecimal principalPortion = BigDecimal.ZERO;
|
||||
final BigDecimal overPaymentPortion = BigDecimal.ZERO;
|
||||
final boolean reversed = false;
|
||||
final PaymentDetail paymentDetail = null;
|
||||
final String externalId = null;
|
||||
final LocalDateTime createdDate = DateUtils.getLocalDateTimeOfTenant();
|
||||
return new LoanTransaction(loan, office, typeOf, dateOf, amount, principalPortion, interestPortion, feeChargesPortion,
|
||||
penaltyChargesPortion, overPaymentPortion, reversed, paymentDetail, externalId, createdDate, appUser);
|
||||
}
|
||||
public static LoanTransaction disbursement(final Office office, final Money amount, final PaymentDetail paymentDetail,
|
||||
final LocalDate disbursementDate, final String externalId, final LocalDateTime createdDate, final AppUser appUser) {
|
||||
return new LoanTransaction(null, office, LoanTransactionType.DISBURSEMENT, paymentDetail, amount.getAmount(), disbursementDate,
|
||||
@@ -199,6 +212,19 @@ public final class LoanTransaction extends AbstractPersistable<Long> {
|
||||
principalPortion, interestPortion, feesPortion, penaltiesPortion, overPaymentPortion, reversed, paymentDetail, externalId,
|
||||
createdDate, appUser);
|
||||
}
|
||||
public static LoanTransaction accrueTransaction(final Loan loan, final Office office, final LocalDate dateOf, final BigDecimal amount,
|
||||
final BigDecimal interestPortion, final BigDecimal feeChargesPortion,
|
||||
final BigDecimal penaltyChargesPortion, final AppUser appUser) {
|
||||
BigDecimal principalPortion = null;
|
||||
BigDecimal overPaymentPortion = null;
|
||||
boolean reversed = false;
|
||||
PaymentDetail paymentDetail = null;
|
||||
String externalId = null;
|
||||
LocalDateTime createdDate = DateUtils.getLocalDateTimeOfTenant();
|
||||
return new LoanTransaction(loan, office, LoanTransactionType.ACCRUAL.getValue(), dateOf.toDate(), amount,
|
||||
principalPortion, interestPortion, feeChargesPortion, penaltyChargesPortion, overPaymentPortion, reversed, paymentDetail, externalId,
|
||||
createdDate, appUser);
|
||||
}
|
||||
|
||||
public static LoanTransaction initiateTransfer(final Office office, final Loan loan, final LocalDate transferDate,
|
||||
final LocalDateTime createdDate, final AppUser appUser) {
|
||||
@@ -461,6 +487,9 @@ public final class LoanTransaction extends AbstractPersistable<Long> {
|
||||
return !isRepayment();
|
||||
}
|
||||
|
||||
public boolean isIncomePosting() {
|
||||
return LoanTransactionType.INCOME_POSTING.equals(getTypeOf()) && isNotReversed();
|
||||
}
|
||||
public boolean isDisbursement() {
|
||||
return LoanTransactionType.DISBURSEMENT.equals(getTypeOf()) && isNotReversed();
|
||||
}
|
||||
|
||||
+8
-1
@@ -51,7 +51,8 @@ public enum LoanTransactionType {
|
||||
REJECT_TRANSFER(15, "loanTransactionType.rejectTransfer"), //
|
||||
REFUND(16, "loanTransactionType.refund"), //
|
||||
CHARGE_PAYMENT(17, "loanTransactionType.chargePayment"), //
|
||||
REFUND_FOR_ACTIVE_LOAN(18, "loanTransactionType.refund");
|
||||
REFUND_FOR_ACTIVE_LOAN(18, "loanTransactionType.refund"), //
|
||||
INCOME_POSTING(19,"loanTransactionType.incomePosting");
|
||||
|
||||
private final Integer value;
|
||||
private final String code;
|
||||
@@ -126,6 +127,9 @@ public enum LoanTransactionType {
|
||||
case 18:
|
||||
loanTransactionType = LoanTransactionType.REFUND_FOR_ACTIVE_LOAN;
|
||||
break;
|
||||
case 19:
|
||||
loanTransactionType = LoanTransactionType.INCOME_POSTING;
|
||||
break;
|
||||
default:
|
||||
loanTransactionType = LoanTransactionType.INVALID;
|
||||
break;
|
||||
@@ -172,4 +176,7 @@ public enum LoanTransactionType {
|
||||
public boolean isRefundForActiveLoan() {
|
||||
return this.value.equals(LoanTransactionType.REFUND_FOR_ACTIVE_LOAN.getValue());
|
||||
}
|
||||
public boolean isIncomePosting() {
|
||||
return this.value.equals(LoanTransactionType.INCOME_POSTING.getValue());
|
||||
}
|
||||
}
|
||||
+54
-22
@@ -69,8 +69,19 @@ public class LoanScheduleParams {
|
||||
// date(after applying compounding frequency)
|
||||
// from when these amounts will effect the outstanding balance for
|
||||
// interest calculation
|
||||
private final TreeMap<LocalDate, Money> compoundingMap;
|
||||
private final Map<LocalDate, TreeMap<LocalDate, Money>> compoundingDateVariations = new HashMap<>();
|
||||
private final Map<LocalDate, Money> compoundingMap;
|
||||
private final Map<LocalDate, Map<LocalDate, Money>> compoundingDateVariations = new HashMap<>();
|
||||
private Money unCompoundedAmount;
|
||||
private Money compoundedInLastInstallment;
|
||||
|
||||
|
||||
public Money getCompoundedInLastInstallment() {
|
||||
return this.compoundedInLastInstallment;
|
||||
}
|
||||
|
||||
public void setCompoundedInLastInstallment(Money compoundedInLastInstallment) {
|
||||
this.compoundedInLastInstallment = compoundedInLastInstallment;
|
||||
}
|
||||
|
||||
// disbursement map for tranche details(will added to outstanding
|
||||
// balance as per the start date)
|
||||
@@ -94,7 +105,7 @@ public class LoanScheduleParams {
|
||||
final LocalDate actualRepaymentDate, final Money totalCumulativePrincipal, final Money totalCumulativeInterest,
|
||||
final Money totalFeeChargesCharged, final Money totalPenaltyChargesCharged, final Money totalRepaymentExpected,
|
||||
Money totalOutstandingInterestPaymentDueToGrace, final Money reducePrincipal, final Map<LocalDate, Money> principalPortionMap,
|
||||
final Map<LocalDate, Money> latePaymentMap, final TreeMap<LocalDate, Money> compoundingMap,
|
||||
final Map<LocalDate, Money> latePaymentMap, final Map<LocalDate, Money> compoundingMap, final Money unCompoundedAmount,
|
||||
final Map<LocalDate, Money> disburseDetailMap, Money principalToBeScheduled, final Money outstandingBalance,
|
||||
final Money outstandingBalanceAsPerRest, final List<LoanRepaymentScheduleInstallment> installments,
|
||||
final Collection<RecalculationDetail> recalculationDetails,
|
||||
@@ -115,6 +126,7 @@ public class LoanScheduleParams {
|
||||
this.principalPortionMap = principalPortionMap;
|
||||
this.latePaymentMap = latePaymentMap;
|
||||
this.compoundingMap = compoundingMap;
|
||||
this.unCompoundedAmount = unCompoundedAmount;
|
||||
this.disburseDetailMap = disburseDetailMap;
|
||||
this.principalToBeScheduled = principalToBeScheduled;
|
||||
this.outstandingBalance = outstandingBalance;
|
||||
@@ -126,6 +138,9 @@ public class LoanScheduleParams {
|
||||
this.partialUpdate = partialUpdate;
|
||||
this.currency = currency;
|
||||
this.applyInterestRecalculation = applyInterestRecalculation;
|
||||
if (this.currency != null) {
|
||||
this.compoundedInLastInstallment = Money.zero(this.currency);
|
||||
}
|
||||
}
|
||||
|
||||
public static LoanScheduleParams createLoanScheduleParamsForPartialUpdate(final int periodNumber, final int instalmentNumber,
|
||||
@@ -133,8 +148,8 @@ public class LoanScheduleParams {
|
||||
final Money totalCumulativeInterest, final Money totalFeeChargesCharged, final Money totalPenaltyChargesCharged,
|
||||
final Money totalRepaymentExpected, Money totalOutstandingInterestPaymentDueToGrace, final Money reducePrincipal,
|
||||
final Map<LocalDate, Money> principalPortionMap, final Map<LocalDate, Money> latePaymentMap,
|
||||
final TreeMap<LocalDate, Money> compoundingMap, final Map<LocalDate, Money> disburseDetailMap, Money principalToBeScheduled,
|
||||
final Money outstandingBalance, final Money outstandingBalanceAsPerRest,
|
||||
final Map<LocalDate, Money> compoundingMap, Money unCompoundedAmount, final Map<LocalDate, Money> disburseDetailMap,
|
||||
final Money principalToBeScheduled, final Money outstandingBalance, final Money outstandingBalanceAsPerRest,
|
||||
final List<LoanRepaymentScheduleInstallment> installments, final Collection<RecalculationDetail> recalculationDetails,
|
||||
final LoanRepaymentScheduleTransactionProcessor loanRepaymentScheduleTransactionProcessor, final LocalDate scheduleTillDate,
|
||||
final MonetaryCurrency currency, final boolean applyInterestRecalculation) {
|
||||
@@ -142,9 +157,9 @@ public class LoanScheduleParams {
|
||||
return new LoanScheduleParams(periodNumber, instalmentNumber, loanTermInDays, periodStartDate, actualRepaymentDate,
|
||||
totalCumulativePrincipal, totalCumulativeInterest, totalFeeChargesCharged, totalPenaltyChargesCharged,
|
||||
totalRepaymentExpected, totalOutstandingInterestPaymentDueToGrace, reducePrincipal, principalPortionMap, latePaymentMap,
|
||||
compoundingMap, disburseDetailMap, principalToBeScheduled, outstandingBalance, outstandingBalanceAsPerRest, installments,
|
||||
recalculationDetails, loanRepaymentScheduleTransactionProcessor, scheduleTillDate, partialUpdate, currency,
|
||||
applyInterestRecalculation);
|
||||
compoundingMap, unCompoundedAmount, disburseDetailMap, principalToBeScheduled, outstandingBalance,
|
||||
outstandingBalanceAsPerRest, installments, recalculationDetails, loanRepaymentScheduleTransactionProcessor,
|
||||
scheduleTillDate, partialUpdate, currency, applyInterestRecalculation);
|
||||
}
|
||||
|
||||
public static LoanScheduleParams createLoanScheduleParamsForCompleteUpdate(final Collection<RecalculationDetail> recalculationDetails,
|
||||
@@ -162,7 +177,7 @@ public class LoanScheduleParams {
|
||||
final Money reducePrincipal = null;
|
||||
final Map<LocalDate, Money> principalPortionMap = null;
|
||||
final Map<LocalDate, Money> latePaymentMap = null;
|
||||
final TreeMap<LocalDate, Money> compoundingMap = null;
|
||||
final Map<LocalDate, Money> compoundingMap = null;
|
||||
final Map<LocalDate, Money> disburseDetailMap = null;
|
||||
final Money principalToBeScheduled = null;
|
||||
final Money outstandingBalance = null;
|
||||
@@ -172,12 +187,13 @@ public class LoanScheduleParams {
|
||||
final int loanTermInDays = 0;
|
||||
final Money totalOutstandingInterestPaymentDueToGrace = null;
|
||||
final MonetaryCurrency currency = null;
|
||||
final Money unCompoundedAmount = null;
|
||||
return new LoanScheduleParams(periodNumber, instalmentNumber, loanTermInDays, periodStartDate, actualRepaymentDate,
|
||||
totalCumulativePrincipal, totalCumulativeInterest, totalFeeChargesCharged, totalPenaltyChargesCharged,
|
||||
totalRepaymentExpected, totalOutstandingInterestPaymentDueToGrace, reducePrincipal, principalPortionMap, latePaymentMap,
|
||||
compoundingMap, disburseDetailMap, principalToBeScheduled, outstandingBalance, outstandingBalanceAsPerRest, installments,
|
||||
recalculationDetails, loanRepaymentScheduleTransactionProcessor, scheduleTillDate, partialUpdate, currency,
|
||||
applyInterestRecalculation);
|
||||
compoundingMap, unCompoundedAmount, disburseDetailMap, principalToBeScheduled, outstandingBalance,
|
||||
outstandingBalanceAsPerRest, installments, recalculationDetails, loanRepaymentScheduleTransactionProcessor,
|
||||
scheduleTillDate, partialUpdate, currency, applyInterestRecalculation);
|
||||
}
|
||||
|
||||
public static LoanScheduleParams createLoanScheduleParams(final MonetaryCurrency currency, final Money chargesDueAtTimeOfDisbursement,
|
||||
@@ -195,7 +211,7 @@ public class LoanScheduleParams {
|
||||
final Money reducePrincipal = Money.zero(currency);
|
||||
final Map<LocalDate, Money> principalPortionMap = new HashMap<>();
|
||||
final Map<LocalDate, Money> latePaymentMap = new HashMap<>();
|
||||
final TreeMap<LocalDate, Money> compoundingMap = new TreeMap<>();
|
||||
final Map<LocalDate, Money> compoundingMap = new TreeMap<>();
|
||||
final Map<LocalDate, Money> disburseDetailMap = new TreeMap<>();
|
||||
final Money outstandingBalance = principalToBeScheduled;
|
||||
final Money outstandingBalanceAsPerRest = principalToBeScheduled;
|
||||
@@ -205,12 +221,13 @@ public class LoanScheduleParams {
|
||||
final LoanRepaymentScheduleTransactionProcessor loanRepaymentScheduleTransactionProcessor = null;
|
||||
final LocalDate scheduleTillDate = null;
|
||||
final boolean applyInterestRecalculation = false;
|
||||
final Money unCompoundedAmount = Money.zero(currency);
|
||||
return new LoanScheduleParams(periodNumber, instalmentNumber, loanTermInDays, periodStartDate, actualRepaymentDate,
|
||||
totalCumulativePrincipal, totalCumulativeInterest, totalFeeChargesCharged, totalPenaltyChargesCharged,
|
||||
totalRepaymentExpected, totalOutstandingInterestPaymentDueToGrace, reducePrincipal, principalPortionMap, latePaymentMap,
|
||||
compoundingMap, disburseDetailMap, principalToBeScheduled, outstandingBalance, outstandingBalanceAsPerRest, installments,
|
||||
recalculationDetails, loanRepaymentScheduleTransactionProcessor, scheduleTillDate, partialUpdate, currency,
|
||||
applyInterestRecalculation);
|
||||
compoundingMap, unCompoundedAmount, disburseDetailMap, principalToBeScheduled, outstandingBalance,
|
||||
outstandingBalanceAsPerRest, installments, recalculationDetails, loanRepaymentScheduleTransactionProcessor,
|
||||
scheduleTillDate, partialUpdate, currency, applyInterestRecalculation);
|
||||
}
|
||||
|
||||
public static LoanScheduleParams createLoanScheduleParams(final MonetaryCurrency currency, final Money chargesDueAtTimeOfDisbursement,
|
||||
@@ -228,7 +245,7 @@ public class LoanScheduleParams {
|
||||
final Money reducePrincipal = Money.zero(currency);
|
||||
final Map<LocalDate, Money> principalPortionMap = new HashMap<>();
|
||||
final Map<LocalDate, Money> latePaymentMap = new HashMap<>();
|
||||
final TreeMap<LocalDate, Money> compoundingMap = new TreeMap<>();
|
||||
final Map<LocalDate, Money> compoundingMap = new TreeMap<>();
|
||||
final Map<LocalDate, Money> disburseDetailMap = new TreeMap<>();
|
||||
final Money outstandingBalance = principalToBeScheduled;
|
||||
final Money outstandingBalanceAsPerRest = principalToBeScheduled;
|
||||
@@ -238,12 +255,13 @@ public class LoanScheduleParams {
|
||||
final LoanRepaymentScheduleTransactionProcessor loanRepaymentScheduleTransactionProcessor = loanScheduleParams.loanRepaymentScheduleTransactionProcessor;
|
||||
final LocalDate scheduleTillDate = loanScheduleParams.scheduleTillDate;
|
||||
final boolean applyInterestRecalculation = loanScheduleParams.applyInterestRecalculation;
|
||||
final Money unCompoundedAmount = Money.zero(currency);
|
||||
return new LoanScheduleParams(periodNumber, instalmentNumber, loanTermInDays, periodStartDate, actualRepaymentDate,
|
||||
totalCumulativePrincipal, totalCumulativeInterest, totalFeeChargesCharged, totalPenaltyChargesCharged,
|
||||
totalRepaymentExpected, totalOutstandingInterestPaymentDueToGrace, reducePrincipal, principalPortionMap, latePaymentMap,
|
||||
compoundingMap, disburseDetailMap, principalToBeScheduled, outstandingBalance, outstandingBalanceAsPerRest, installments,
|
||||
recalculationDetails, loanRepaymentScheduleTransactionProcessor, scheduleTillDate, partialUpdate, currency,
|
||||
applyInterestRecalculation);
|
||||
compoundingMap, unCompoundedAmount, disburseDetailMap, principalToBeScheduled, outstandingBalance,
|
||||
outstandingBalanceAsPerRest, installments, recalculationDetails, loanRepaymentScheduleTransactionProcessor,
|
||||
scheduleTillDate, partialUpdate, currency, applyInterestRecalculation);
|
||||
}
|
||||
|
||||
public int getPeriodNumber() {
|
||||
@@ -310,7 +328,7 @@ public class LoanScheduleParams {
|
||||
return this.latePaymentMap;
|
||||
}
|
||||
|
||||
public TreeMap<LocalDate, Money> getCompoundingMap() {
|
||||
public Map<LocalDate, Money> getCompoundingMap() {
|
||||
return this.compoundingMap;
|
||||
}
|
||||
|
||||
@@ -434,7 +452,7 @@ public class LoanScheduleParams {
|
||||
this.totalOutstandingInterestPaymentDueToGrace = totalOutstandingInterestPaymentDueToGrace;
|
||||
}
|
||||
|
||||
public Map<LocalDate, TreeMap<LocalDate, Money>> getCompoundingDateVariations() {
|
||||
public Map<LocalDate, Map<LocalDate, Money>> getCompoundingDateVariations() {
|
||||
return this.compoundingDateVariations;
|
||||
}
|
||||
|
||||
@@ -446,4 +464,18 @@ public class LoanScheduleParams {
|
||||
return this.applyInterestRecalculation;
|
||||
}
|
||||
|
||||
public Money getUnCompoundedAmount() {
|
||||
return this.unCompoundedAmount;
|
||||
}
|
||||
public void addUnCompoundedAmount(Money unCompoundedAmount) {
|
||||
this.unCompoundedAmount = this.unCompoundedAmount.plus(unCompoundedAmount);
|
||||
}
|
||||
|
||||
public void minusUnCompoundedAmount(Money unCompoundedAmount) {
|
||||
this.unCompoundedAmount = this.unCompoundedAmount.minus(unCompoundedAmount);
|
||||
}
|
||||
|
||||
public void setUnCompoundedAmount(Money unCompoundedAmount) {
|
||||
this.unCompoundedAmount = unCompoundedAmount;
|
||||
}
|
||||
}
|
||||
|
||||
+326
-178
@@ -45,6 +45,7 @@ import org.apache.fineract.portfolio.loanaccount.data.HolidayDetailDTO;
|
||||
import org.apache.fineract.portfolio.loanaccount.data.LoanTermVariationsData;
|
||||
import org.apache.fineract.portfolio.loanaccount.domain.Loan;
|
||||
import org.apache.fineract.portfolio.loanaccount.domain.LoanCharge;
|
||||
import org.apache.fineract.portfolio.loanaccount.domain.LoanInterestRecalcualtionAdditionalDetails;
|
||||
import org.apache.fineract.portfolio.loanaccount.domain.LoanRepaymentScheduleInstallment;
|
||||
import org.apache.fineract.portfolio.loanaccount.domain.LoanSummary;
|
||||
import org.apache.fineract.portfolio.loanaccount.domain.LoanTransaction;
|
||||
@@ -124,7 +125,8 @@ public abstract class AbstractLoanScheduleGenerator implements LoanScheduleGener
|
||||
LocalDate firstRepaymentdate = this.scheduledDateGenerator.generateNextRepaymentDate(
|
||||
loanApplicationTerms.getExpectedDisbursementDate(), loanApplicationTerms, isFirstRepayment, holidayDetailDTO);
|
||||
final LocalDate idealDisbursementDate = this.scheduledDateGenerator.idealDisbursementDateBasedOnFirstRepaymentDate(
|
||||
loanApplicationTerms.getLoanTermPeriodFrequencyType(), loanApplicationTerms.getRepaymentEvery(), firstRepaymentdate);
|
||||
loanApplicationTerms.getLoanTermPeriodFrequencyType(), loanApplicationTerms.getRepaymentEvery(), firstRepaymentdate,
|
||||
loanApplicationTerms.getLoanCalendar(), loanApplicationTerms.getHolidayDetailDTO(), loanApplicationTerms);
|
||||
|
||||
if (!scheduleParams.isPartialUpdate()) {
|
||||
// Set Fixed Principal Amount
|
||||
@@ -203,13 +205,6 @@ public abstract class AbstractLoanScheduleGenerator implements LoanScheduleGener
|
||||
if (scheduleParams.getPeriodStartDate().isAfter(scheduledDueDate)) { throw new ScheduleDateException(
|
||||
"Due date can't be before period start date", scheduledDueDate); }
|
||||
|
||||
if (!scheduleParams.getLatePaymentMap().isEmpty()) {
|
||||
populateCompoundingDatesInPeriod(scheduleParams.getPeriodStartDate(), scheduledDueDate, currentDate, loanApplicationTerms,
|
||||
holidayDetailDTO, scheduleParams.getCompoundingMap(), loanCharges, currency);
|
||||
scheduleParams.getCompoundingDateVariations().put(scheduleParams.getPeriodStartDate(),
|
||||
new TreeMap<>(scheduleParams.getCompoundingMap()));
|
||||
}
|
||||
|
||||
if (extendTermForDailyRepayments) {
|
||||
scheduleParams.setActualRepaymentDate(scheduledDueDate);
|
||||
}
|
||||
@@ -220,6 +215,10 @@ public abstract class AbstractLoanScheduleGenerator implements LoanScheduleGener
|
||||
scheduledDueDate = scheduleParams.getScheduleTillDate();
|
||||
isNextRepaymentAvailable = false;
|
||||
}
|
||||
if (loanApplicationTerms.isInterestRecalculationEnabled()) {
|
||||
populateCompoundingDatesInPeriod(scheduleParams.getPeriodStartDate(), scheduledDueDate, loanApplicationTerms,
|
||||
holidayDetailDTO, scheduleParams, loanCharges, currency);
|
||||
}
|
||||
|
||||
// populates the collection with transactions till the due date of
|
||||
// the period for interest recalculation enabled loans
|
||||
@@ -316,6 +315,7 @@ public abstract class AbstractLoanScheduleGenerator implements LoanScheduleGener
|
||||
currentPeriodParams.getFeeChargesForInstallment(), currentPeriodParams.getPenaltyChargesForInstallment(),
|
||||
totalInstallmentDue, false);
|
||||
|
||||
addLoanRepaymentScheduleInstallment(scheduleParams.getInstallments(), installment);
|
||||
// apply loan transactions on installments to identify early/late
|
||||
// payments for interest recalculation
|
||||
installment = handleRecalculationForTransactions(mc, loanApplicationTerms, holidayDetailDTO, currency, scheduleParams,
|
||||
@@ -327,7 +327,7 @@ public abstract class AbstractLoanScheduleGenerator implements LoanScheduleGener
|
||||
// Updates principal paid map with efective date for reducing
|
||||
// the amount from outstanding balance(interest calculation)
|
||||
updateAmountsWithEffectiveDate(loanApplicationTerms, holidayDetailDTO, scheduleParams, scheduledDueDate, currentPeriodParams,
|
||||
installment);
|
||||
installment, lastRestDate);
|
||||
|
||||
// handle cumulative fields
|
||||
|
||||
@@ -337,7 +337,6 @@ public abstract class AbstractLoanScheduleGenerator implements LoanScheduleGener
|
||||
scheduleParams.setPeriodStartDate(scheduledDueDate);
|
||||
scheduleParams.incrementInstalmentNumber();
|
||||
scheduleParams.incrementPeriodNumber();
|
||||
scheduleParams.getCompoundingDateVariations().clear();
|
||||
if (termVariationParams.isRecalculateAmounts()) {
|
||||
loanApplicationTerms.setCurrentPeriodFixedEmiAmount(null);
|
||||
loanApplicationTerms.setCurrentPeriodFixedPrincipalAmount(null);
|
||||
@@ -377,6 +376,7 @@ public abstract class AbstractLoanScheduleGenerator implements LoanScheduleGener
|
||||
final BigDecimal totalPrincipalPaid = BigDecimal.ZERO;
|
||||
final BigDecimal totalOutstanding = BigDecimal.ZERO;
|
||||
|
||||
updateCompoundingDetails(periods, scheduleParams, loanApplicationTerms);
|
||||
return LoanScheduleModel.from(periods, applicationCurrency, scheduleParams.getLoanTermInDays(),
|
||||
scheduleParams.getPrincipalToBeScheduled(), scheduleParams.getTotalCumulativePrincipal().getAmount(), totalPrincipalPaid,
|
||||
scheduleParams.getTotalCumulativeInterest().getAmount(), scheduleParams.getTotalFeeChargesCharged().getAmount(),
|
||||
@@ -384,6 +384,30 @@ public abstract class AbstractLoanScheduleGenerator implements LoanScheduleGener
|
||||
totalOutstanding);
|
||||
}
|
||||
|
||||
private void updateCompoundingDetails(final Collection<LoanScheduleModelPeriod> periods, final LoanScheduleParams params,
|
||||
final LoanApplicationTerms loanApplicationTerms) {
|
||||
final Map<LocalDate, Map<LocalDate, Money>> compoundingDetails = params.getCompoundingDateVariations();
|
||||
if (compoundingDetails.isEmpty()) { return; }
|
||||
for (LoanScheduleModelPeriod loanScheduleModelPeriod : periods) {
|
||||
if (loanScheduleModelPeriod.isRepaymentPeriod() && loanScheduleModelPeriod.getLoanCompoundingDetails().isEmpty()) {
|
||||
Map<LocalDate, Money> periodCompoundingDetails = compoundingDetails.get(loanScheduleModelPeriod.periodFromDate());
|
||||
if (periodCompoundingDetails != null) {
|
||||
for (Map.Entry<LocalDate, Money> entry : periodCompoundingDetails.entrySet()) {
|
||||
if (entry.getValue().isGreaterThanZero() && !entry.getKey().isAfter(loanScheduleModelPeriod.periodDueDate())) {
|
||||
LocalDate effectiveDate = entry.getKey();
|
||||
if (loanApplicationTerms.allowCompoundingOnEod()) {
|
||||
effectiveDate = effectiveDate.minusDays(1);
|
||||
}
|
||||
LoanInterestRecalcualtionAdditionalDetails additionalDetails = new LoanInterestRecalcualtionAdditionalDetails(
|
||||
effectiveDate, entry.getValue().getAmount());
|
||||
loanScheduleModelPeriod.getLoanCompoundingDetails().add(additionalDetails);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private void applyChargesForCurrentPeriod(final Set<LoanCharge> loanCharges, final MonetaryCurrency currency,
|
||||
LoanScheduleParams scheduleParams, LocalDate scheduledDueDate, ScheduleCurrentPeriodParams currentPeriodParams) {
|
||||
PrincipalInterest principalInterest = new PrincipalInterest(currentPeriodParams.getPrincipalForThisPeriod(),
|
||||
@@ -422,13 +446,14 @@ public abstract class AbstractLoanScheduleGenerator implements LoanScheduleGener
|
||||
|
||||
private void updateAmountsWithEffectiveDate(final LoanApplicationTerms loanApplicationTerms, final HolidayDetailDTO holidayDetailDTO,
|
||||
LoanScheduleParams scheduleParams, LocalDate scheduledDueDate, ScheduleCurrentPeriodParams currentPeriodParams,
|
||||
LoanScheduleModelPeriod installment) {
|
||||
LoanScheduleModelPeriod installment, LocalDate lastRestDate) {
|
||||
LocalDate amountApplicableDate = installment.periodDueDate();
|
||||
if (loanApplicationTerms.isInterestRecalculationEnabled()) {
|
||||
amountApplicableDate = getNextRestScheduleDate(installment.periodDueDate().minusDays(1), loanApplicationTerms, holidayDetailDTO);
|
||||
}
|
||||
updateMapWithAmount(scheduleParams.getPrincipalPortionMap(),
|
||||
currentPeriodParams.getPrincipalForThisPeriod().minus(currentPeriodParams.getReducedBalance()), amountApplicableDate);
|
||||
updateCompoundingMap(loanApplicationTerms, holidayDetailDTO, scheduleParams, lastRestDate, scheduledDueDate);
|
||||
|
||||
// update outstanding balance for interest calculation
|
||||
updateOutstandingBalanceAsPerRest(scheduleParams, scheduledDueDate);
|
||||
@@ -445,7 +470,6 @@ public abstract class AbstractLoanScheduleGenerator implements LoanScheduleGener
|
||||
LoanScheduleModelPeriod modifiedInstallment = installment;
|
||||
if (scheduleParams.applyInterestRecalculation() && loanRepaymentScheduleTransactionProcessor != null) {
|
||||
Money principalProcessed = Money.zero(currency);
|
||||
addLoanRepaymentScheduleInstallment(scheduleParams.getInstallments(), modifiedInstallment);
|
||||
for (RecalculationDetail detail : applicableTransactions) {
|
||||
if (!detail.isProcessed()) {
|
||||
LocalDate transactionDate = detail.getTransactionDate();
|
||||
@@ -489,10 +513,12 @@ public abstract class AbstractLoanScheduleGenerator implements LoanScheduleGener
|
||||
}
|
||||
|
||||
}
|
||||
adjustCompoundedAmountWithPaidDetail(scheduleParams, lastRestDate, currentTransactions, loanApplicationTerms,
|
||||
holidayDetailDTO);
|
||||
}
|
||||
}
|
||||
updateLatePaymentsToMap(loanApplicationTerms, holidayDetailDTO, currency, scheduleParams.getLatePaymentMap(), scheduledDueDate,
|
||||
scheduleParams.getInstallments(), true, lastRestDate, scheduleParams.getCompoundingMap());
|
||||
scheduleParams.getInstallments(), true, lastRestDate);
|
||||
currentPeriodParams.minusPrincipalForThisPeriod(principalProcessed);
|
||||
}
|
||||
return modifiedInstallment;
|
||||
@@ -600,9 +626,6 @@ public abstract class AbstractLoanScheduleGenerator implements LoanScheduleGener
|
||||
scheduleParams.getCompoundingMap().clear();
|
||||
scheduleParams.getCompoundingMap().putAll(
|
||||
scheduleParams.getCompoundingDateVariations().get(periodStartDateApplicableForInterest));
|
||||
} else {
|
||||
scheduleParams.getCompoundingDateVariations().put(periodStartDateApplicableForInterest,
|
||||
new TreeMap<>(scheduleParams.getCompoundingMap()));
|
||||
}
|
||||
}
|
||||
|
||||
@@ -656,10 +679,6 @@ public abstract class AbstractLoanScheduleGenerator implements LoanScheduleGener
|
||||
if (daysInPeriodApplicable > 0) {
|
||||
// 5 determine interest till the transaction
|
||||
// date
|
||||
if (!scheduleParams.getCompoundingDateVariations().containsKey(periodStartDateApplicableForInterest)) {
|
||||
scheduleParams.getCompoundingDateVariations().put(periodStartDateApplicableForInterest,
|
||||
new TreeMap<>(scheduleParams.getCompoundingMap()));
|
||||
}
|
||||
PrincipalInterest principalInterestForThisPeriod = calculatePrincipalInterestComponentsForPeriod(
|
||||
this.paymentPeriodsInOneYearCalculator,
|
||||
currentPeriodParams.getInterestCalculationGraceOnRepaymentPeriodFraction(), scheduleParams
|
||||
@@ -700,6 +719,8 @@ public abstract class AbstractLoanScheduleGenerator implements LoanScheduleGener
|
||||
scheduleParams.getOutstandingBalance(), interestForThisinstallment, feeChargesForInstallment,
|
||||
penaltyChargesForInstallment, totalInstallmentDue, true);
|
||||
periods.add(installment);
|
||||
addLoanRepaymentScheduleInstallment(scheduleParams.getInstallments(), installment);
|
||||
updateCompoundingMap(loanApplicationTerms, holidayDetailDTO, scheduleParams, lastRestDate, scheduledDueDate);
|
||||
|
||||
// update outstanding balance for interest
|
||||
// calculation as per the rest
|
||||
@@ -716,10 +737,12 @@ public abstract class AbstractLoanScheduleGenerator implements LoanScheduleGener
|
||||
periodStartDateApplicableForInterest = scheduleParams.getPeriodStartDate();
|
||||
updateLatePaymentMap = true;
|
||||
scheduleParams.incrementInstalmentNumber();
|
||||
populateCompoundingDatesInPeriod(scheduleParams.getPeriodStartDate(), scheduledDueDate, loanApplicationTerms,
|
||||
holidayDetailDTO, scheduleParams, loanCharges, currency);
|
||||
// creates and insert Loan repayment schedule
|
||||
// for
|
||||
// the period
|
||||
addLoanRepaymentScheduleInstallment(scheduleParams.getInstallments(), installment);
|
||||
|
||||
} else if (installment == null) {
|
||||
installment = ((List<LoanScheduleModelPeriod>) periods).get(periods.size() - 1);
|
||||
}
|
||||
@@ -762,12 +785,10 @@ public abstract class AbstractLoanScheduleGenerator implements LoanScheduleGener
|
||||
// identify late payments and add compounding
|
||||
// details to
|
||||
// map for interest calculation
|
||||
handleLatePayments(loanApplicationTerms, holidayDetailDTO, currency, scheduleParams, lastRestDate,
|
||||
periodStartDateApplicableForInterest, detail);
|
||||
handleLatePayments(loanApplicationTerms, holidayDetailDTO, currency, scheduleParams, lastRestDate, detail);
|
||||
if (updateLatePaymentMap) {
|
||||
updateLatePaymentsToMap(loanApplicationTerms, holidayDetailDTO, currency, scheduleParams.getLatePaymentMap(),
|
||||
scheduledDueDate, scheduleParams.getInstallments(), true, lastRestDate,
|
||||
scheduleParams.getCompoundingMap());
|
||||
scheduledDueDate, scheduleParams.getInstallments(), true, lastRestDate);
|
||||
}
|
||||
} else if (scheduleParams.getLoanRepaymentScheduleTransactionProcessor() != null) {
|
||||
LocalDate applicableDate = getNextRestScheduleDate(transactionDate.minusDays(1), loanApplicationTerms,
|
||||
@@ -776,9 +797,8 @@ public abstract class AbstractLoanScheduleGenerator implements LoanScheduleGener
|
||||
List<LoanTransaction> currentTransactions = createCurrentTransactionList(detail);
|
||||
Money unprocessed = scheduleParams.getLoanRepaymentScheduleTransactionProcessor().handleRepaymentSchedule(
|
||||
currentTransactions, currency, scheduleParams.getInstallments());
|
||||
Money arrears = fetchCompoundedArrears(loanApplicationTerms, currency, detail.getTransaction());
|
||||
Money arrears = fetchArrears(loanApplicationTerms, currency, detail.getTransaction());
|
||||
if (unprocessed.isGreaterThanZero()) {
|
||||
arrears = getTotalAmount(scheduleParams.getLatePaymentMap(), currency);
|
||||
updateMapWithAmount(scheduleParams.getPrincipalPortionMap(), unprocessed, applicableDate);
|
||||
currentPeriodParams.plusEarlyPaidAmount(unprocessed);
|
||||
|
||||
@@ -790,10 +810,6 @@ public abstract class AbstractLoanScheduleGenerator implements LoanScheduleGener
|
||||
.calculateTillRestFrequencyEnabled()) {
|
||||
|
||||
LocalDate calculateTill = transactionDate;
|
||||
if (!scheduleParams.getCompoundingDateVariations().containsKey(periodStartDateApplicableForInterest)) {
|
||||
scheduleParams.getCompoundingDateVariations().put(periodStartDateApplicableForInterest,
|
||||
new TreeMap<>(scheduleParams.getCompoundingMap()));
|
||||
}
|
||||
PrincipalInterest principalInterestForThisPeriod = calculatePrincipalInterestComponentsForPeriod(
|
||||
this.paymentPeriodsInOneYearCalculator,
|
||||
currentPeriodParams.getInterestCalculationGraceOnRepaymentPeriodFraction(), scheduleParams
|
||||
@@ -836,8 +852,7 @@ public abstract class AbstractLoanScheduleGenerator implements LoanScheduleGener
|
||||
|
||||
}
|
||||
if (arrears.isGreaterThanZero() && applicableDate.isBefore(lastRestDate)) {
|
||||
handleLatePayments(loanApplicationTerms, holidayDetailDTO, currency, scheduleParams, lastRestDate,
|
||||
periodStartDateApplicableForInterest, detail);
|
||||
handleLatePayments(loanApplicationTerms, holidayDetailDTO, currency, scheduleParams, lastRestDate, detail);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -862,12 +877,9 @@ public abstract class AbstractLoanScheduleGenerator implements LoanScheduleGener
|
||||
* @param detail
|
||||
*/
|
||||
private void handleLatePayments(final LoanApplicationTerms loanApplicationTerms, final HolidayDetailDTO holidayDetailDTO,
|
||||
final MonetaryCurrency currency, LoanScheduleParams scheduleParams, LocalDate lastRestDate,
|
||||
LocalDate periodStartDateApplicableForInterest, RecalculationDetail detail) {
|
||||
final MonetaryCurrency currency, LoanScheduleParams scheduleParams, LocalDate lastRestDate, RecalculationDetail detail) {
|
||||
updateLatePaidAmountsToPrincipalMap(detail.getTransaction(), loanApplicationTerms, currency, holidayDetailDTO, lastRestDate,
|
||||
scheduleParams);
|
||||
scheduleParams.getCompoundingDateVariations().put(periodStartDateApplicableForInterest,
|
||||
new TreeMap<>(scheduleParams.getCompoundingMap()));
|
||||
}
|
||||
|
||||
private void updateAmountsBasedOnEarlyPayment(final LoanApplicationTerms loanApplicationTerms, final HolidayDetailDTO holidayDetailDTO,
|
||||
@@ -1064,9 +1076,16 @@ public abstract class AbstractLoanScheduleGenerator implements LoanScheduleGener
|
||||
return isAmountChanged;
|
||||
}
|
||||
|
||||
private Money fetchCompoundedArrears(final LoanApplicationTerms loanApplicationTerms, final MonetaryCurrency currency,
|
||||
private Money fetchArrears(final LoanApplicationTerms loanApplicationTerms, final MonetaryCurrency currency,
|
||||
final LoanTransaction transaction) {
|
||||
Money arrears = transaction.getPrincipalPortion(currency);
|
||||
arrears = arrears.plus(fetchCompoundedArrears(loanApplicationTerms, currency, transaction));
|
||||
return arrears;
|
||||
}
|
||||
|
||||
private Money fetchCompoundedArrears(final LoanApplicationTerms loanApplicationTerms, final MonetaryCurrency currency,
|
||||
final LoanTransaction transaction) {
|
||||
Money arrears = Money.zero(currency);
|
||||
if (loanApplicationTerms.getInterestRecalculationCompoundingMethod().isInterestCompoundingEnabled()) {
|
||||
arrears = arrears.plus(transaction.getInterestPortion(currency));
|
||||
}
|
||||
@@ -1096,7 +1115,7 @@ public abstract class AbstractLoanScheduleGenerator implements LoanScheduleGener
|
||||
final Collection<RecalculationDetail> transactions, final Set<LoanCharge> loanCharges, final LoanScheduleParams params) {
|
||||
boolean isFirstRepayment = false;
|
||||
LocalDate startDate = params.getPeriodStartDate();
|
||||
Money outstanding = Money.zero(currency);
|
||||
Money outstanding = params.getOutstandingBalanceAsPerRest();
|
||||
Money totalInterest = Money.zero(currency);
|
||||
Money totalCumulativeInterest = Money.zero(currency);
|
||||
double interestCalculationGraceOnRepaymentPeriodFraction = Double.valueOf(0);
|
||||
@@ -1111,15 +1130,12 @@ public abstract class AbstractLoanScheduleGenerator implements LoanScheduleGener
|
||||
if (params.getActualRepaymentDate().isAfter(currentDate)) {
|
||||
params.setActualRepaymentDate(currentDate);
|
||||
}
|
||||
outstanding = updateOutstandingFromLatePayment(params.getPeriodStartDate(), params.getLatePaymentMap(), outstanding);
|
||||
|
||||
Collection<RecalculationDetail> applicableTransactions = getApplicableTransactionsForPeriod(
|
||||
params.applyInterestRecalculation(), params.getActualRepaymentDate(), transactions);
|
||||
|
||||
if (!params.getLatePaymentMap().isEmpty()) {
|
||||
populateCompoundingDatesInPeriod(params.getPeriodStartDate(), params.getActualRepaymentDate(), currentDate,
|
||||
loanApplicationTerms, holidayDetailDTO, params.getCompoundingMap(), loanCharges, currency);
|
||||
}
|
||||
populateCompoundingDatesInPeriod(params.getPeriodStartDate(), params.getActualRepaymentDate(), loanApplicationTerms,
|
||||
holidayDetailDTO, params, loanCharges, currency);
|
||||
|
||||
for (RecalculationDetail detail : applicableTransactions) {
|
||||
if (detail.isProcessed()) {
|
||||
@@ -1146,22 +1162,30 @@ public abstract class AbstractLoanScheduleGenerator implements LoanScheduleGener
|
||||
totalCumulativeInterest = totalCumulativeInterest.plus(totalInterest);
|
||||
totalInterest = totalInterest.zero();
|
||||
addLoanRepaymentScheduleInstallment(params.getInstallments(), installment);
|
||||
updateCompoundingMap(loanApplicationTerms, holidayDetailDTO, params, lastRestDate, transactionDate);
|
||||
populateCompoundingDatesInPeriod(installment.periodDueDate(), params.getActualRepaymentDate(), loanApplicationTerms,
|
||||
holidayDetailDTO, params, loanCharges, currency);
|
||||
params.setCompoundedInLastInstallment(params.getUnCompoundedAmount());
|
||||
params.setPeriodStartDate(transactionDate);
|
||||
startDate = transactionDate;
|
||||
}
|
||||
loanRepaymentScheduleTransactionProcessor.handleRepaymentSchedule(currentTransactions, currency, params.getInstallments());
|
||||
updateLatePaidAmountsToPrincipalMap(detail.getTransaction(), loanApplicationTerms, currency, holidayDetailDTO,
|
||||
lastRestDate, params);
|
||||
updateLatePaymentsToMap(loanApplicationTerms, holidayDetailDTO, currency, params.getLatePaymentMap(), currentDate,
|
||||
params.getInstallments(), false, lastRestDate, params.getCompoundingMap());
|
||||
outstanding = outstanding.zero();
|
||||
outstanding = updateOutstandingFromLatePayment(params.getPeriodStartDate(), params.getLatePaymentMap(), outstanding);
|
||||
outstanding = updateBalanceForInterestCalculation(params.getPrincipalPortionMap(), params.getPeriodStartDate(),
|
||||
outstanding, false);
|
||||
if (params.getLatePaymentMap().isEmpty() && !outstanding.isGreaterThanZero()) {
|
||||
params.getInstallments(), false, lastRestDate);
|
||||
if (params.getLatePaymentMap().isEmpty() && isCompleted(params.getInstallments())) {
|
||||
outstanding = outstanding.zero();
|
||||
} else {
|
||||
outstanding = updateBalanceForInterestCalculation(params.getPrincipalPortionMap(), params.getPeriodStartDate(),
|
||||
outstanding, false);
|
||||
}
|
||||
if (params.getLatePaymentMap().isEmpty() && outstanding.isZero()) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (outstanding.isGreaterThanZero()) {
|
||||
if (!outstanding.isZero()) {
|
||||
PrincipalInterest principalInterestForThisPeriod = calculatePrincipalInterestComponentsForPeriod(
|
||||
this.paymentPeriodsInOneYearCalculator, interestCalculationGraceOnRepaymentPeriodFraction, totalInterest.zero(),
|
||||
totalInterest.zero(), totalInterest.zero(), totalInterest.zero(), outstanding, loanApplicationTerms,
|
||||
@@ -1169,15 +1193,31 @@ public abstract class AbstractLoanScheduleGenerator implements LoanScheduleGener
|
||||
params.getActualRepaymentDate(), applicableVariations);
|
||||
Money interest = principalInterestForThisPeriod.interest();
|
||||
totalInterest = totalInterest.plus(interest);
|
||||
if (loanApplicationTerms.getInterestRecalculationCompoundingMethod().isInterestCompoundingEnabled()) {
|
||||
LocalDate compoundingEffectiveDate = getNextCompoundScheduleDate(params.getActualRepaymentDate().minusDays(1),
|
||||
loanApplicationTerms, holidayDetailDTO);
|
||||
params.getLatePaymentMap().put(compoundingEffectiveDate, interest);
|
||||
|
||||
Money uncompounded = params.getUnCompoundedAmount();
|
||||
Money compounded = uncompounded.zero();
|
||||
for (Map.Entry<LocalDate, Money> mapEntry : params.getCompoundingMap().entrySet()) {
|
||||
if (mapEntry.getKey().isAfter(params.getPeriodStartDate())) {
|
||||
compounded = compounded.plus(mapEntry.getValue());
|
||||
}
|
||||
}
|
||||
Money compoundedForThisPeriod = compounded.minus(uncompounded);
|
||||
Money uncompoundedForThisPeriod = interest.minus(compoundedForThisPeriod);
|
||||
params.setUnCompoundedAmount(uncompoundedForThisPeriod);
|
||||
LocalDate compoundingDate = params.getPeriodStartDate();
|
||||
if (loanApplicationTerms.allowCompoundingOnEod()) {
|
||||
compoundingDate = compoundingDate.minusDays(1);
|
||||
}
|
||||
compoundingDate = getNextCompoundScheduleDate(compoundingDate, loanApplicationTerms, holidayDetailDTO);
|
||||
if(compoundingDate.isEqual(params.getActualRepaymentDate())){
|
||||
params.getCompoundingMap().put(compoundingDate, uncompoundedForThisPeriod);
|
||||
params.setUnCompoundedAmount(uncompoundedForThisPeriod.zero());
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
params.setPeriodStartDate(params.getActualRepaymentDate());
|
||||
} while (params.getActualRepaymentDate().isBefore(currentDate) && outstanding.isGreaterThanZero());
|
||||
} while (params.getActualRepaymentDate().isBefore(currentDate) && !outstanding.isZero());
|
||||
|
||||
if (totalInterest.isGreaterThanZero()) {
|
||||
LoanScheduleModelRepaymentPeriod installment = LoanScheduleModelRepaymentPeriod.repayment(params.getInstalmentNumber(),
|
||||
@@ -1185,11 +1225,23 @@ public abstract class AbstractLoanScheduleGenerator implements LoanScheduleGener
|
||||
totalInterest.zero(), totalInterest.zero(), totalInterest, true);
|
||||
params.incrementInstalmentNumber();
|
||||
periods.add(installment);
|
||||
params.getCompoundingDateVariations().put(startDate, new TreeMap<>(params.getCompoundingMap()));
|
||||
totalCumulativeInterest = totalCumulativeInterest.plus(totalInterest);
|
||||
}
|
||||
return totalCumulativeInterest;
|
||||
}
|
||||
|
||||
private boolean isCompleted(List<LoanRepaymentScheduleInstallment> installments) {
|
||||
boolean isCompleted = true;
|
||||
for (LoanRepaymentScheduleInstallment installment : installments) {
|
||||
if (installment.isNotFullyPaidOff()) {
|
||||
isCompleted = false;
|
||||
break;
|
||||
}
|
||||
}
|
||||
return isCompleted;
|
||||
}
|
||||
|
||||
private Collection<RecalculationDetail> getApplicableTransactionsForPeriod(final boolean applyInterestRecalculation,
|
||||
LocalDate repaymentDate, final Collection<RecalculationDetail> transactions) {
|
||||
Collection<RecalculationDetail> applicableTransactions = new ArrayList<>();
|
||||
@@ -1221,21 +1273,7 @@ public abstract class AbstractLoanScheduleGenerator implements LoanScheduleGener
|
||||
currentTransactions.add(detail.getTransaction());
|
||||
detail.setProcessed(true);
|
||||
return currentTransactions;
|
||||
}
|
||||
|
||||
private Money updateOutstandingFromLatePayment(LocalDate periodStartDate, Map<LocalDate, Money> latePaymentMap, Money outstanding) {
|
||||
Map<LocalDate, Money> retainEntries = new HashMap<>();
|
||||
for (Map.Entry<LocalDate, Money> mapEntry : latePaymentMap.entrySet()) {
|
||||
if (!mapEntry.getKey().isAfter(periodStartDate)) {
|
||||
outstanding = outstanding.plus(mapEntry.getValue());
|
||||
} else {
|
||||
retainEntries.put(mapEntry.getKey(), mapEntry.getValue());
|
||||
}
|
||||
}
|
||||
latePaymentMap.clear();
|
||||
latePaymentMap.putAll(retainEntries);
|
||||
retainEntries.clear();
|
||||
return outstanding;
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -1315,22 +1353,13 @@ public abstract class AbstractLoanScheduleGenerator implements LoanScheduleGener
|
||||
holidayDetailDTO);
|
||||
|
||||
Money principalPortion = loanTransaction.getPrincipalPortion(currency);
|
||||
Money compoundedLatePayments = Money.zero(currency);
|
||||
if (applicationTerms.getInterestRecalculationCompoundingMethod().isInterestCompoundingEnabled()) {
|
||||
compoundedLatePayments = compoundedLatePayments.plus(loanTransaction.getInterestPortion(currency));
|
||||
}
|
||||
if (applicationTerms.getInterestRecalculationCompoundingMethod().isFeeCompoundingEnabled()) {
|
||||
compoundedLatePayments = compoundedLatePayments.plus(loanTransaction.getFeeChargesPortion(currency)).plus(
|
||||
loanTransaction.getPenaltyChargesPortion(currency));
|
||||
}
|
||||
|
||||
updateCompoundingAmount(params.getPrincipalPortionMap(), params.getLatePaymentMap(), currency, lastRestDate, principalPortion,
|
||||
applicableDate);
|
||||
updateCompoundingAmount(params.getPrincipalPortionMap(), params.getCompoundingMap(), currency, lastRestDate,
|
||||
compoundedLatePayments, applicableDate);
|
||||
updateLatePaymentCompoundingAmount(params.getPrincipalPortionMap(), params.getLatePaymentMap(), currency, lastRestDate,
|
||||
principalPortion, applicableDate);
|
||||
adjustCompoundedAmountWithPaidDetail(params, lastRestDate, applicableDate, loanTransaction, applicationTerms);
|
||||
}
|
||||
|
||||
private void updateCompoundingAmount(final Map<LocalDate, Money> principalVariationMap,
|
||||
private void updateLatePaymentCompoundingAmount(final Map<LocalDate, Money> principalVariationMap,
|
||||
final Map<LocalDate, Money> latePaymentCompoundingMap, final MonetaryCurrency currency, final LocalDate lastRestDate,
|
||||
Money compoundedPortion, final LocalDate applicableDate) {
|
||||
Money appliedOnPrincipalVariationMap = Money.zero(currency);
|
||||
@@ -1368,17 +1397,11 @@ public abstract class AbstractLoanScheduleGenerator implements LoanScheduleGener
|
||||
*/
|
||||
private void updateLatePaymentsToMap(final LoanApplicationTerms loanApplicationTerms, final HolidayDetailDTO holidayDetailDTO,
|
||||
final MonetaryCurrency currency, final Map<LocalDate, Money> latePaymentMap, final LocalDate scheduledDueDate,
|
||||
List<LoanRepaymentScheduleInstallment> installments, boolean applyRestFrequencyForPrincipal, final LocalDate lastRestDate,
|
||||
final TreeMap<LocalDate, Money> compoundingMap) {
|
||||
List<LoanRepaymentScheduleInstallment> installments, boolean applyRestFrequencyForPrincipal, final LocalDate lastRestDate) {
|
||||
latePaymentMap.clear();
|
||||
LocalDate currentDate = DateUtils.getLocalDateOfTenant();
|
||||
|
||||
Money totalCompoundingAmount = Money.zero(currency);
|
||||
Money compoundedMoney = Money.zero(currency);
|
||||
if (!compoundingMap.isEmpty()) {
|
||||
compoundedMoney = compoundingMap.get(lastRestDate);
|
||||
}
|
||||
boolean clearCompoundingMap = true;
|
||||
for (LoanRepaymentScheduleInstallment loanRepaymentScheduleInstallment : installments) {
|
||||
if (loanRepaymentScheduleInstallment.isNotFullyPaidOff()
|
||||
&& !loanRepaymentScheduleInstallment.getDueDate().isAfter(scheduledDueDate)
|
||||
@@ -1395,106 +1418,183 @@ public abstract class AbstractLoanScheduleGenerator implements LoanScheduleGener
|
||||
.plus(loanRepaymentScheduleInstallment.getPrincipalOutstanding(currency));
|
||||
}
|
||||
|
||||
final Money changedCompoundedMoney = updateMapWithCompoundingDetails(loanApplicationTerms, holidayDetailDTO, currency,
|
||||
compoundingMap, loanRepaymentScheduleInstallment, lastRestDate, compoundedMoney, scheduledDueDate);
|
||||
if (compoundedMoney.isZero() || !compoundedMoney.isEqualTo(changedCompoundedMoney)) {
|
||||
compoundedMoney = changedCompoundedMoney;
|
||||
clearCompoundingMap = false;
|
||||
}
|
||||
}
|
||||
}
|
||||
if (totalCompoundingAmount.isGreaterThanZero()) {
|
||||
updateMapWithAmount(latePaymentMap, totalCompoundingAmount.negated(), lastRestDate);
|
||||
}
|
||||
if (clearCompoundingMap) {
|
||||
compoundingMap.clear();
|
||||
}
|
||||
}
|
||||
|
||||
private Money updateMapWithCompoundingDetails(final LoanApplicationTerms loanApplicationTerms, final HolidayDetailDTO holidayDetailDTO,
|
||||
final MonetaryCurrency currency, final TreeMap<LocalDate, Money> compoundingMap,
|
||||
final LoanRepaymentScheduleInstallment loanRepaymentScheduleInstallment, final LocalDate lastRestDate,
|
||||
final Money compoundedMoney, final LocalDate scheduledDueDate) {
|
||||
Money ignoreMoney = compoundedMoney;
|
||||
if (loanApplicationTerms.getInterestRecalculationCompoundingMethod().isCompoundingEnabled()) {
|
||||
LocalDate compoundingEffectiveDate = getNextCompoundScheduleDate(loanRepaymentScheduleInstallment.getDueDate().minusDays(1),
|
||||
loanApplicationTerms, holidayDetailDTO);
|
||||
|
||||
if (compoundingEffectiveDate.isBefore(DateUtils.getLocalDateOfTenant())) {
|
||||
Money amount = Money.zero(currency);
|
||||
switch (loanApplicationTerms.getInterestRecalculationCompoundingMethod()) {
|
||||
case INTEREST:
|
||||
amount = amount.plus(loanRepaymentScheduleInstallment.getInterestOutstanding(currency));
|
||||
break;
|
||||
case FEE:
|
||||
amount = amount.plus(loanRepaymentScheduleInstallment.getFeeChargesOutstanding(currency));
|
||||
amount = amount.plus(loanRepaymentScheduleInstallment.getPenaltyChargesOutstanding(currency));
|
||||
break;
|
||||
case INTEREST_AND_FEE:
|
||||
amount = amount.plus(loanRepaymentScheduleInstallment.getInterestOutstanding(currency));
|
||||
amount = amount.plus(loanRepaymentScheduleInstallment.getFeeChargesOutstanding(currency));
|
||||
amount = amount.plus(loanRepaymentScheduleInstallment.getPenaltyChargesOutstanding(currency));
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
if (compoundingEffectiveDate.isBefore(scheduledDueDate)) {
|
||||
ignoreMoney = ignoreMoney.plus(amount);
|
||||
if (ignoreMoney.isGreaterThanZero()) {
|
||||
updateMapWithAmount(compoundingMap, ignoreMoney, compoundingEffectiveDate);
|
||||
updateMapWithAmount(compoundingMap, ignoreMoney.negated(), lastRestDate);
|
||||
ignoreMoney = ignoreMoney.zero();
|
||||
}
|
||||
private void updateCompoundingMap(final LoanApplicationTerms loanApplicationTerms, final HolidayDetailDTO holidayDetailDTO,
|
||||
final LoanScheduleParams params, final LocalDate lastRestDate, final LocalDate scheduledDueDate) {
|
||||
if (loanApplicationTerms.isInterestRecalculationEnabled()
|
||||
&& loanApplicationTerms.getInterestRecalculationCompoundingMethod().isCompoundingEnabled()) {
|
||||
final MonetaryCurrency currency = params.getCurrency();
|
||||
Money totalCompoundedAmount = Money.zero(currency);
|
||||
boolean lastInstallmentIsPastDate = false;
|
||||
for (LoanRepaymentScheduleInstallment loanRepaymentScheduleInstallment : params.getInstallments()) {
|
||||
if (params.getCompoundingDateVariations().containsKey(loanRepaymentScheduleInstallment.getFromDate())) {
|
||||
lastInstallmentIsPastDate = params.applyInterestRecalculation()
|
||||
&& loanRepaymentScheduleInstallment.getDueDate().isBefore(DateUtils.getLocalDateOfTenant());
|
||||
} else {
|
||||
if (ignoreMoney.isLessThanZero()) {
|
||||
LocalDate firstKey = compoundingMap.firstKey();
|
||||
updateMapWithAmount(compoundingMap, ignoreMoney, firstKey);
|
||||
updateMapWithAmount(compoundingMap, ignoreMoney.negated(), lastRestDate);
|
||||
ignoreMoney = ignoreMoney.zero();
|
||||
final boolean isPastDate = params.applyInterestRecalculation()
|
||||
&& loanRepaymentScheduleInstallment.getDueDate().isBefore(DateUtils.getLocalDateOfTenant());
|
||||
boolean periodHasCompoundingDate = false;
|
||||
Money amountCharged = getIncomeForCompounding(loanApplicationTerms, currency, loanRepaymentScheduleInstallment);
|
||||
final Map<LocalDate, Money> compoundingMap = params.getCompoundingMap();
|
||||
LocalDate effectiveStartDate = loanRepaymentScheduleInstallment.getFromDate();
|
||||
if (loanApplicationTerms.allowCompoundingOnEod()) {
|
||||
effectiveStartDate = loanRepaymentScheduleInstallment.getFromDate().minusDays(1);
|
||||
}
|
||||
updateMapWithAmount(compoundingMap, amount, compoundingEffectiveDate);
|
||||
updateMapWithAmount(compoundingMap, amount.negated(), lastRestDate);
|
||||
LocalDate compoundingEffectiveDate = getNextCompoundScheduleDate(effectiveStartDate, loanApplicationTerms,
|
||||
holidayDetailDTO);
|
||||
final LocalDate restDate = getNextRestScheduleDate(scheduledDueDate.minusDays(1), loanApplicationTerms,
|
||||
holidayDetailDTO);
|
||||
if (!compoundingEffectiveDate.isAfter(loanRepaymentScheduleInstallment.getDueDate())) {
|
||||
totalCompoundedAmount = totalCompoundedAmount.minus(params.getUnCompoundedAmount());
|
||||
periodHasCompoundingDate = true;
|
||||
}
|
||||
while (!compoundingEffectiveDate.isAfter(loanRepaymentScheduleInstallment.getDueDate())) {
|
||||
if (compoundingEffectiveDate.isEqual(loanRepaymentScheduleInstallment.getDueDate())) {
|
||||
Money amountToBeCompounding = amountCharged.minus(totalCompoundedAmount);
|
||||
updateMapWithAmount(compoundingMap, amountToBeCompounding, compoundingEffectiveDate);
|
||||
totalCompoundedAmount = totalCompoundedAmount.plus(amountToBeCompounding);
|
||||
|
||||
} else if (compoundingMap.containsKey(compoundingEffectiveDate)) {
|
||||
Money compounedAmount = compoundingMap.get(compoundingEffectiveDate);
|
||||
totalCompoundedAmount = totalCompoundedAmount.plus(compounedAmount);
|
||||
}
|
||||
|
||||
if (!loanApplicationTerms.allowCompoundingOnEod()) {
|
||||
compoundingEffectiveDate = compoundingEffectiveDate.plusDays(1);
|
||||
}
|
||||
compoundingEffectiveDate = getNextCompoundScheduleDate(compoundingEffectiveDate, loanApplicationTerms,
|
||||
holidayDetailDTO);
|
||||
}
|
||||
if (periodHasCompoundingDate) {
|
||||
if (isPastDate) {
|
||||
updateMapWithAmount(params.getPrincipalPortionMap(),
|
||||
totalCompoundedAmount.plus(params.getUnCompoundedAmount()), lastRestDate);
|
||||
} else {
|
||||
Money amountToBeEffected = amountCharged;
|
||||
if (lastInstallmentIsPastDate) {
|
||||
amountToBeEffected = amountToBeEffected.plus(params.getUnCompoundedAmount());
|
||||
}
|
||||
updateMapWithAmount(params.getPrincipalPortionMap(), amountToBeEffected, restDate);
|
||||
}
|
||||
}
|
||||
if (totalCompoundedAmount.isGreaterThanZero()) {
|
||||
params.getCompoundingDateVariations().put(loanRepaymentScheduleInstallment.getFromDate(),
|
||||
new TreeMap<>(params.getCompoundingMap()));
|
||||
for (Map.Entry<LocalDate, Money> mapEntry : params.getCompoundingMap().entrySet()) {
|
||||
if (!mapEntry.getKey().isAfter(loanRepaymentScheduleInstallment.getDueDate())) {
|
||||
updateMapWithAmount(params.getPrincipalPortionMap(), mapEntry.getValue().negated(), mapEntry.getKey());
|
||||
}else if(params.getUnCompoundedAmount().isEqualTo( mapEntry.getValue())){
|
||||
totalCompoundedAmount = totalCompoundedAmount.plus(params.getUnCompoundedAmount());
|
||||
}
|
||||
}
|
||||
params.minusUnCompoundedAmount(params.getUnCompoundedAmount());
|
||||
params.getCompoundingMap().clear();
|
||||
params.addUnCompoundedAmount(amountCharged.minus(totalCompoundedAmount.minus(params.getCompoundedInLastInstallment())));
|
||||
} else {
|
||||
params.getCompoundingMap().clear();
|
||||
params.getCompoundingDateVariations().put(loanRepaymentScheduleInstallment.getFromDate(),
|
||||
new TreeMap<>(params.getCompoundingMap()));
|
||||
params.addUnCompoundedAmount(amountCharged);
|
||||
}
|
||||
params.setCompoundedInLastInstallment(amountCharged.zero());
|
||||
lastInstallmentIsPastDate = isPastDate;
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
return ignoreMoney;
|
||||
|
||||
}
|
||||
|
||||
private void populateCompoundingDatesInPeriod(final LocalDate startDate, final LocalDate endDate, final LocalDate currentDate,
|
||||
private Money getIncomeForCompounding(final LoanApplicationTerms loanApplicationTerms, final MonetaryCurrency currency,
|
||||
LoanRepaymentScheduleInstallment loanRepaymentScheduleInstallment) {
|
||||
Money interestCharged = Money.zero(currency);
|
||||
Money feeCharged = Money.zero(currency);
|
||||
Money penaltyCharged = Money.zero(currency);
|
||||
Money amountCharged = Money.zero(currency);
|
||||
switch (loanApplicationTerms.getInterestRecalculationCompoundingMethod()) {
|
||||
case INTEREST:
|
||||
interestCharged = interestCharged.plus(loanRepaymentScheduleInstallment.getInterestCharged(currency));
|
||||
break;
|
||||
case FEE:
|
||||
feeCharged = feeCharged.plus(loanRepaymentScheduleInstallment.getFeeChargesCharged(currency));
|
||||
penaltyCharged = penaltyCharged.plus(loanRepaymentScheduleInstallment.getPenaltyChargesCharged(currency));
|
||||
break;
|
||||
case INTEREST_AND_FEE:
|
||||
interestCharged = interestCharged.plus(loanRepaymentScheduleInstallment.getInterestCharged(currency));
|
||||
feeCharged = feeCharged.plus(loanRepaymentScheduleInstallment.getFeeChargesCharged(currency));
|
||||
penaltyCharged = penaltyCharged.plus(loanRepaymentScheduleInstallment.getPenaltyChargesCharged(currency));
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
amountCharged = interestCharged.plus(feeCharged).plus(penaltyCharged);
|
||||
return amountCharged;
|
||||
}
|
||||
|
||||
private void adjustCompoundedAmountWithPaidDetail(final LoanScheduleParams params, final LocalDate lastRestDate,
|
||||
final Collection<LoanTransaction> transactions, final LoanApplicationTerms loanApplicationTerms,
|
||||
HolidayDetailDTO holidayDetailDTO) {
|
||||
for (LoanTransaction loanTransaction : transactions) {
|
||||
final LocalDate amountApplicableDate = getNextRestScheduleDate(loanTransaction.getTransactionDate().minusDays(1),
|
||||
loanApplicationTerms, holidayDetailDTO);
|
||||
adjustCompoundedAmountWithPaidDetail(params, lastRestDate, amountApplicableDate, loanTransaction, loanApplicationTerms);
|
||||
}
|
||||
}
|
||||
|
||||
private void adjustCompoundedAmountWithPaidDetail(final LoanScheduleParams params, final LocalDate lastRestDate,
|
||||
final LocalDate amountApplicableDate, final LoanTransaction transaction, final LoanApplicationTerms loanApplicationTerms) {
|
||||
adjustCompoundedAmountWithPaidDetail(params.getPrincipalPortionMap(), lastRestDate, amountApplicableDate, transaction,
|
||||
loanApplicationTerms, params.getCurrency());
|
||||
}
|
||||
|
||||
private void adjustCompoundedAmountWithPaidDetail(final Map<LocalDate, Money> principalPortionMap, final LocalDate lastRestDate,
|
||||
final LocalDate amountApplicableDate, final LoanTransaction transaction, final LoanApplicationTerms loanApplicationTerms,
|
||||
final MonetaryCurrency currency) {
|
||||
if (!amountApplicableDate.isEqual(lastRestDate)) {
|
||||
Money compoundedIncome = fetchCompoundedArrears(loanApplicationTerms, currency, transaction);
|
||||
updateMapWithAmount(principalPortionMap, compoundedIncome, amountApplicableDate);
|
||||
updateMapWithAmount(principalPortionMap, compoundedIncome.negated(), lastRestDate);
|
||||
}
|
||||
}
|
||||
|
||||
private void populateCompoundingDatesInPeriod(final LocalDate startDate, final LocalDate endDate,
|
||||
final LoanApplicationTerms loanApplicationTerms, final HolidayDetailDTO holidayDetailDTO,
|
||||
final Map<LocalDate, Money> compoundingMap, final Set<LoanCharge> charges, MonetaryCurrency currency) {
|
||||
final LoanScheduleParams scheduleParams, final Set<LoanCharge> charges, MonetaryCurrency currency) {
|
||||
if (loanApplicationTerms.getInterestRecalculationCompoundingMethod().isCompoundingEnabled()) {
|
||||
final Map<LocalDate, Money> compoundingMap = scheduleParams.getCompoundingMap();
|
||||
LocalDate lastCompoundingDate = startDate;
|
||||
LocalDate compoundingDate = startDate;
|
||||
while (compoundingDate.isBefore(endDate) && compoundingDate.isBefore(currentDate)) {
|
||||
boolean addUncompounded = true;
|
||||
while (compoundingDate.isBefore(endDate)) {
|
||||
if (loanApplicationTerms.allowCompoundingOnEod()) {
|
||||
compoundingDate = compoundingDate.minusDays(1);
|
||||
}
|
||||
compoundingDate = getNextCompoundScheduleDate(compoundingDate, loanApplicationTerms, holidayDetailDTO);
|
||||
if (!compoundingDate.isBefore(currentDate)) {
|
||||
break;
|
||||
} else if (compoundingDate.isAfter(endDate)) {
|
||||
updateMapWithAmount(compoundingMap, Money.zero(currency), compoundingDate);
|
||||
} else {
|
||||
|
||||
if (compoundingDate.isBefore(endDate)) {
|
||||
Money feeChargesForInstallment = cumulativeFeeChargesDueWithin(lastCompoundingDate, compoundingDate, charges, currency,
|
||||
null, loanApplicationTerms.getPrincipal(), null, false);
|
||||
Money penaltyChargesForInstallment = cumulativePenaltyChargesDueWithin(lastCompoundingDate, compoundingDate, charges,
|
||||
currency, null, loanApplicationTerms.getPrincipal(), null, false);
|
||||
updateMapWithAmount(compoundingMap, feeChargesForInstallment.plus(penaltyChargesForInstallment), compoundingDate);
|
||||
Money compoundAmount = feeChargesForInstallment.plus(penaltyChargesForInstallment);
|
||||
if (addUncompounded) {
|
||||
compoundAmount = compoundAmount.plus(scheduleParams.getUnCompoundedAmount());
|
||||
addUncompounded = false;
|
||||
}
|
||||
updateMapWithAmount(compoundingMap, compoundAmount, compoundingDate);
|
||||
}
|
||||
|
||||
lastCompoundingDate = compoundingDate;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
protected void clearMapDetails(final LocalDate startDate, final Map<LocalDate, Money> compoundingMap) {
|
||||
Map<LocalDate, Money> temp = new HashMap<>();
|
||||
for (LocalDate date : compoundingMap.keySet()) {
|
||||
if (!date.isBefore(startDate)) {
|
||||
temp.put(date, compoundingMap.get(date));
|
||||
}
|
||||
}
|
||||
compoundingMap.clear();
|
||||
compoundingMap.putAll(temp);
|
||||
}
|
||||
|
||||
/**
|
||||
* This Method updates principal paid component to map with effective date
|
||||
* as per the REST
|
||||
@@ -1580,16 +1680,7 @@ public abstract class AbstractLoanScheduleGenerator implements LoanScheduleGener
|
||||
principalPaid = map.get(amountApplicableDate).plus(principalPaid);
|
||||
}
|
||||
map.put(amountApplicableDate, principalPaid);
|
||||
}
|
||||
|
||||
private Money getTotalAmount(final Map<LocalDate, Money> map, final MonetaryCurrency currency) {
|
||||
Money total = Money.zero(currency);
|
||||
for (Map.Entry<LocalDate, Money> mapEntry : map.entrySet()) {
|
||||
if (mapEntry.getKey().isBefore(DateUtils.getLocalDateOfTenant())) {
|
||||
total = total.plus(mapEntry.getValue());
|
||||
}
|
||||
}
|
||||
return total;
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -1737,8 +1828,9 @@ public abstract class AbstractLoanScheduleGenerator implements LoanScheduleGener
|
||||
}
|
||||
|
||||
// get the loan application terms from the Loan object
|
||||
final LoanApplicationTerms loanApplicationTerms = loan.getLoanApplicationTerms(applicationCurrency, restCalendarInstance,
|
||||
compoundingCalendarInstance, loanCalendar, floatingRateDTO, isSkipRepaymentonmonthFirst, numberofdays);
|
||||
final LoanApplicationTerms loanApplicationTerms = loan
|
||||
.getLoanApplicationTerms(applicationCurrency, restCalendarInstance, compoundingCalendarInstance, loanCalendar,
|
||||
floatingRateDTO, isSkipRepaymentonmonthFirst, numberofdays, holidayDetailDTO);
|
||||
|
||||
// for applying variations
|
||||
Collection<LoanTermVariationsData> loanTermVariations = loanApplicationTerms.getLoanTermVariations().getInterestRateChanges();
|
||||
@@ -2117,6 +2209,7 @@ public abstract class AbstractLoanScheduleGenerator implements LoanScheduleGener
|
||||
// action will be performed on this value
|
||||
Money reducePrincipal = outstandingBalanceAsPerRest.zero();
|
||||
|
||||
Money uncompoundedAmount = outstandingBalanceAsPerRest.zero();
|
||||
// principal changes will be added along with date(after applying
|
||||
// rest)
|
||||
// from when these amounts will effect the outstanding balance for
|
||||
@@ -2133,6 +2226,7 @@ public abstract class AbstractLoanScheduleGenerator implements LoanScheduleGener
|
||||
// from when these amounts will effect the outstanding balance for
|
||||
// interest calculation
|
||||
final TreeMap<LocalDate, Money> compoundingMap = new TreeMap<>();
|
||||
final Map<LocalDate, Map<LocalDate, Money>> compoundingDateVariations = new HashMap<>();
|
||||
LocalDate currentDate = DateUtils.getLocalDateOfTenant();
|
||||
LocalDate lastRestDate = currentDate;
|
||||
if (loanApplicationTerms.getRestCalendarInstance() != null) {
|
||||
@@ -2179,6 +2273,9 @@ public abstract class AbstractLoanScheduleGenerator implements LoanScheduleGener
|
||||
// process the installment only if recalculate from date is
|
||||
// greater than due date
|
||||
if (installment.getDueDate().isAfter(lastInstallmentDate)) {
|
||||
if (totalCumulativePrincipal.isGreaterThanOrEqualTo(loanApplicationTerms.getTotalDisbursedAmount())) {
|
||||
break;
|
||||
}
|
||||
LocalDate previousRepaymentDate = actualRepaymentDate;
|
||||
actualRepaymentDate = this.scheduledDateGenerator.generateNextRepaymentDate(actualRepaymentDate, loanApplicationTerms,
|
||||
isFirstRepayment, holidayDetailDTO);
|
||||
@@ -2272,6 +2369,9 @@ public abstract class AbstractLoanScheduleGenerator implements LoanScheduleGener
|
||||
// updates map with the installment principal amount excluding
|
||||
// unprocessed amount since this amount is already accounted.
|
||||
updateMapWithAmount(principalPortionMap, installment.getPrincipal(currency).minus(unprocessed), amountApplicableDate);
|
||||
uncompoundedAmount = updateCompoundingDetailsForPartialScheduleGeneration(installment, loanApplicationTerms,
|
||||
principalPortionMap, compoundingDateVariations, uncompoundedAmount, applicableTransactions, lastRestDate,
|
||||
holidayDetailDTO);
|
||||
// update outstanding balance for interest calculation
|
||||
outstandingBalanceAsPerRest = updateBalanceForInterestCalculation(principalPortionMap, installment.getDueDate(),
|
||||
outstandingBalanceAsPerRest, false);
|
||||
@@ -2284,7 +2384,7 @@ public abstract class AbstractLoanScheduleGenerator implements LoanScheduleGener
|
||||
|
||||
// updates the map with over due amounts
|
||||
updateLatePaymentsToMap(loanApplicationTerms, holidayDetailDTO, currency, latePaymentMap, lastInstallmentDate,
|
||||
newRepaymentScheduleInstallments, true, lastRestDate, compoundingMap);
|
||||
newRepaymentScheduleInstallments, true, lastRestDate);
|
||||
|
||||
// for partial schedule generation
|
||||
if (!newRepaymentScheduleInstallments.isEmpty() && totalCumulativeInterest.isGreaterThanZero()) {
|
||||
@@ -2293,10 +2393,11 @@ public abstract class AbstractLoanScheduleGenerator implements LoanScheduleGener
|
||||
loanTermInDays, periodStartDate, actualRepaymentDate, totalCumulativePrincipal, totalCumulativeInterest,
|
||||
totalFeeChargesCharged, totalPenaltyChargesCharged, totalRepaymentExpected,
|
||||
totalOutstandingInterestPaymentDueToGrace, reducePrincipal, principalPortionMap, latePaymentMap, compoundingMap,
|
||||
disburseDetailMap, principalToBeScheduled, outstandingBalance, outstandingBalanceAsPerRest,
|
||||
uncompoundedAmount, disburseDetailMap, principalToBeScheduled, outstandingBalance, outstandingBalanceAsPerRest,
|
||||
newRepaymentScheduleInstallments, recalculationDetails, loanRepaymentScheduleTransactionProcessor,
|
||||
scheduleTillDate, currency, applyInterestRecalculation);
|
||||
retainedInstallments.addAll(newRepaymentScheduleInstallments);
|
||||
loanScheduleParams.getCompoundingDateVariations().putAll(compoundingDateVariations);
|
||||
}
|
||||
|
||||
}
|
||||
@@ -2328,6 +2429,7 @@ public abstract class AbstractLoanScheduleGenerator implements LoanScheduleGener
|
||||
final Map<LocalDate, Money> principalPortionMap, LoanRepaymentScheduleInstallment installment,
|
||||
Collection<RecalculationDetail> applicableTransactions, Money actualPrincipalPortion) {
|
||||
Money unprocessed = Money.zero(currency);
|
||||
Money totalUnprocessed = Money.zero(currency);
|
||||
for (RecalculationDetail detail : applicableTransactions) {
|
||||
if (!detail.isProcessed()) {
|
||||
Money principalProcessed = installment.getPrincipalCompleted(currency);
|
||||
@@ -2357,10 +2459,53 @@ public abstract class AbstractLoanScheduleGenerator implements LoanScheduleGener
|
||||
LocalDate applicableDate = getNextRestScheduleDate(detail.getTransactionDate().minusDays(1), loanApplicationTerms,
|
||||
holidayDetailDTO);
|
||||
updateMapWithAmount(principalPortionMap, unprocessed, applicableDate);
|
||||
totalUnprocessed = totalUnprocessed.plus(unprocessed);
|
||||
|
||||
}
|
||||
}
|
||||
return unprocessed;
|
||||
return totalUnprocessed;
|
||||
}
|
||||
|
||||
private Money updateCompoundingDetailsForPartialScheduleGeneration(final LoanRepaymentScheduleInstallment installment,
|
||||
LoanApplicationTerms loanApplicationTerms, Map<LocalDate, Money> principalMap,
|
||||
final Map<LocalDate, Map<LocalDate, Money>> compoundingDateVariations, final Money uncompoundedAmount,
|
||||
final Collection<RecalculationDetail> applicableTransactions, LocalDate lastRestDate, HolidayDetailDTO holidayDetailDTO) {
|
||||
Money uncompounded = uncompoundedAmount;
|
||||
MonetaryCurrency currency = uncompoundedAmount.getCurrency();
|
||||
for (RecalculationDetail detail : applicableTransactions) {
|
||||
LocalDate applicableDate = getNextRestScheduleDate(detail.getTransactionDate().minusDays(1), loanApplicationTerms,
|
||||
holidayDetailDTO);
|
||||
adjustCompoundedAmountWithPaidDetail(principalMap, lastRestDate, applicableDate, detail.getTransaction(), loanApplicationTerms,
|
||||
currency);
|
||||
}
|
||||
Money amountCharged = getIncomeForCompounding(loanApplicationTerms, currency, installment);
|
||||
final List<LoanInterestRecalcualtionAdditionalDetails> details = installment.getLoanCompoundingDetails();
|
||||
Money totalCompounded = Money.zero(currency);
|
||||
Map<LocalDate, Money> compoundingMap = new TreeMap<>();
|
||||
for (LoanInterestRecalcualtionAdditionalDetails additionalDetails : details) {
|
||||
LocalDate effectiveDate = additionalDetails.getEffectiveDate();
|
||||
if (loanApplicationTerms.allowCompoundingOnEod()) {
|
||||
effectiveDate = effectiveDate.plusDays(1);
|
||||
}
|
||||
compoundingMap.put(effectiveDate, Money.of(currency, additionalDetails.getAmount()));
|
||||
totalCompounded = totalCompounded.plus(additionalDetails.getAmount());
|
||||
updateMapWithAmount(principalMap, Money.of(currency, additionalDetails.getAmount()).negated(), effectiveDate);
|
||||
}
|
||||
compoundingDateVariations.put(installment.getFromDate(), compoundingMap);
|
||||
if (totalCompounded.isGreaterThanZero()) {
|
||||
final boolean isPastDate = installment.getDueDate().isBefore(DateUtils.getLocalDateOfTenant());
|
||||
final LocalDate restDate = getNextRestScheduleDate(installment.getDueDate().minusDays(1), loanApplicationTerms,
|
||||
holidayDetailDTO);
|
||||
if (isPastDate) {
|
||||
updateMapWithAmount(principalMap, totalCompounded, lastRestDate);
|
||||
} else {
|
||||
updateMapWithAmount(principalMap, totalCompounded, restDate);
|
||||
}
|
||||
uncompounded = amountCharged.plus(uncompounded).minus(totalCompounded);
|
||||
} else {
|
||||
uncompounded = uncompounded.plus(amountCharged);
|
||||
}
|
||||
return uncompounded;
|
||||
}
|
||||
|
||||
private void updateAmortization(final MathContext mc, final LoanApplicationTerms loanApplicationTerms, int periodNumber,
|
||||
@@ -2432,7 +2577,7 @@ public abstract class AbstractLoanScheduleGenerator implements LoanScheduleGener
|
||||
scheduledLoanInstallment.periodFromDate(), scheduledLoanInstallment.periodDueDate(),
|
||||
scheduledLoanInstallment.principalDue(), scheduledLoanInstallment.interestDue(),
|
||||
scheduledLoanInstallment.feeChargesDue(), scheduledLoanInstallment.penaltyChargesDue(),
|
||||
scheduledLoanInstallment.isRecalculatedInterestComponent());
|
||||
scheduledLoanInstallment.isRecalculatedInterestComponent(), scheduledLoanInstallment.getLoanCompoundingDetails());
|
||||
installments.add(installment);
|
||||
}
|
||||
return installment;
|
||||
@@ -2473,6 +2618,9 @@ public abstract class AbstractLoanScheduleGenerator implements LoanScheduleGener
|
||||
} else {
|
||||
CalendarInstance calendarInstance = loanApplicationTerms.getCompoundingCalendarInstance();
|
||||
nextScheduleDate = CalendarUtils.getNextScheduleDate(calendarInstance.getCalendar(), startDate);
|
||||
if (loanApplicationTerms.allowCompoundingOnEod()) {
|
||||
nextScheduleDate = nextScheduleDate.plusDays(1);
|
||||
}
|
||||
}
|
||||
|
||||
return nextScheduleDate;
|
||||
@@ -2510,9 +2658,9 @@ public abstract class AbstractLoanScheduleGenerator implements LoanScheduleGener
|
||||
penaltyCharges = penaltyCharges.plus(currentInstallment.getPenaltyChargesOutstanding(currency));
|
||||
}
|
||||
}
|
||||
|
||||
final List<LoanInterestRecalcualtionAdditionalDetails> compoundingDetails = null;
|
||||
return new LoanRepaymentScheduleInstallment(null, 0, onDate, onDate, totalPrincipal.getAmount(), totalInterest.getAmount(),
|
||||
feeCharges.getAmount(), penaltyCharges.getAmount(), false);
|
||||
feeCharges.getAmount(), penaltyCharges.getAmount(), false, compoundingDetails);
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
+1
-18
@@ -25,7 +25,6 @@ import java.util.HashMap;
|
||||
import java.util.Map;
|
||||
import java.util.TreeMap;
|
||||
|
||||
import org.apache.fineract.infrastructure.core.service.DateUtils;
|
||||
import org.apache.fineract.organisation.monetary.domain.Money;
|
||||
import org.apache.fineract.portfolio.loanaccount.data.LoanTermVariationsData;
|
||||
import org.apache.fineract.portfolio.loanproduct.domain.AmortizationMethod;
|
||||
@@ -70,7 +69,6 @@ public class DecliningBalanceInterestLoanScheduleGenerator extends AbstractLoanS
|
||||
|
||||
LocalDate interestStartDate = periodStartDate;
|
||||
Money interestForThisInstallment = totalCumulativePrincipal.zero();
|
||||
Money compoundedMoney = totalCumulativePrincipal.zero();
|
||||
Money compoundedInterest = totalCumulativePrincipal.zero();
|
||||
Money balanceForInterestCalculation = outstandingBalance;
|
||||
Money cumulatingInterestDueToGrace = cumulatingInterestPaymentDueToGrace;
|
||||
@@ -89,13 +87,6 @@ public class DecliningBalanceInterestLoanScheduleGenerator extends AbstractLoanS
|
||||
}
|
||||
}
|
||||
if (principalVariation != null) {
|
||||
// identifies rest date after current date for reducing all
|
||||
// compounding
|
||||
// values
|
||||
LocalDate compoundingEndDate = principalVariation.ceilingKey(DateUtils.getLocalDateOfTenant());
|
||||
if (compoundingEndDate == null) {
|
||||
compoundingEndDate = DateUtils.getLocalDateOfTenant();
|
||||
}
|
||||
|
||||
for (Map.Entry<LocalDate, Money> principal : principalVariation.entrySet()) {
|
||||
|
||||
@@ -120,7 +111,7 @@ public class DecliningBalanceInterestLoanScheduleGenerator extends AbstractLoanS
|
||||
}
|
||||
// fee compounding will be done after calculation
|
||||
compoundFee = compoundingMap.get(principal.getKey());
|
||||
compoundedMoney = compoundedMoney.plus(interestToBeCompounded).plus(compoundFee);
|
||||
compoundingMap.put(principal.getKey(), interestToBeCompounded.plus(compoundFee));
|
||||
}
|
||||
balanceForInterestCalculation = balanceForInterestCalculation.plus(principal.getValue()).plus(compoundFee);
|
||||
if (interestRates.containsKey(principal.getKey())) {
|
||||
@@ -129,14 +120,6 @@ public class DecliningBalanceInterestLoanScheduleGenerator extends AbstractLoanS
|
||||
}
|
||||
|
||||
}
|
||||
if (!periodEndDate.isBefore(compoundingEndDate)) {
|
||||
balanceForInterestCalculation = balanceForInterestCalculation.minus(compoundedMoney);
|
||||
compoundingMap.clear();
|
||||
} else if (compoundedMoney.isGreaterThanZero()) {
|
||||
compoundingMap.put(periodEndDate, compoundedMoney);
|
||||
compoundingMap.put(compoundingEndDate, compoundedMoney.negated());
|
||||
clearMapDetails(periodEndDate, compoundingMap);
|
||||
}
|
||||
}
|
||||
|
||||
final PrincipalInterest result = loanApplicationTerms.calculateTotalInterestForPeriod(calculator,
|
||||
|
||||
+13
-4
@@ -62,8 +62,8 @@ public class DefaultScheduledDateGenerator implements ScheduledDateGenerator {
|
||||
} else {
|
||||
Calendar currentCalendar = loanApplicationTerms.getLoanCalendar();
|
||||
dueRepaymentPeriodDate = getRepaymentPeriodDate(loanApplicationTerms.getRepaymentPeriodFrequencyType(),
|
||||
loanApplicationTerms.getRepaymentEvery(), lastRepaymentDate, loanApplicationTerms.getNthDay(),
|
||||
loanApplicationTerms.getWeekDayType());
|
||||
loanApplicationTerms.getRepaymentEvery(), lastRepaymentDate, null,
|
||||
null);
|
||||
dueRepaymentPeriodDate = CalendarUtils.adjustDate(dueRepaymentPeriodDate, loanApplicationTerms.getSeedDate(),
|
||||
loanApplicationTerms.getRepaymentPeriodFrequencyType());
|
||||
if (currentCalendar != null) {
|
||||
@@ -219,7 +219,8 @@ public class DefaultScheduledDateGenerator implements ScheduledDateGenerator {
|
||||
|
||||
@Override
|
||||
public LocalDate idealDisbursementDateBasedOnFirstRepaymentDate(final PeriodFrequencyType repaymentPeriodFrequencyType,
|
||||
final int repaidEvery, final LocalDate firstRepaymentDate) {
|
||||
final int repaidEvery, final LocalDate firstRepaymentDate, final Calendar loanCalendar, final HolidayDetailDTO holidayDetailDTO,
|
||||
final LoanApplicationTerms loanApplicationTerms) {
|
||||
|
||||
LocalDate idealDisbursementDate = null;
|
||||
|
||||
@@ -231,7 +232,15 @@ public class DefaultScheduledDateGenerator implements ScheduledDateGenerator {
|
||||
idealDisbursementDate = firstRepaymentDate.minusWeeks(repaidEvery);
|
||||
break;
|
||||
case MONTHS:
|
||||
idealDisbursementDate = firstRepaymentDate.minusMonths(repaidEvery);
|
||||
if (loanCalendar == null) {
|
||||
idealDisbursementDate = firstRepaymentDate.minusMonths(repaidEvery);
|
||||
} else {
|
||||
idealDisbursementDate = CalendarUtils.getNewRepaymentMeetingDate(loanCalendar.getRecurrence(),
|
||||
firstRepaymentDate.minusMonths(repaidEvery), firstRepaymentDate.minusMonths(repaidEvery), repaidEvery,
|
||||
CalendarUtils.getMeetingFrequencyFromPeriodFrequencyType(repaymentPeriodFrequencyType),
|
||||
holidayDetailDTO.getWorkingDays(), loanApplicationTerms.isSkipRepaymentOnFirstDayofMonth(),
|
||||
loanApplicationTerms.getNumberOfdays());
|
||||
}
|
||||
break;
|
||||
case YEARS:
|
||||
idealDisbursementDate = firstRepaymentDate.minusYears(repaidEvery);
|
||||
|
||||
Executable → Regular
+1513
-1854
File diff suppressed because it is too large
Load Diff
+6
@@ -19,8 +19,10 @@
|
||||
package org.apache.fineract.portfolio.loanaccount.loanschedule.domain;
|
||||
|
||||
import java.math.BigDecimal;
|
||||
import java.util.List;
|
||||
|
||||
import org.apache.fineract.organisation.monetary.domain.Money;
|
||||
import org.apache.fineract.portfolio.loanaccount.domain.LoanInterestRecalcualtionAdditionalDetails;
|
||||
import org.apache.fineract.portfolio.loanaccount.loanschedule.data.LoanSchedulePeriodData;
|
||||
import org.joda.time.LocalDate;
|
||||
|
||||
@@ -122,4 +124,8 @@ public final class LoanScheduleModelDisbursementPeriod implements LoanScheduleMo
|
||||
public void addInterestAmount(@SuppressWarnings("unused") Money principalDue) {
|
||||
return;
|
||||
}
|
||||
@Override
|
||||
public List<LoanInterestRecalcualtionAdditionalDetails> getLoanCompoundingDetails() {
|
||||
return null;
|
||||
}
|
||||
}
|
||||
+3
@@ -19,8 +19,10 @@
|
||||
package org.apache.fineract.portfolio.loanaccount.loanschedule.domain;
|
||||
|
||||
import java.math.BigDecimal;
|
||||
import java.util.List;
|
||||
|
||||
import org.apache.fineract.organisation.monetary.domain.Money;
|
||||
import org.apache.fineract.portfolio.loanaccount.domain.LoanInterestRecalcualtionAdditionalDetails;
|
||||
import org.apache.fineract.portfolio.loanaccount.loanschedule.data.LoanSchedulePeriodData;
|
||||
import org.joda.time.LocalDate;
|
||||
|
||||
@@ -51,4 +53,5 @@ public interface LoanScheduleModelPeriod {
|
||||
void addPrincipalAmount(Money principalDue);
|
||||
|
||||
void addInterestAmount(Money interestDue);
|
||||
List<LoanInterestRecalcualtionAdditionalDetails> getLoanCompoundingDetails();
|
||||
}
|
||||
|
||||
+8
@@ -19,8 +19,11 @@
|
||||
package org.apache.fineract.portfolio.loanaccount.loanschedule.domain;
|
||||
|
||||
import java.math.BigDecimal;
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
|
||||
import org.apache.fineract.organisation.monetary.domain.Money;
|
||||
import org.apache.fineract.portfolio.loanaccount.domain.LoanInterestRecalcualtionAdditionalDetails;
|
||||
import org.apache.fineract.portfolio.loanaccount.loanschedule.data.LoanSchedulePeriodData;
|
||||
import org.joda.time.LocalDate;
|
||||
|
||||
@@ -40,6 +43,7 @@ public final class LoanScheduleModelRepaymentPeriod implements LoanScheduleModel
|
||||
private Money penaltyChargesDue;
|
||||
private Money totalDue;
|
||||
private final boolean recalculatedInterestComponent;
|
||||
private final List<LoanInterestRecalcualtionAdditionalDetails> loanCompoundingDetails = new ArrayList<>();
|
||||
|
||||
public static LoanScheduleModelRepaymentPeriod repayment(final int periodNumber, final LocalDate startDate,
|
||||
final LocalDate scheduledDueDate, final Money principalDue, final Money outstandingLoanBalance, final Money interestDue,
|
||||
@@ -154,4 +158,8 @@ public final class LoanScheduleModelRepaymentPeriod implements LoanScheduleModel
|
||||
this.interestDue = this.interestDue.plus(interestDue);
|
||||
this.totalDue = this.totalDue.plus(principalDue);
|
||||
}
|
||||
@Override
|
||||
public List<LoanInterestRecalcualtionAdditionalDetails> getLoanCompoundingDetails() {
|
||||
return this.loanCompoundingDetails;
|
||||
}
|
||||
}
|
||||
+3
-1
@@ -18,6 +18,7 @@
|
||||
*/
|
||||
package org.apache.fineract.portfolio.loanaccount.loanschedule.domain;
|
||||
|
||||
import org.apache.fineract.portfolio.calendar.domain.Calendar;
|
||||
import org.apache.fineract.portfolio.common.domain.DayOfWeekType;
|
||||
import org.apache.fineract.portfolio.common.domain.PeriodFrequencyType;
|
||||
import org.apache.fineract.portfolio.loanaccount.data.HolidayDetailDTO;
|
||||
@@ -28,7 +29,8 @@ public interface ScheduledDateGenerator {
|
||||
LocalDate getLastRepaymentDate(LoanApplicationTerms loanApplicationTerms, final HolidayDetailDTO holidayDetailDTO);
|
||||
|
||||
LocalDate idealDisbursementDateBasedOnFirstRepaymentDate(PeriodFrequencyType repaymentPeriodFrequencyType, int repaidEvery,
|
||||
final LocalDate firstRepaymentDate);
|
||||
final LocalDate firstRepaymentDate, final Calendar loanCalendar, final HolidayDetailDTO holidayDetailDTO,
|
||||
final LoanApplicationTerms loanApplicationTerms);
|
||||
|
||||
LocalDate generateNextRepaymentDate(LocalDate lastRepaymentDate, LoanApplicationTerms loanApplicationTerms, boolean isFirstRepayment,
|
||||
final HolidayDetailDTO holidayDetailDTO);
|
||||
|
||||
+72
-31
@@ -68,6 +68,7 @@ import org.apache.fineract.portfolio.client.domain.ClientRepositoryWrapper;
|
||||
import org.apache.fineract.portfolio.common.domain.DayOfWeekType;
|
||||
import org.apache.fineract.portfolio.common.domain.DaysInMonthType;
|
||||
import org.apache.fineract.portfolio.common.domain.DaysInYearType;
|
||||
import org.apache.fineract.portfolio.common.domain.NthDayType;
|
||||
import org.apache.fineract.portfolio.common.domain.PeriodFrequencyType;
|
||||
import org.apache.fineract.portfolio.floatingrates.data.FloatingRateDTO;
|
||||
import org.apache.fineract.portfolio.floatingrates.data.FloatingRatePeriodData;
|
||||
@@ -115,7 +116,6 @@ import org.apache.fineract.portfolio.loanproduct.service.LoanEnumerations;
|
||||
import org.apache.fineract.useradministration.domain.AppUser;
|
||||
import org.joda.time.Days;
|
||||
import org.joda.time.LocalDate;
|
||||
import org.joda.time.LocalTime;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.stereotype.Service;
|
||||
|
||||
@@ -256,6 +256,12 @@ public class LoanScheduleAssembler {
|
||||
final PeriodFrequencyType meetingPeriodFrequency = CalendarUtils.getMeetingPeriodFrequencyType(calendar.getRecurrence());
|
||||
validateRepaymentFrequencyIsSameAsMeetingFrequency(meetingPeriodFrequency.getValue(), repaymentFrequencyType,
|
||||
CalendarUtils.getInterval(calendar.getRecurrence()), repaymentEvery);
|
||||
} else {
|
||||
if (repaymentPeriodFrequencyType == PeriodFrequencyType.MONTHS && nthDay != null && nthDay != NthDayType.INVALID.getValue()) {
|
||||
LocalDate calendarStartDate = repaymentsStartingFromDate;
|
||||
if (calendarStartDate == null) calendarStartDate = expectedDisbursementDate;
|
||||
calendar = createLoanCalendar(calendarStartDate, repaymentEvery, CalendarFrequencyType.MONTHLY, dayOfWeek, nthDay);
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
@@ -306,7 +312,8 @@ public class LoanScheduleAssembler {
|
||||
final Integer graceOnInterestPayment = this.fromApiJsonHelper.extractIntegerWithLocaleNamed("graceOnInterestPayment", element);
|
||||
final Integer graceOnInterestCharged = this.fromApiJsonHelper.extractIntegerWithLocaleNamed("graceOnInterestCharged", element);
|
||||
final LocalDate interestChargedFromDate = this.fromApiJsonHelper.extractLocalDateNamed("interestChargedFromDate", element);
|
||||
final Boolean isInterestChargedFromDateSameAsDisbursalDateEnabled = this.configurationDomainService.isInterestChargedFromDateSameAsDisbursementDate();
|
||||
final Boolean isInterestChargedFromDateSameAsDisbursalDateEnabled = this.configurationDomainService
|
||||
.isInterestChargedFromDateSameAsDisbursementDate();
|
||||
|
||||
final Integer graceOnArrearsAgeing = this.fromApiJsonHelper.extractIntegerWithLocaleNamed(
|
||||
LoanProductConstants.graceOnArrearsAgeingParameterName, element);
|
||||
@@ -334,39 +341,47 @@ public class LoanScheduleAssembler {
|
||||
CalendarInstance restCalendarInstance = null;
|
||||
RecalculationFrequencyType compoundingFrequencyType = null;
|
||||
CalendarInstance compoundingCalendarInstance = null;
|
||||
InterestRecalculationCompoundingMethod compoundingMethod = null;
|
||||
boolean allowCompoundingOnEod = false;
|
||||
if (isInterestRecalculationEnabled) {
|
||||
LoanProductInterestRecalculationDetails loanProductInterestRecalculationDetails = loanProduct
|
||||
.getProductInterestRecalculationDetails();
|
||||
recalculationFrequencyType = loanProductInterestRecalculationDetails.getRestFrequencyType();
|
||||
Integer repeatsOnDay = null;
|
||||
Integer recalculationFrequencyNthDay = loanProductInterestRecalculationDetails.getRestFrequencyOnDay();
|
||||
if (recalculationFrequencyNthDay == null) {
|
||||
recalculationFrequencyNthDay = loanProductInterestRecalculationDetails.getRestFrequencyNthDay();
|
||||
repeatsOnDay = loanProductInterestRecalculationDetails.getRestFrequencyWeekday();
|
||||
}
|
||||
Integer frequency = loanProductInterestRecalculationDetails.getRestInterval();
|
||||
if (recalculationFrequencyType.isSameAsRepayment()) {
|
||||
restCalendarInstance = createCalendarForSameAsRepayment(repaymentEvery, repaymentPeriodFrequencyType,
|
||||
expectedDisbursementDate);
|
||||
} else {
|
||||
LocalDate calendarStartDate = this.fromApiJsonHelper.extractLocalDateNamed(
|
||||
LoanProductConstants.recalculationRestFrequencyDateParamName, element);
|
||||
if (calendarStartDate == null) {
|
||||
calendarStartDate = expectedDisbursementDate;
|
||||
}
|
||||
LocalDate calendarStartDate = expectedDisbursementDate;
|
||||
restCalendarInstance = createInterestRecalculationCalendarInstance(calendarStartDate, recalculationFrequencyType,
|
||||
loanProductInterestRecalculationDetails.getRestInterval());
|
||||
frequency, recalculationFrequencyNthDay, repeatsOnDay);
|
||||
}
|
||||
InterestRecalculationCompoundingMethod compoundingMethod = InterestRecalculationCompoundingMethod
|
||||
.fromInt(loanProductInterestRecalculationDetails.getInterestRecalculationCompoundingMethod());
|
||||
compoundingMethod = InterestRecalculationCompoundingMethod.fromInt(loanProductInterestRecalculationDetails
|
||||
.getInterestRecalculationCompoundingMethod());
|
||||
if (compoundingMethod.isCompoundingEnabled()) {
|
||||
Integer compoundingRepeatsOnDay = null;
|
||||
Integer recalculationCompoundingFrequencyNthDay = loanProductInterestRecalculationDetails.getCompoundingFrequencyOnDay();
|
||||
if (recalculationCompoundingFrequencyNthDay == null) {
|
||||
recalculationCompoundingFrequencyNthDay = loanProductInterestRecalculationDetails.getCompoundingFrequencyNthDay();
|
||||
compoundingRepeatsOnDay = loanProductInterestRecalculationDetails.getCompoundingFrequencyWeekday();
|
||||
}
|
||||
compoundingFrequencyType = loanProductInterestRecalculationDetails.getCompoundingFrequencyType();
|
||||
if (compoundingFrequencyType.isSameAsRepayment()) {
|
||||
compoundingCalendarInstance = createCalendarForSameAsRepayment(repaymentEvery, repaymentPeriodFrequencyType,
|
||||
expectedDisbursementDate);
|
||||
} else {
|
||||
LocalDate calendarStartDate = this.fromApiJsonHelper.extractLocalDateNamed(
|
||||
LoanProductConstants.recalculationCompoundingFrequencyDateParamName, element);
|
||||
if (calendarStartDate == null) {
|
||||
calendarStartDate = expectedDisbursementDate;
|
||||
}
|
||||
LocalDate calendarStartDate = expectedDisbursementDate;
|
||||
compoundingCalendarInstance = createInterestRecalculationCalendarInstance(calendarStartDate, compoundingFrequencyType,
|
||||
loanProductInterestRecalculationDetails.getCompoundingInterval());
|
||||
loanProductInterestRecalculationDetails.getCompoundingInterval(), recalculationCompoundingFrequencyNthDay,
|
||||
compoundingRepeatsOnDay);
|
||||
}
|
||||
|
||||
allowCompoundingOnEod = loanProductInterestRecalculationDetails.allowCompoundingOnEod();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -405,6 +420,21 @@ public class LoanScheduleAssembler {
|
||||
}
|
||||
}
|
||||
|
||||
final Long clientId = this.fromApiJsonHelper.extractLongNamed("clientId", element);
|
||||
Client client = null;
|
||||
Long officeId = null;
|
||||
if (clientId != null) {
|
||||
client = this.clientRepository.findOneWithNotFoundDetection(clientId);
|
||||
officeId = client.getOffice().getId();
|
||||
} else if (groupId != null) {
|
||||
group = this.groupRepository.findOneWithNotFoundDetection(groupId);
|
||||
officeId = group.getOffice().getId();
|
||||
}
|
||||
final boolean isHolidayEnabled = this.configurationDomainService.isRescheduleRepaymentsOnHolidaysEnabled();
|
||||
final List<Holiday> holidays = this.holidayRepository.findByOfficeIdAndGreaterThanDate(officeId, expectedDisbursementDate.toDate(),
|
||||
HolidayStatusType.ACTIVE.getValue());
|
||||
final WorkingDays workingDays = this.workingDaysRepository.findOne();
|
||||
HolidayDetailDTO detailDTO = new HolidayDetailDTO(isHolidayEnabled, holidays, workingDays);
|
||||
return LoanApplicationTerms.assembleFrom(applicationCurrency, loanTermFrequency, loanTermPeriodFrequencyType, numberOfRepayments,
|
||||
repaymentEvery, repaymentPeriodFrequencyType, nthDay, weekDayType, amortizationMethod, interestMethod,
|
||||
interestRatePerPeriod, interestRatePeriodFrequencyType, annualNominalInterestRate, interestCalculationPeriodMethod,
|
||||
@@ -412,21 +442,24 @@ public class LoanScheduleAssembler {
|
||||
calculatedRepaymentsStartingFromDate, graceOnPrincipalPayment, recurringMoratoriumOnPrincipalPeriods, graceOnInterestPayment, graceOnInterestCharged,
|
||||
interestChargedFromDate, inArrearsToleranceMoney, loanProduct.isMultiDisburseLoan(), emiAmount, disbursementDatas,
|
||||
maxOutstandingBalance, graceOnArrearsAgeing, daysInMonthType, daysInYearType, isInterestRecalculationEnabled,
|
||||
recalculationFrequencyType, restCalendarInstance, compoundingCalendarInstance, compoundingFrequencyType,
|
||||
recalculationFrequencyType, restCalendarInstance, compoundingMethod, compoundingCalendarInstance, compoundingFrequencyType,
|
||||
principalThresholdForLastInstalment, installmentAmountInMultiplesOf, loanProduct.preCloseInterestCalculationStrategy(),
|
||||
calendar, BigDecimal.ZERO, loanTermVariations, isInterestChargedFromDateSameAsDisbursalDateEnabled,numberOfDays, isSkipMeetingOnFirstDay);
|
||||
calendar, BigDecimal.ZERO, loanTermVariations, isInterestChargedFromDateSameAsDisbursalDateEnabled,numberOfDays, isSkipMeetingOnFirstDay, detailDTO,
|
||||
allowCompoundingOnEod);
|
||||
}
|
||||
|
||||
private CalendarInstance createCalendarForSameAsRepayment(final Integer repaymentEvery,
|
||||
final PeriodFrequencyType repaymentPeriodFrequencyType, final LocalDate expectedDisbursementDate) {
|
||||
|
||||
final Integer recalculationFrequencyNthDay = null;
|
||||
final Integer repeatsOnDay = expectedDisbursementDate.getDayOfWeek();
|
||||
CalendarInstance restCalendarInstance = createInterestRecalculationCalendarInstance(expectedDisbursementDate, repaymentEvery,
|
||||
CalendarFrequencyType.from(repaymentPeriodFrequencyType));
|
||||
CalendarFrequencyType.from(repaymentPeriodFrequencyType), recalculationFrequencyNthDay, repeatsOnDay);
|
||||
return restCalendarInstance;
|
||||
}
|
||||
|
||||
private CalendarInstance createInterestRecalculationCalendarInstance(final LocalDate calendarStartDate,
|
||||
final RecalculationFrequencyType recalculationFrequencyType, final Integer frequency) {
|
||||
final RecalculationFrequencyType recalculationFrequencyType, final Integer frequency,
|
||||
final Integer recalculationFrequencyNthDay, final Integer repeatsOnDay) {
|
||||
|
||||
CalendarFrequencyType calendarFrequencyType = CalendarFrequencyType.INVALID;
|
||||
switch (recalculationFrequencyType) {
|
||||
@@ -443,18 +476,26 @@ public class LoanScheduleAssembler {
|
||||
break;
|
||||
}
|
||||
|
||||
return createInterestRecalculationCalendarInstance(calendarStartDate, frequency, calendarFrequencyType);
|
||||
return createInterestRecalculationCalendarInstance(calendarStartDate, frequency, calendarFrequencyType,
|
||||
recalculationFrequencyNthDay, repeatsOnDay);
|
||||
}
|
||||
|
||||
private CalendarInstance createInterestRecalculationCalendarInstance(final LocalDate calendarStartDate, final Integer frequency,
|
||||
CalendarFrequencyType calendarFrequencyType) {
|
||||
final Integer repeatsOnDay = calendarStartDate.getDayOfWeek();
|
||||
CalendarFrequencyType calendarFrequencyType, final Integer recalculationFrequencyNthDay, final Integer repeatsOnDay) {
|
||||
final String title = "loan_recalculation_detail";
|
||||
final Calendar calendar = Calendar.createRepeatingCalendar(title, calendarStartDate, CalendarType.COLLECTION.getValue(),
|
||||
calendarFrequencyType, frequency, repeatsOnDay);
|
||||
calendarFrequencyType, frequency, repeatsOnDay, recalculationFrequencyNthDay);
|
||||
return CalendarInstance.from(calendar, null, CalendarEntityType.LOAN_RECALCULATION_REST_DETAIL.getValue());
|
||||
}
|
||||
|
||||
private Calendar createLoanCalendar(final LocalDate calendarStartDate, final Integer frequency,
|
||||
CalendarFrequencyType calendarFrequencyType, final Integer repeatsOnDay, final Integer repeatsOnNthDayOfMonth) {
|
||||
final String title = "loan_schedule";
|
||||
final Calendar calendar = Calendar.createRepeatingCalendar(title, calendarStartDate, CalendarType.COLLECTION.getValue(),
|
||||
calendarFrequencyType, frequency, repeatsOnDay, repeatsOnNthDayOfMonth);
|
||||
return calendar;
|
||||
}
|
||||
|
||||
private List<DisbursementData> fetchDisbursementData(final JsonObject command) {
|
||||
final Locale locale = this.fromApiJsonHelper.extractLocaleParameter(command);
|
||||
final String dateFormat = this.fromApiJsonHelper.extractDateFormatParameter(command);
|
||||
@@ -559,7 +600,7 @@ public class LoanScheduleAssembler {
|
||||
|
||||
validateDisbursementDateIsOnNonWorkingDay(loanApplicationTerms.getExpectedDisbursementDate(), workingDays);
|
||||
validateDisbursementDateIsOnHoliday(loanApplicationTerms.getExpectedDisbursementDate(), isHolidayEnabled, holidays);
|
||||
|
||||
|
||||
Set<LoanDisbursementDetails> loanDisbursementDetails = this.loanUtilService.fetchDisbursementData(element.getAsJsonObject());
|
||||
|
||||
return assembleLoanScheduleFrom(loanApplicationTerms, isHolidayEnabled, holidays, workingDays, element, loanDisbursementDetails);
|
||||
@@ -996,10 +1037,10 @@ public class LoanScheduleAssembler {
|
||||
final LocalDate dateBasedOnMinimumDaysBetweenDisbursalAndFirstRepayment = expectedDisbursementDate
|
||||
.plusDays(minimumDaysBetweenDisbursalAndFirstRepayment);
|
||||
|
||||
if ((loanType.isJLGAccount() || loanType.isGroupAccount()) && calendar != null) {
|
||||
if (calendar != null) {
|
||||
|
||||
final LocalDate refernceDateForCalculatingFirstRepaymentDate = expectedDisbursementDate;
|
||||
derivedFirstRepayment = deriveFirstRepaymentDateForJLGLoans(repaymentEvery, expectedDisbursementDate,
|
||||
derivedFirstRepayment = deriveFirstRepaymentDateForLoans(repaymentEvery, expectedDisbursementDate,
|
||||
refernceDateForCalculatingFirstRepaymentDate, repaymentPeriodFrequencyType,
|
||||
minimumDaysBetweenDisbursalAndFirstRepayment, calendar);
|
||||
|
||||
@@ -1027,7 +1068,7 @@ public class LoanScheduleAssembler {
|
||||
return derivedFirstRepayment;
|
||||
}
|
||||
|
||||
private LocalDate deriveFirstRepaymentDateForJLGLoans(final Integer repaymentEvery, final LocalDate expectedDisbursementDate,
|
||||
private LocalDate deriveFirstRepaymentDateForLoans(final Integer repaymentEvery, final LocalDate expectedDisbursementDate,
|
||||
final LocalDate refernceDateForCalculatingFirstRepaymentDate, final PeriodFrequencyType repaymentPeriodFrequencyType,
|
||||
final Integer minimumDaysBetweenDisbursalAndFirstRepayment, final Calendar calendar) {
|
||||
boolean isMeetingSkipOnFirstDayOfMonth = configurationDomainService.isSkippingMeetingOnFirstDayOfMonthEnabled();
|
||||
@@ -1036,7 +1077,7 @@ public class LoanScheduleAssembler {
|
||||
final LocalDate derivedFirstRepayment = CalendarUtils.getFirstRepaymentMeetingDate(calendar,
|
||||
refernceDateForCalculatingFirstRepaymentDate, repaymentEvery, frequency, isMeetingSkipOnFirstDayOfMonth, numberOfDays);
|
||||
final LocalDate minimumFirstRepaymentDate = expectedDisbursementDate.plusDays(minimumDaysBetweenDisbursalAndFirstRepayment);
|
||||
return minimumFirstRepaymentDate.isBefore(derivedFirstRepayment) ? derivedFirstRepayment : deriveFirstRepaymentDateForJLGLoans(
|
||||
return minimumFirstRepaymentDate.isBefore(derivedFirstRepayment) ? derivedFirstRepayment : deriveFirstRepaymentDateForLoans(
|
||||
repaymentEvery, expectedDisbursementDate, derivedFirstRepayment, repaymentPeriodFrequencyType,
|
||||
minimumDaysBetweenDisbursalAndFirstRepayment, calendar);
|
||||
}
|
||||
|
||||
+3
-2
@@ -63,6 +63,7 @@ import org.apache.fineract.portfolio.loanaccount.domain.DefaultLoanLifecycleStat
|
||||
import org.apache.fineract.portfolio.loanaccount.domain.Loan;
|
||||
import org.apache.fineract.portfolio.loanaccount.domain.LoanCharge;
|
||||
import org.apache.fineract.portfolio.loanaccount.domain.LoanInstallmentCharge;
|
||||
import org.apache.fineract.portfolio.loanaccount.domain.LoanInterestRecalcualtionAdditionalDetails;
|
||||
import org.apache.fineract.portfolio.loanaccount.domain.LoanLifecycleStateMachine;
|
||||
import org.apache.fineract.portfolio.loanaccount.domain.LoanRepaymentScheduleInstallment;
|
||||
import org.apache.fineract.portfolio.loanaccount.domain.LoanRepository;
|
||||
@@ -370,13 +371,13 @@ public class LoanRescheduleRequestWritePlatformServiceImpl implements LoanResche
|
||||
final Collection<LoanRescheduleModelRepaymentPeriod> periods = loanRescheduleModel.getPeriods();
|
||||
List<LoanRepaymentScheduleInstallment> repaymentScheduleInstallments = loan.getRepaymentScheduleInstallments();
|
||||
Collection<LoanCharge> waiveLoanCharges = new ArrayList<>();
|
||||
|
||||
final List<LoanInterestRecalcualtionAdditionalDetails> compoundingDetails = null;
|
||||
for (LoanRescheduleModelRepaymentPeriod period : periods) {
|
||||
|
||||
if (period.isNew()) {
|
||||
LoanRepaymentScheduleInstallment repaymentScheduleInstallment = new LoanRepaymentScheduleInstallment(loan,
|
||||
period.periodNumber(), period.periodFromDate(), period.periodDueDate(), period.principalDue(),
|
||||
period.interestDue(), BigDecimal.ZERO, BigDecimal.ZERO, false);
|
||||
period.interestDue(), BigDecimal.ZERO, BigDecimal.ZERO, false, compoundingDetails);
|
||||
|
||||
repaymentScheduleInstallments.add(repaymentScheduleInstallment);
|
||||
}
|
||||
|
||||
+22
-11
@@ -46,18 +46,29 @@ public final class CalculateLoanScheduleQueryFromApiJsonHelper {
|
||||
/**
|
||||
* The parameters supported for this command.
|
||||
*/
|
||||
final Set<String> supportedParameters = new HashSet<>(Arrays.asList("id", "clientId", "groupId", "loanType", "calendarId", "productId",
|
||||
"accountNo", "externalId", "fundId", "loanOfficerId", "loanPurposeId", "transactionProcessingStrategyId", "principal",
|
||||
"inArrearsTolerance", "interestRatePerPeriod", "repaymentEvery", "numberOfRepayments", "loanTermFrequency",
|
||||
"loanTermFrequencyType", "repaymentFrequencyType", "amortizationType", "interestType", "interestCalculationPeriodType",
|
||||
LoanProductConstants.allowPartialPeriodInterestCalcualtionParamName, "interestRateFrequencyType", "expectedDisbursementDate",
|
||||
"repaymentsStartingFromDate", "graceOnPrincipalPayment", "recurringMoratoriumOnPrincipalPeriods", "graceOnInterestPayment", "graceOnInterestCharged",
|
||||
"interestChargedFromDate", "submittedOnDate", "submittedOnNote", "locale", "dateFormat", "charges", "collateral",
|
||||
"syncDisbursementWithMeeting", "linkAccountId", LoanApiConstants.disbursementDataParameterName,
|
||||
final Set<String> supportedParameters = new HashSet<>(Arrays.asList(LoanApiConstants.idParameterName,
|
||||
LoanApiConstants.clientIdParameterName, LoanApiConstants.groupIdParameterName, LoanApiConstants.loanTypeParameterName,
|
||||
LoanApiConstants.calendarIdParameterName, LoanApiConstants.productIdParameterName, LoanApiConstants.accountNoParameterName,
|
||||
LoanApiConstants.externalIdParameterName, LoanApiConstants.fundIdParameterName, LoanApiConstants.loanOfficerIdParameterName,
|
||||
LoanApiConstants.loanPurposeIdParameterName, LoanApiConstants.transactionProcessingStrategyIdParameterName,
|
||||
LoanApiConstants.principalParamName, LoanApiConstants.inArrearsToleranceParameterName,
|
||||
LoanApiConstants.interestRatePerPeriodParameterName, LoanApiConstants.repaymentEveryParameterName,
|
||||
LoanApiConstants.numberOfRepaymentsParameterName, LoanApiConstants.loanTermFrequencyParameterName,
|
||||
LoanApiConstants.loanTermFrequencyTypeParameterName, LoanApiConstants.repaymentFrequencyTypeParameterName,
|
||||
LoanApiConstants.amortizationTypeParameterName, LoanApiConstants.interestTypeParameterName,
|
||||
LoanApiConstants.interestCalculationPeriodTypeParameterName,
|
||||
LoanProductConstants.allowPartialPeriodInterestCalcualtionParamName, LoanApiConstants.interestRateFrequencyTypeParameterName,
|
||||
LoanApiConstants.disbursementDateParameterName, LoanApiConstants.repaymentsStartingFromDateParameterName,
|
||||
LoanApiConstants.graceOnPrincipalPaymentParameterName, LoanApiConstants.graceOnInterestPaymentParameterName,
|
||||
LoanApiConstants.graceOnInterestChargedParameterName, LoanApiConstants.interestChargedFromDateParameterName,
|
||||
LoanApiConstants.submittedOnDateParameterName, LoanApiConstants.submittedOnNoteParameterName,
|
||||
LoanApiConstants.localeParameterName, LoanApiConstants.dateFormatParameterName, LoanApiConstants.chargesParameterName,
|
||||
LoanApiConstants.collateralParameterName, LoanApiConstants.syncDisbursementWithMeetingParameterName,
|
||||
LoanApiConstants.linkAccountIdParameterName, LoanApiConstants.disbursementDataParameterName,
|
||||
LoanApiConstants.emiAmountParameterName, LoanApiConstants.maxOutstandingBalanceParameterName,
|
||||
LoanProductConstants.graceOnArrearsAgeingParameterName, LoanProductConstants.recalculationRestFrequencyDateParamName,
|
||||
"createStandingInstructionAtDisbursement", LoanApiConstants.isFloatingInterestRateParameterName,
|
||||
LoanApiConstants.interestRateDifferentialParameterName));
|
||||
LoanProductConstants.graceOnArrearsAgeingParameterName, LoanApiConstants.createStandingInstructionAtDisbursementParameterName,
|
||||
LoanApiConstants.isFloatingInterestRateParameterName, LoanApiConstants.interestRateDifferentialParameterName,
|
||||
LoanApiConstants.repaymentFrequencyNthDayTypeParameterName, LoanApiConstants.repaymentFrequencyDayOfWeekTypeParameterName));
|
||||
|
||||
private final FromJsonHelper fromApiJsonHelper;
|
||||
|
||||
|
||||
+41
-58
@@ -36,10 +36,10 @@ import org.apache.fineract.infrastructure.core.exception.PlatformApiDataValidati
|
||||
import org.apache.fineract.infrastructure.core.exception.UnsupportedParameterException;
|
||||
import org.apache.fineract.infrastructure.core.serialization.FromJsonHelper;
|
||||
import org.apache.fineract.portfolio.accountdetails.domain.AccountType;
|
||||
import org.apache.fineract.portfolio.calendar.service.CalendarUtils;
|
||||
import org.apache.fineract.portfolio.loanaccount.api.LoanApiConstants;
|
||||
import org.apache.fineract.portfolio.loanaccount.domain.Loan;
|
||||
import org.apache.fineract.portfolio.loanaccount.domain.LoanCharge;
|
||||
import org.apache.fineract.portfolio.loanaccount.domain.LoanInterestRecalculationDetails;
|
||||
import org.apache.fineract.portfolio.loanproduct.LoanProductConstants;
|
||||
import org.apache.fineract.portfolio.loanproduct.domain.InterestCalculationPeriodMethod;
|
||||
import org.apache.fineract.portfolio.loanproduct.domain.InterestMethod;
|
||||
@@ -60,34 +60,38 @@ public final class LoanApplicationCommandFromApiJsonHelper {
|
||||
/**
|
||||
* The parameters supported for this command.
|
||||
*/
|
||||
final Set<String> supportedParameters = new HashSet<>(Arrays.asList("dateFormat", "locale", "id", "clientId", "groupId", "loanType",
|
||||
"productId", "principal", "loanTermFrequency", "loanTermFrequencyType", "numberOfRepayments", "repaymentEvery",
|
||||
"repaymentFrequencyType", "repaymentFrequencyNthDayType", "repaymentFrequencyDayOfWeekType", "interestRatePerPeriod",
|
||||
"amortizationType", "interestType", LoanApiConstants.isFloatingInterestRate, LoanApiConstants.interestRateDifferential,
|
||||
"interestCalculationPeriodType", LoanProductConstants.allowPartialPeriodInterestCalcualtionParamName,
|
||||
"interestRateFrequencyType", "expectedDisbursementDate", "repaymentsStartingFromDate",
|
||||
"graceOnPrincipalPayment",
|
||||
"recurringMoratoriumOnPrincipalPeriods",
|
||||
"graceOnInterestPayment",
|
||||
"graceOnInterestCharged",
|
||||
"interestChargedFromDate",
|
||||
"submittedOnDate",
|
||||
"submittedOnNote",
|
||||
"accountNo",
|
||||
"externalId",
|
||||
"fundId",
|
||||
"loanOfficerId", // optional
|
||||
"loanPurposeId",
|
||||
"inArrearsTolerance",
|
||||
"charges",
|
||||
"collateral", // optional
|
||||
"transactionProcessingStrategyId", // settings
|
||||
"calendarId", // optional
|
||||
"syncDisbursementWithMeeting",// optional
|
||||
"linkAccountId", LoanApiConstants.disbursementDataParameterName, LoanApiConstants.emiAmountParameterName,
|
||||
LoanApiConstants.maxOutstandingBalanceParameterName, LoanProductConstants.graceOnArrearsAgeingParameterName,
|
||||
LoanProductConstants.recalculationRestFrequencyDateParamName,
|
||||
LoanProductConstants.recalculationCompoundingFrequencyDateParamName, "createStandingInstructionAtDisbursement"));
|
||||
final Set<String> supportedParameters = new HashSet<>(Arrays.asList(LoanApiConstants.dateFormatParameterName,
|
||||
LoanApiConstants.localeParameterName, LoanApiConstants.idParameterName, LoanApiConstants.clientIdParameterName,
|
||||
LoanApiConstants.groupIdParameterName, LoanApiConstants.loanTypeParameterName, LoanApiConstants.productIdParameterName,
|
||||
LoanApiConstants.principalParamName, LoanApiConstants.loanTermFrequencyParameterName,
|
||||
LoanApiConstants.loanTermFrequencyTypeParameterName, LoanApiConstants.numberOfRepaymentsParameterName,
|
||||
LoanApiConstants.repaymentEveryParameterName, LoanApiConstants.repaymentFrequencyTypeParameterName,
|
||||
LoanApiConstants.repaymentFrequencyNthDayTypeParameterName, LoanApiConstants.repaymentFrequencyDayOfWeekTypeParameterName,
|
||||
LoanApiConstants.interestRatePerPeriodParameterName, LoanApiConstants.amortizationTypeParameterName,
|
||||
LoanApiConstants.interestTypeParameterName, LoanApiConstants.isFloatingInterestRate, LoanApiConstants.interestRateDifferential,
|
||||
LoanApiConstants.interestCalculationPeriodTypeParameterName,
|
||||
LoanProductConstants.allowPartialPeriodInterestCalcualtionParamName, LoanApiConstants.interestRateFrequencyTypeParameterName,
|
||||
LoanApiConstants.disbursementDateParameterName, LoanApiConstants.repaymentsStartingFromDateParameterName,
|
||||
LoanApiConstants.graceOnPrincipalPaymentParameterName,
|
||||
LoanApiConstants.graceOnInterestPaymentParameterName,
|
||||
LoanApiConstants.graceOnInterestChargedParameterName,
|
||||
LoanApiConstants.interestChargedFromDateParameterName,
|
||||
LoanApiConstants.submittedOnDateParameterName,
|
||||
LoanApiConstants.submittedOnNoteParameterName,
|
||||
LoanApiConstants.accountNoParameterName,
|
||||
LoanApiConstants.externalIdParameterName,
|
||||
LoanApiConstants.fundIdParameterName,
|
||||
LoanApiConstants.loanOfficerIdParameterName, // optional
|
||||
LoanApiConstants.loanPurposeIdParameterName,
|
||||
LoanApiConstants.inArrearsToleranceParameterName,
|
||||
LoanApiConstants.chargesParameterName,
|
||||
LoanApiConstants.collateralParameterName, // optional
|
||||
LoanApiConstants.transactionProcessingStrategyIdParameterName, // settings
|
||||
LoanApiConstants.calendarIdParameterName, // optional
|
||||
LoanApiConstants.syncDisbursementWithMeetingParameterName,// optional
|
||||
LoanApiConstants.linkAccountIdParameterName, LoanApiConstants.disbursementDataParameterName,
|
||||
LoanApiConstants.emiAmountParameterName, LoanApiConstants.maxOutstandingBalanceParameterName,
|
||||
LoanProductConstants.graceOnArrearsAgeingParameterName, LoanApiConstants.createStandingInstructionAtDisbursementParameterName));
|
||||
|
||||
private final FromJsonHelper fromApiJsonHelper;
|
||||
private final CalculateLoanScheduleQueryFromApiJsonHelper apiJsonHelper;
|
||||
@@ -214,6 +218,10 @@ public final class LoanApplicationCommandFromApiJsonHelper {
|
||||
baseDataValidator.reset().parameter(repaymentEveryFrequencyTypeParameterName).value(repaymentEveryType).notNull()
|
||||
.inMinMaxRange(0, 3);
|
||||
|
||||
final String repaymentFrequencyNthDayTypeParameterName = "repaymentFrequencyNthDayType";
|
||||
final String repaymentFrequencyDayOfWeekTypeParameterName = "repaymentFrequencyDayOfWeekType";
|
||||
CalendarUtils.validateNthDayOfMonthFrequency(baseDataValidator, repaymentFrequencyNthDayTypeParameterName,
|
||||
repaymentFrequencyDayOfWeekTypeParameterName, element, this.fromApiJsonHelper);
|
||||
final String interestTypeParameterName = "interestType";
|
||||
final Integer interestType = this.fromApiJsonHelper.extractIntegerSansLocaleNamed(interestTypeParameterName, element);
|
||||
baseDataValidator.reset().parameter(interestTypeParameterName).value(interestType).notNull().inMinMaxRange(0, 1);
|
||||
@@ -591,6 +599,10 @@ public final class LoanApplicationCommandFromApiJsonHelper {
|
||||
element);
|
||||
baseDataValidator.reset().parameter(repaymentEveryTypeParameterName).value(repaymentEveryType).notNull().inMinMaxRange(0, 3);
|
||||
}
|
||||
final String repaymentFrequencyNthDayTypeParameterName = "repaymentFrequencyNthDayType";
|
||||
final String repaymentFrequencyDayOfWeekTypeParameterName = "repaymentFrequencyDayOfWeekType";
|
||||
CalendarUtils.validateNthDayOfMonthFrequency(baseDataValidator, repaymentFrequencyNthDayTypeParameterName,
|
||||
repaymentFrequencyDayOfWeekTypeParameterName, element, this.fromApiJsonHelper);
|
||||
|
||||
final String interestTypeParameterName = "interestType";
|
||||
Integer interestType = null;
|
||||
@@ -1095,14 +1107,6 @@ public final class LoanApplicationCommandFromApiJsonHelper {
|
||||
|
||||
}
|
||||
|
||||
public void validateRecalcuationFrequency(final LocalDate recalculationFrequencyDate, final LocalDate expectedDisbursementDate,
|
||||
final List<ApiParameterError> dataValidationErrors, final String paramName) {
|
||||
|
||||
final DataValidatorBuilder baseDataValidator = new DataValidatorBuilder(dataValidationErrors).resource("loan");
|
||||
baseDataValidator.reset().parameter(paramName).value(recalculationFrequencyDate).notNull()
|
||||
.validateDateBeforeOrEqual(expectedDisbursementDate);
|
||||
}
|
||||
|
||||
public void validateLoanCharges(final Set<LoanCharge> charges, final List<ApiParameterError> dataValidationErrors) {
|
||||
if (charges == null) { return; }
|
||||
final DataValidatorBuilder baseDataValidator = new DataValidatorBuilder(dataValidationErrors).resource("loan");
|
||||
@@ -1139,32 +1143,11 @@ public final class LoanApplicationCommandFromApiJsonHelper {
|
||||
|
||||
public void validateLoanForInterestRecalculation(final Loan loan) {
|
||||
final List<ApiParameterError> dataValidationErrors = new ArrayList<>();
|
||||
LoanInterestRecalculationDetails interestRecalculationDetails = loan.loanInterestRecalculationDetails();
|
||||
if (!interestRecalculationDetails.getRestFrequencyType().isSameAsRepayment()) {
|
||||
String paramName = LoanProductConstants.recalculationRestFrequencyDateParamName;
|
||||
validateRecalcuationFrequency(interestRecalculationDetails.getRestFrequencyLocalDate(), loan.getExpectedDisbursedOnLocalDate(),
|
||||
dataValidationErrors, paramName);
|
||||
}
|
||||
|
||||
if (interestRecalculationDetails.getInterestRecalculationCompoundingMethod().isCompoundingEnabled()
|
||||
&& !interestRecalculationDetails.getCompoundingFrequencyType().isSameAsRepayment()) {
|
||||
String paramName = LoanProductConstants.recalculationCompoundingFrequencyDateParamName;
|
||||
validateCompoundingFrequency(interestRecalculationDetails.getCompoundingFrequencyLocalDate(),
|
||||
loan.getExpectedDisbursedOnLocalDate(), dataValidationErrors, paramName);
|
||||
}
|
||||
|
||||
validateLoanCharges(loan.charges(), dataValidationErrors);
|
||||
if (!dataValidationErrors.isEmpty()) { throw new PlatformApiDataValidationException(dataValidationErrors); }
|
||||
}
|
||||
|
||||
public void validateCompoundingFrequency(final LocalDate recalculationFrequencyDate, final LocalDate expectedDisbursementDate,
|
||||
final List<ApiParameterError> dataValidationErrors, final String paramName) {
|
||||
|
||||
final DataValidatorBuilder baseDataValidator = new DataValidatorBuilder(dataValidationErrors).resource("loan");
|
||||
baseDataValidator.reset().parameter(paramName).value(recalculationFrequencyDate).notNull()
|
||||
.validateDateForEqual(expectedDisbursementDate);
|
||||
}
|
||||
|
||||
private void validatePartialPeriodSupport(final Integer interestCalculationPeriodType, final DataValidatorBuilder baseDataValidator,
|
||||
final JsonElement element, final LoanProduct loanProduct) {
|
||||
if (interestCalculationPeriodType != null) {
|
||||
|
||||
+1
@@ -33,5 +33,6 @@ public interface LoanAccrualPlatformService {
|
||||
void addAccrualAccounting() throws JobExecutionException;
|
||||
|
||||
void addPeriodicAccruals() throws JobExecutionException;
|
||||
void addPeriodicAccrualsForLoansWithIncomePostedAsTransactions() throws JobExecutionException;
|
||||
|
||||
}
|
||||
|
||||
+20
@@ -117,4 +117,24 @@ public class LoanAccrualPlatformServiceImpl implements LoanAccrualPlatformServic
|
||||
return sb.toString();
|
||||
}
|
||||
|
||||
@Override
|
||||
@CronTarget(jobName = JobName.ADD_PERIODIC_ACCRUAL_ENTRIES_FOR_LOANS_WITH_INCOME_POSTED_AS_TRANSACTIONS)
|
||||
public void addPeriodicAccrualsForLoansWithIncomePostedAsTransactions() throws JobExecutionException {
|
||||
Collection<Long> loanIds = this.loanReadPlatformService.retrieveLoanIdsWithPendingIncomePostingTransactions();
|
||||
if(loanIds != null && loanIds.size() > 0){
|
||||
StringBuilder sb = new StringBuilder();
|
||||
for (Long loanId : loanIds) {
|
||||
try {
|
||||
this.loanAccrualWritePlatformService.addIncomeAndAccrualTransactions(loanId);
|
||||
} catch (Exception e) {
|
||||
Throwable realCause = e;
|
||||
if (e.getCause() != null) {
|
||||
realCause = e.getCause();
|
||||
}
|
||||
sb.append("failed to add income and accrual transaction for loan " + loanId + " with message " + realCause.getMessage());
|
||||
}
|
||||
}
|
||||
if (sb.length() > 0) { throw new JobExecutionException(sb.toString()); }
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
+1
@@ -29,4 +29,5 @@ public interface LoanAccrualWritePlatformService {
|
||||
|
||||
void addPeriodicAccruals(LocalDate tilldate, Long loanId, Collection<LoanScheduleAccrualData> loanScheduleAccrualDatas) throws Exception;
|
||||
|
||||
void addIncomeAndAccrualTransactions(Long loanId) throws Exception;
|
||||
}
|
||||
|
||||
+40
-1
@@ -32,15 +32,22 @@ import javax.sql.DataSource;
|
||||
import org.apache.fineract.accounting.journalentry.service.JournalEntryWritePlatformService;
|
||||
import org.apache.fineract.infrastructure.core.service.DateUtils;
|
||||
import org.apache.fineract.infrastructure.core.service.RoutingDataSource;
|
||||
import org.apache.fineract.organisation.monetary.domain.ApplicationCurrency;
|
||||
import org.apache.fineract.organisation.monetary.domain.ApplicationCurrencyRepositoryWrapper;
|
||||
import org.apache.fineract.organisation.monetary.domain.MonetaryCurrency;
|
||||
import org.apache.fineract.organisation.monetary.domain.MoneyHelper;
|
||||
import org.apache.fineract.portfolio.loanaccount.data.LoanChargeData;
|
||||
import org.apache.fineract.portfolio.loanaccount.data.LoanInstallmentChargeData;
|
||||
import org.apache.fineract.portfolio.loanaccount.data.LoanScheduleAccrualData;
|
||||
import org.apache.fineract.portfolio.loanaccount.data.LoanTransactionData;
|
||||
import org.apache.fineract.portfolio.loanaccount.data.LoanTransactionEnumData;
|
||||
import org.apache.fineract.portfolio.loanaccount.domain.Loan;
|
||||
import org.apache.fineract.portfolio.loanaccount.domain.LoanRepository;
|
||||
import org.apache.fineract.portfolio.loanaccount.domain.LoanTransactionType;
|
||||
import org.apache.fineract.portfolio.loanaccount.exception.LoanNotFoundException;
|
||||
import org.apache.fineract.portfolio.loanaccount.loanschedule.data.LoanSchedulePeriodData;
|
||||
import org.apache.fineract.portfolio.loanproduct.service.LoanEnumerations;
|
||||
import org.apache.fineract.useradministration.domain.AppUserRepositoryWrapper;
|
||||
import org.joda.time.Days;
|
||||
import org.joda.time.LocalDate;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
@@ -56,16 +63,23 @@ public class LoanAccrualWritePlatformServiceImpl implements LoanAccrualWritePlat
|
||||
private final JdbcTemplate jdbcTemplate;
|
||||
private final DataSource dataSource;
|
||||
private final JournalEntryWritePlatformService journalEntryWritePlatformService;
|
||||
private final AppUserRepositoryWrapper userRepository;
|
||||
private final LoanRepository loanRepository;
|
||||
private final ApplicationCurrencyRepositoryWrapper applicationCurrencyRepository;
|
||||
|
||||
@Autowired
|
||||
public LoanAccrualWritePlatformServiceImpl(final RoutingDataSource dataSource, final LoanReadPlatformService loanReadPlatformService,
|
||||
final JournalEntryWritePlatformService journalEntryWritePlatformService,
|
||||
final LoanChargeReadPlatformService loanChargeReadPlatformService) {
|
||||
final LoanChargeReadPlatformService loanChargeReadPlatformService, final AppUserRepositoryWrapper userRepository,
|
||||
final LoanRepository loanRepository, final ApplicationCurrencyRepositoryWrapper applicationCurrencyRepository) {
|
||||
this.loanReadPlatformService = loanReadPlatformService;
|
||||
this.dataSource = dataSource;
|
||||
this.jdbcTemplate = new JdbcTemplate(this.dataSource);
|
||||
this.journalEntryWritePlatformService = journalEntryWritePlatformService;
|
||||
this.loanChargeReadPlatformService = loanChargeReadPlatformService;
|
||||
this.userRepository = userRepository;
|
||||
this.loanRepository = loanRepository;
|
||||
this.applicationCurrencyRepository = applicationCurrencyRepository;
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -469,4 +483,29 @@ public class LoanAccrualWritePlatformServiceImpl implements LoanAccrualWritePlat
|
||||
accrualData.updateAccruableIncome(interestIncome);
|
||||
}
|
||||
|
||||
@Override
|
||||
@Transactional
|
||||
public void addIncomeAndAccrualTransactions(Long loanId) throws Exception {
|
||||
if (loanId != null) {
|
||||
Loan loan = this.loanRepository.findOne(loanId);
|
||||
if (loan == null) { throw new LoanNotFoundException(loanId); }
|
||||
final List<Long> existingTransactionIds = new ArrayList<>();
|
||||
final List<Long> existingReversedTransactionIds = new ArrayList<>();
|
||||
existingTransactionIds.addAll(loan.findExistingTransactionIds());
|
||||
existingReversedTransactionIds.addAll(loan.findExistingReversedTransactionIds());
|
||||
loan.processIncomeTransactions(this.userRepository.fetchSystemUser());
|
||||
this.loanRepository.saveAndFlush(loan);
|
||||
postJournalEntries(loan, existingTransactionIds, existingReversedTransactionIds);
|
||||
}
|
||||
}
|
||||
|
||||
private void postJournalEntries(final Loan loan, final List<Long> existingTransactionIds,
|
||||
final List<Long> existingReversedTransactionIds) {
|
||||
final MonetaryCurrency currency = loan.getCurrency();
|
||||
final ApplicationCurrency applicationCurrency = this.applicationCurrencyRepository.findOneWithNotFoundDetection(currency);
|
||||
boolean isAccountTransfer = false;
|
||||
final Map<String, Object> accountingBridgeData = loan.deriveAccountingBridgeData(applicationCurrency.toData(),
|
||||
existingTransactionIds, existingReversedTransactionIds, isAccountTransfer);
|
||||
this.journalEntryWritePlatformService.createJournalEntriesForLoan(accountingBridgeData);
|
||||
}
|
||||
}
|
||||
|
||||
+118
-95
@@ -55,6 +55,7 @@ import org.apache.fineract.portfolio.calendar.domain.CalendarInstanceRepository;
|
||||
import org.apache.fineract.portfolio.calendar.domain.CalendarRepository;
|
||||
import org.apache.fineract.portfolio.calendar.domain.CalendarType;
|
||||
import org.apache.fineract.portfolio.calendar.exception.CalendarNotFoundException;
|
||||
import org.apache.fineract.portfolio.calendar.service.CalendarReadPlatformService;
|
||||
import org.apache.fineract.portfolio.charge.domain.Charge;
|
||||
import org.apache.fineract.portfolio.client.domain.AccountNumberGenerator;
|
||||
import org.apache.fineract.portfolio.client.domain.Client;
|
||||
@@ -64,6 +65,7 @@ import org.apache.fineract.portfolio.collateral.domain.LoanCollateral;
|
||||
import org.apache.fineract.portfolio.collateral.service.CollateralAssembler;
|
||||
import org.apache.fineract.portfolio.common.BusinessEventNotificationConstants.BUSINESS_ENTITY;
|
||||
import org.apache.fineract.portfolio.common.BusinessEventNotificationConstants.BUSINESS_EVENTS;
|
||||
import org.apache.fineract.portfolio.common.domain.PeriodFrequencyType;
|
||||
import org.apache.fineract.portfolio.common.service.BusinessEventNotifierService;
|
||||
import org.apache.fineract.portfolio.fund.domain.Fund;
|
||||
import org.apache.fineract.portfolio.group.domain.Group;
|
||||
@@ -88,6 +90,7 @@ import org.apache.fineract.portfolio.loanaccount.exception.LoanApplicationNotInS
|
||||
import org.apache.fineract.portfolio.loanaccount.exception.LoanApplicationNotInSubmittedAndPendingApprovalStateCannotBeModified;
|
||||
import org.apache.fineract.portfolio.loanaccount.exception.LoanNotFoundException;
|
||||
import org.apache.fineract.portfolio.loanaccount.loanschedule.domain.AprCalculator;
|
||||
import org.apache.fineract.portfolio.loanaccount.loanschedule.domain.LoanApplicationTerms;
|
||||
import org.apache.fineract.portfolio.loanaccount.loanschedule.domain.LoanScheduleModel;
|
||||
import org.apache.fineract.portfolio.loanaccount.loanschedule.service.LoanScheduleAssembler;
|
||||
import org.apache.fineract.portfolio.loanaccount.loanschedule.service.LoanScheduleCalculationPlatformService;
|
||||
@@ -108,7 +111,6 @@ import org.apache.fineract.portfolio.savings.domain.SavingsAccount;
|
||||
import org.apache.fineract.portfolio.savings.domain.SavingsAccountAssembler;
|
||||
import org.apache.fineract.useradministration.domain.AppUser;
|
||||
import org.joda.time.LocalDate;
|
||||
import org.joda.time.LocalTime;
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
@@ -153,6 +155,7 @@ public class LoanApplicationWritePlatformServiceJpaRepositoryImpl implements Loa
|
||||
private final ConfigurationDomainService configurationDomainService;
|
||||
private final LoanScheduleAssembler loanScheduleAssembler;
|
||||
private final LoanUtilService loanUtilService;
|
||||
private final CalendarReadPlatformService calendarReadPlatformService;
|
||||
|
||||
@Autowired
|
||||
public LoanApplicationWritePlatformServiceJpaRepositoryImpl(final PlatformSecurityContext context, final FromJsonHelper fromJsonHelper,
|
||||
@@ -171,7 +174,8 @@ public class LoanApplicationWritePlatformServiceJpaRepositoryImpl implements Loa
|
||||
final LoanReadPlatformService loanReadPlatformService,
|
||||
final AccountNumberFormatRepositoryWrapper accountNumberFormatRepository,
|
||||
final BusinessEventNotifierService businessEventNotifierService, final ConfigurationDomainService configurationDomainService,
|
||||
final LoanScheduleAssembler loanScheduleAssembler, final LoanUtilService loanUtilService) {
|
||||
final LoanScheduleAssembler loanScheduleAssembler, final LoanUtilService loanUtilService,
|
||||
final CalendarReadPlatformService calendarReadPlatformService) {
|
||||
this.context = context;
|
||||
this.fromJsonHelper = fromJsonHelper;
|
||||
this.loanApplicationTransitionApiJsonValidator = loanApplicationTransitionApiJsonValidator;
|
||||
@@ -201,6 +205,7 @@ public class LoanApplicationWritePlatformServiceJpaRepositoryImpl implements Loa
|
||||
this.configurationDomainService = configurationDomainService;
|
||||
this.loanScheduleAssembler = loanScheduleAssembler;
|
||||
this.loanUtilService = loanUtilService;
|
||||
this.calendarReadPlatformService = calendarReadPlatformService;
|
||||
}
|
||||
|
||||
private LoanLifecycleStateMachine defaultLoanLifecycleStateMachine() {
|
||||
@@ -288,6 +293,26 @@ public class LoanApplicationWritePlatformServiceJpaRepositoryImpl implements Loa
|
||||
final CalendarInstance calendarInstance = new CalendarInstance(calendar, newLoanApplication.getId(),
|
||||
CalendarEntityType.LOANS.getValue());
|
||||
this.calendarInstanceRepository.save(calendarInstance);
|
||||
} else {
|
||||
final LoanApplicationTerms loanApplicationTerms = this.loanScheduleAssembler.assembleLoanTerms(command.parsedJson());
|
||||
final Integer repaymentFrequencyNthDayType = command.integerValueOfParameterNamed("repaymentFrequencyNthDayType");
|
||||
if (loanApplicationTerms.getRepaymentPeriodFrequencyType() == PeriodFrequencyType.MONTHS
|
||||
&& repaymentFrequencyNthDayType != null) {
|
||||
final String title = "loan_schedule_" + newLoanApplication.getId();
|
||||
LocalDate calendarStartDate = loanApplicationTerms.getRepaymentsStartingFromLocalDate();
|
||||
if (calendarStartDate == null) calendarStartDate = loanApplicationTerms.getExpectedDisbursementDate();
|
||||
final CalendarFrequencyType calendarFrequencyType = CalendarFrequencyType.MONTHLY;
|
||||
final Integer frequency = loanApplicationTerms.getRepaymentEvery();
|
||||
final Integer repeatsOnDay = loanApplicationTerms.getWeekDayType().getValue();
|
||||
final Integer repeatsOnNthDayOfMonth = loanApplicationTerms.getNthDay();
|
||||
final Integer calendarEntityType = CalendarEntityType.LOANS.getValue();
|
||||
final Calendar loanCalendar = Calendar.createRepeatingCalendar(title, calendarStartDate,
|
||||
CalendarType.COLLECTION.getValue(), calendarFrequencyType, frequency, repeatsOnDay, repeatsOnNthDayOfMonth);
|
||||
this.calendarRepository.save(loanCalendar);
|
||||
final CalendarInstance calendarInstance = CalendarInstance.from(loanCalendar, newLoanApplication.getId(),
|
||||
calendarEntityType);
|
||||
this.calendarInstanceRepository.save(calendarInstance);
|
||||
}
|
||||
}
|
||||
|
||||
// Save linked account information
|
||||
@@ -357,43 +382,49 @@ public class LoanApplicationWritePlatformServiceJpaRepositoryImpl implements Loa
|
||||
|
||||
private void createAndPersistCalendarInstanceForInterestRecalculation(final Loan loan) {
|
||||
|
||||
LocalDate calendarStartDate = loan.loanInterestRecalculationDetails().getRestFrequencyLocalDate();
|
||||
if (calendarStartDate == null) {
|
||||
calendarStartDate = loan.getExpectedDisbursedOnLocalDate();
|
||||
}
|
||||
final Integer repeatsOnDay = calendarStartDate.getDayOfWeek();
|
||||
LocalDate calendarStartDate = loan.getExpectedDisbursedOnLocalDate();
|
||||
Integer repeatsOnDay = null;
|
||||
final RecalculationFrequencyType recalculationFrequencyType = loan.loanInterestRecalculationDetails().getRestFrequencyType();
|
||||
Integer recalculationFrequencyNthDay = loan.loanInterestRecalculationDetails().getRestFrequencyOnDay();
|
||||
if (recalculationFrequencyNthDay == null) {
|
||||
recalculationFrequencyNthDay = loan.loanInterestRecalculationDetails().getRestFrequencyNthDay();
|
||||
repeatsOnDay = loan.loanInterestRecalculationDetails().getRestFrequencyWeekday();
|
||||
}
|
||||
|
||||
Integer frequency = loan.loanInterestRecalculationDetails().getRestInterval();
|
||||
CalendarEntityType calendarEntityType = CalendarEntityType.LOAN_RECALCULATION_REST_DETAIL;
|
||||
final String title = "loan_recalculation_detail_" + loan.loanInterestRecalculationDetails().getId();
|
||||
|
||||
createCalendar(loan, calendarStartDate, repeatsOnDay, recalculationFrequencyType, frequency, calendarEntityType, title);
|
||||
createCalendar(loan, calendarStartDate, recalculationFrequencyNthDay, repeatsOnDay, recalculationFrequencyType, frequency,
|
||||
calendarEntityType, title);
|
||||
|
||||
if (loan.loanInterestRecalculationDetails().getInterestRecalculationCompoundingMethod().isCompoundingEnabled()) {
|
||||
LocalDate compoundingStartDate = loan.loanInterestRecalculationDetails().getCompoundingFrequencyLocalDate();
|
||||
if (compoundingStartDate == null) {
|
||||
compoundingStartDate = loan.getExpectedDisbursedOnLocalDate();
|
||||
}
|
||||
final Integer compoundingRepeatsOnDay = compoundingStartDate.getDayOfWeek();
|
||||
LocalDate compoundingStartDate = loan.getExpectedDisbursedOnLocalDate();
|
||||
Integer compoundingRepeatsOnDay = null;
|
||||
final RecalculationFrequencyType recalculationCompoundingFrequencyType = loan.loanInterestRecalculationDetails()
|
||||
.getCompoundingFrequencyType();
|
||||
Integer recalculationCompoundingFrequencyNthDay = loan.loanInterestRecalculationDetails().getCompoundingFrequencyOnDay();
|
||||
if (recalculationCompoundingFrequencyNthDay == null) {
|
||||
recalculationCompoundingFrequencyNthDay = loan.loanInterestRecalculationDetails().getCompoundingFrequencyNthDay();
|
||||
compoundingRepeatsOnDay = loan.loanInterestRecalculationDetails().getCompoundingFrequencyWeekday();
|
||||
}
|
||||
|
||||
Integer compoundingFrequency = loan.loanInterestRecalculationDetails().getCompoundingInterval();
|
||||
CalendarEntityType compoundingCalendarEntityType = CalendarEntityType.LOAN_RECALCULATION_COMPOUNDING_DETAIL;
|
||||
final String compoundingCalendarTitle = "loan_recalculation_detail_compounding_frequency"
|
||||
+ loan.loanInterestRecalculationDetails().getId();
|
||||
|
||||
createCalendar(loan, compoundingStartDate, compoundingRepeatsOnDay, recalculationCompoundingFrequencyType,
|
||||
compoundingFrequency, compoundingCalendarEntityType, compoundingCalendarTitle);
|
||||
createCalendar(loan, compoundingStartDate, recalculationCompoundingFrequencyNthDay, compoundingRepeatsOnDay,
|
||||
recalculationCompoundingFrequencyType, compoundingFrequency, compoundingCalendarEntityType, compoundingCalendarTitle);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
private void createCalendar(final Loan loan, LocalDate calendarStartDate, final Integer repeatsOnDay,
|
||||
final RecalculationFrequencyType recalculationFrequencyType, Integer frequency, CalendarEntityType calendarEntityType,
|
||||
final String title) {
|
||||
private void createCalendar(final Loan loan, LocalDate calendarStartDate, Integer recalculationFrequencyNthDay,
|
||||
final Integer repeatsOnDay, final RecalculationFrequencyType recalculationFrequencyType, Integer frequency,
|
||||
CalendarEntityType calendarEntityType, final String title) {
|
||||
CalendarFrequencyType calendarFrequencyType = CalendarFrequencyType.INVALID;
|
||||
Integer updatedRepeatsOnDay = repeatsOnDay;
|
||||
switch (recalculationFrequencyType) {
|
||||
case DAILY:
|
||||
calendarFrequencyType = CalendarFrequencyType.DAILY;
|
||||
@@ -405,6 +436,9 @@ public class LoanApplicationWritePlatformServiceJpaRepositoryImpl implements Loa
|
||||
frequency = loan.repaymentScheduleDetail().getRepayEvery();
|
||||
calendarFrequencyType = CalendarFrequencyType.from(loan.repaymentScheduleDetail().getRepaymentPeriodFrequencyType());
|
||||
calendarStartDate = loan.getExpectedDisbursedOnLocalDate();
|
||||
if (updatedRepeatsOnDay == null) {
|
||||
updatedRepeatsOnDay = calendarStartDate.getDayOfWeek();
|
||||
}
|
||||
break;
|
||||
case WEEKLY:
|
||||
calendarFrequencyType = CalendarFrequencyType.WEEKLY;
|
||||
@@ -414,71 +448,12 @@ public class LoanApplicationWritePlatformServiceJpaRepositoryImpl implements Loa
|
||||
}
|
||||
|
||||
final Calendar calendar = Calendar.createRepeatingCalendar(title, calendarStartDate, CalendarType.COLLECTION.getValue(),
|
||||
calendarFrequencyType, frequency, repeatsOnDay);
|
||||
calendarFrequencyType, frequency, updatedRepeatsOnDay, recalculationFrequencyNthDay);
|
||||
final CalendarInstance calendarInstance = CalendarInstance.from(calendar, loan.loanInterestRecalculationDetails().getId(),
|
||||
calendarEntityType.getValue());
|
||||
this.calendarInstanceRepository.save(calendarInstance);
|
||||
}
|
||||
|
||||
private void updateRestCalendarDetailsForInterestRecalculation(final CalendarInstance calendarInstance, final Loan loan) {
|
||||
|
||||
Calendar interestRecalculationRecurrings = calendarInstance.getCalendar();
|
||||
LocalDate calendarStartDate = loan.loanInterestRecalculationDetails().getRestFrequencyLocalDate();
|
||||
if (calendarStartDate == null) {
|
||||
calendarStartDate = loan.getExpectedDisbursedOnLocalDate();
|
||||
}
|
||||
final Integer repeatsOnDay = calendarStartDate.getDayOfWeek();
|
||||
final RecalculationFrequencyType recalculationFrequencyType = loan.loanInterestRecalculationDetails().getRestFrequencyType();
|
||||
|
||||
Integer frequency = loan.loanInterestRecalculationDetails().getRestInterval();
|
||||
|
||||
updateCalendar(loan, interestRecalculationRecurrings, calendarStartDate, repeatsOnDay, recalculationFrequencyType, frequency);
|
||||
|
||||
}
|
||||
|
||||
private void updateCompoundingCalendarDetailsForInterestRecalculation(final CalendarInstance calendarInstance, final Loan loan) {
|
||||
|
||||
Calendar interestRecalculationRecurrings = calendarInstance.getCalendar();
|
||||
LocalDate calendarStartDate = loan.loanInterestRecalculationDetails().getCompoundingFrequencyLocalDate();
|
||||
if (calendarStartDate == null) {
|
||||
calendarStartDate = loan.getExpectedDisbursedOnLocalDate();
|
||||
}
|
||||
final Integer repeatsOnDay = calendarStartDate.getDayOfWeek();
|
||||
final RecalculationFrequencyType recalculationFrequencyType = loan.loanInterestRecalculationDetails().getCompoundingFrequencyType();
|
||||
|
||||
Integer frequency = loan.loanInterestRecalculationDetails().getCompoundingInterval();
|
||||
|
||||
updateCalendar(loan, interestRecalculationRecurrings, calendarStartDate, repeatsOnDay, recalculationFrequencyType, frequency);
|
||||
|
||||
}
|
||||
|
||||
private void updateCalendar(final Loan loan, Calendar interestRecalculationRecurrings, LocalDate calendarStartDate,
|
||||
final Integer repeatsOnDay, final RecalculationFrequencyType recalculationFrequencyType, Integer frequency) {
|
||||
CalendarFrequencyType calendarFrequencyType = CalendarFrequencyType.INVALID;
|
||||
switch (recalculationFrequencyType) {
|
||||
case DAILY:
|
||||
calendarFrequencyType = CalendarFrequencyType.DAILY;
|
||||
break;
|
||||
|
||||
case MONTHLY:
|
||||
calendarFrequencyType = CalendarFrequencyType.MONTHLY;
|
||||
break;
|
||||
case SAME_AS_REPAYMENT_PERIOD:
|
||||
calendarStartDate = loan.getExpectedDisbursedOnLocalDate();
|
||||
frequency = loan.repaymentScheduleDetail().getRepayEvery();
|
||||
calendarFrequencyType = CalendarFrequencyType.from(loan.repaymentScheduleDetail().getRepaymentPeriodFrequencyType());
|
||||
break;
|
||||
case WEEKLY:
|
||||
calendarFrequencyType = CalendarFrequencyType.WEEKLY;
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
||||
interestRecalculationRecurrings.updateRepeatingCalendar(calendarStartDate, calendarFrequencyType, frequency, repeatsOnDay);
|
||||
this.calendarRepository.save(interestRecalculationRecurrings);
|
||||
}
|
||||
|
||||
@Transactional
|
||||
@Override
|
||||
public CommandProcessingResult modifyApplication(final Long loanId, final JsonCommand command) {
|
||||
@@ -551,7 +526,7 @@ public class LoanApplicationWritePlatformServiceJpaRepositoryImpl implements Loa
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
final Set<LoanCollateral> possiblyModifedLoanCollateralItems = this.loanCollateralAssembler
|
||||
.fromParsedJson(command.parsedJson());
|
||||
|
||||
@@ -700,6 +675,11 @@ public class LoanApplicationWritePlatformServiceJpaRepositoryImpl implements Loa
|
||||
// loan
|
||||
if (ciList != null && !ciList.isEmpty()) {
|
||||
final CalendarInstance calendarInstance = ciList.get(0);
|
||||
final boolean isCalendarAssociatedWithEntity = this.calendarReadPlatformService.isCalendarAssociatedWithEntity(calendarInstance
|
||||
.getEntityId(), calendarInstance.getCalendar().getId(), CalendarEntityType.LOANS.getValue().longValue());
|
||||
if (isCalendarAssociatedWithEntity) {
|
||||
this.calendarRepository.delete(calendarInstance.getCalendar());
|
||||
}
|
||||
if (calendarInstance.getCalendar().getId() != calendar.getId()) {
|
||||
calendarInstance.updateCalendar(calendar);
|
||||
this.calendarInstanceRepository.saveAndFlush(calendarInstance);
|
||||
@@ -711,9 +691,65 @@ public class LoanApplicationWritePlatformServiceJpaRepositoryImpl implements Loa
|
||||
this.calendarInstanceRepository.save(calendarInstance);
|
||||
}
|
||||
|
||||
} else if (ciList != null && !ciList.isEmpty()) {
|
||||
final CalendarInstance calendarInstance = ciList.get(0);
|
||||
this.calendarInstanceRepository.delete(calendarInstance);
|
||||
} else {
|
||||
if (ciList != null && !ciList.isEmpty()) {
|
||||
final CalendarInstance existingCalendarInstance = ciList.get(0);
|
||||
final boolean isCalendarAssociatedWithEntity = this.calendarReadPlatformService.isCalendarAssociatedWithEntity(
|
||||
existingCalendarInstance.getEntityId(), existingCalendarInstance.getCalendar().getId(),
|
||||
CalendarEntityType.GROUPS.getValue().longValue());
|
||||
if (isCalendarAssociatedWithEntity) {
|
||||
this.calendarInstanceRepository.delete(existingCalendarInstance);
|
||||
}
|
||||
}
|
||||
if (changes.containsKey("repaymentFrequencyNthDayType") || changes.containsKey("repaymentFrequencyDayOfWeekType")) {
|
||||
if (changes.get("repaymentFrequencyNthDayType") == null) {
|
||||
if (ciList != null && !ciList.isEmpty()) {
|
||||
final CalendarInstance calendarInstance = ciList.get(0);
|
||||
final boolean isCalendarAssociatedWithEntity = this.calendarReadPlatformService.isCalendarAssociatedWithEntity(
|
||||
calendarInstance.getEntityId(), calendarInstance.getCalendar().getId(), CalendarEntityType.LOANS.getValue().longValue());
|
||||
if (isCalendarAssociatedWithEntity) {
|
||||
this.calendarInstanceRepository.delete(calendarInstance);
|
||||
this.calendarRepository.delete(calendarInstance.getCalendar());
|
||||
}
|
||||
}
|
||||
} else {
|
||||
Integer repaymentFrequencyTypeInt = command.integerValueOfParameterNamed("repaymentFrequencyType");
|
||||
if (repaymentFrequencyTypeInt != null) {
|
||||
if (PeriodFrequencyType.fromInt(repaymentFrequencyTypeInt) == PeriodFrequencyType.MONTHS) {
|
||||
final String title = "loan_schedule_" + existingLoanApplication.getId();
|
||||
final Integer typeId = CalendarType.COLLECTION.getValue();
|
||||
final CalendarFrequencyType repaymentFrequencyType = CalendarFrequencyType.MONTHLY;
|
||||
final Integer interval = command.integerValueOfParameterNamed("repaymentEvery");
|
||||
LocalDate startDate = command.localDateValueOfParameterNamed("repaymentsStartingFromDate");
|
||||
if (startDate == null) startDate = command.localDateValueOfParameterNamed("expectedDisbursementDate");
|
||||
final Calendar newCalendar = Calendar.createRepeatingCalendar(title, startDate, typeId,
|
||||
repaymentFrequencyType, interval, (Integer) changes.get("repaymentFrequencyDayOfWeekType"),
|
||||
(Integer) changes.get("repaymentFrequencyNthDayType"));
|
||||
if (ciList != null && !ciList.isEmpty()) {
|
||||
final CalendarInstance calendarInstance = ciList.get(0);
|
||||
final boolean isCalendarAssociatedWithEntity = this.calendarReadPlatformService.isCalendarAssociatedWithEntity(
|
||||
calendarInstance.getEntityId(), calendarInstance.getCalendar().getId(), CalendarEntityType.LOANS.getValue().longValue());
|
||||
if (isCalendarAssociatedWithEntity) {
|
||||
final Calendar existingCalendar = calendarInstance.getCalendar();
|
||||
if (existingCalendar != null) {
|
||||
String existingRecurrence = existingCalendar.getRecurrence();
|
||||
if (!existingRecurrence.equals(newCalendar.getRecurrence())) {
|
||||
existingCalendar.setRecurrence(newCalendar.getRecurrence());
|
||||
this.calendarRepository.save(existingCalendar);
|
||||
}
|
||||
}
|
||||
}
|
||||
} else {
|
||||
this.calendarRepository.save(newCalendar);
|
||||
final Integer calendarEntityType = CalendarEntityType.LOANS.getValue();
|
||||
final CalendarInstance calendarInstance = new CalendarInstance(newCalendar,
|
||||
existingLoanApplication.getId(), calendarEntityType);
|
||||
this.calendarInstanceRepository.save(calendarInstance);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Save linked account information
|
||||
@@ -776,20 +812,7 @@ public class LoanApplicationWritePlatformServiceJpaRepositoryImpl implements Loa
|
||||
this.fromApiJsonDeserializer.validateLoanForInterestRecalculation(existingLoanApplication);
|
||||
if (changes.containsKey(LoanProductConstants.isInterestRecalculationEnabledParameterName)) {
|
||||
createAndPersistCalendarInstanceForInterestRecalculation(existingLoanApplication);
|
||||
} else {
|
||||
if (changes.containsKey(LoanProductConstants.recalculationRestFrequencyDateParamName)) {
|
||||
|
||||
CalendarInstance calendarInstance = this.calendarInstanceRepository.findByEntityIdAndEntityTypeIdAndCalendarTypeId(
|
||||
existingLoanApplication.loanInterestRecalculationDetailId(),
|
||||
CalendarEntityType.LOAN_RECALCULATION_REST_DETAIL.getValue(), CalendarType.COLLECTION.getValue());
|
||||
updateRestCalendarDetailsForInterestRecalculation(calendarInstance, existingLoanApplication);
|
||||
}
|
||||
if (changes.containsKey(LoanProductConstants.recalculationCompoundingFrequencyDateParamName)) {
|
||||
CalendarInstance calendarInstance = this.calendarInstanceRepository.findByEntityIdAndEntityTypeIdAndCalendarTypeId(
|
||||
existingLoanApplication.loanInterestRecalculationDetailId(),
|
||||
CalendarEntityType.LOAN_RECALCULATION_COMPOUNDING_DETAIL.getValue(), CalendarType.COLLECTION.getValue());
|
||||
updateCompoundingCalendarDetailsForInterestRecalculation(calendarInstance, existingLoanApplication);
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
+2
-7
@@ -70,7 +70,6 @@ import org.apache.fineract.portfolio.loanaccount.exception.MultiDisbursementData
|
||||
import org.apache.fineract.portfolio.loanaccount.loanschedule.domain.LoanApplicationTerms;
|
||||
import org.apache.fineract.portfolio.loanaccount.loanschedule.domain.LoanScheduleModel;
|
||||
import org.apache.fineract.portfolio.loanaccount.loanschedule.service.LoanScheduleAssembler;
|
||||
import org.apache.fineract.portfolio.loanproduct.LoanProductConstants;
|
||||
import org.apache.fineract.portfolio.loanproduct.domain.LoanProduct;
|
||||
import org.apache.fineract.portfolio.loanproduct.domain.LoanProductRelatedDetail;
|
||||
import org.apache.fineract.portfolio.loanproduct.domain.LoanProductRepository;
|
||||
@@ -82,6 +81,7 @@ import org.apache.fineract.useradministration.domain.AppUser;
|
||||
import org.joda.time.LocalDate;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.stereotype.Service;
|
||||
|
||||
import com.google.gson.JsonElement;
|
||||
|
||||
@Service
|
||||
@@ -282,10 +282,6 @@ public class LoanAssembler {
|
||||
}
|
||||
}
|
||||
|
||||
final LocalDate recalculationRestFrequencyDate = this.fromApiJsonHelper.extractLocalDateNamed(
|
||||
LoanProductConstants.recalculationRestFrequencyDateParamName, element);
|
||||
final LocalDate recalculationCompoundingFrequencyDate = this.fromApiJsonHelper.extractLocalDateNamed(
|
||||
LoanProductConstants.recalculationCompoundingFrequencyDateParamName, element);
|
||||
|
||||
final LoanApplicationTerms loanApplicationTerms = this.loanScheduleAssembler.assembleLoanTerms(element);
|
||||
final boolean isHolidayEnabled = this.configurationDomainService.isRescheduleRepaymentsOnHolidaysEnabled();
|
||||
@@ -297,8 +293,7 @@ public class LoanAssembler {
|
||||
final LoanScheduleModel loanScheduleModel = this.loanScheduleAssembler.assembleLoanScheduleFrom(loanApplicationTerms,
|
||||
isHolidayEnabled, holidays, workingDays, element,disbursementDetails);
|
||||
loanApplication.loanApplicationSubmittal(currentUser, loanScheduleModel, loanApplicationTerms, defaultLoanLifecycleStateMachine(),
|
||||
submittedOnDate, externalId, allowTransactionsOnHoliday, holidays, workingDays, allowTransactionsOnNonWorkingDay,
|
||||
recalculationRestFrequencyDate, recalculationCompoundingFrequencyDate);
|
||||
submittedOnDate, externalId, allowTransactionsOnHoliday, holidays, workingDays, allowTransactionsOnNonWorkingDay);
|
||||
|
||||
return loanApplication;
|
||||
}
|
||||
|
||||
+1
@@ -126,4 +126,5 @@ public interface LoanReadPlatformService {
|
||||
LoanTransactionData retrieveRefundByCashTemplate(Long loanId);
|
||||
|
||||
Collection<InterestRatePeriodData> retrieveLoanInterestRatePeriodData(Long loanId);
|
||||
Collection<Long> retrieveLoanIdsWithPendingIncomePostingTransactions();
|
||||
}
|
||||
+78
-29
@@ -550,7 +550,7 @@ public class LoanReadPlatformServiceImpl implements LoanReadPlatformService {
|
||||
+ " l.principal_amount_proposed as proposedPrincipal, l.principal_amount as principal, l.approved_principal as approvedPrincipal, l.arrearstolerance_amount as inArrearsTolerance, l.number_of_repayments as numberOfRepayments, l.repay_every as repaymentEvery,"
|
||||
+ " l.grace_on_principal_periods as graceOnPrincipalPayment, l.recurring_moratorium_principal_periods as recurringMoratoriumOnPrincipalPeriods, l.grace_on_interest_periods as graceOnInterestPayment, l.grace_interest_free_periods as graceOnInterestCharged,l.grace_on_arrears_ageing as graceOnArrearsAgeing,"
|
||||
+ " l.nominal_interest_rate_per_period as interestRatePerPeriod, l.annual_nominal_interest_rate as annualInterestRate, "
|
||||
+ " l.repayment_period_frequency_enum as repaymentFrequencyType, l.repayment_frequency_nth_day_enum as repaymentFrequencyNthDayType, l.repayment_frequency_day_of_week_enum as repaymentFrequencyDayOfWeekType, l.interest_period_frequency_enum as interestRateFrequencyType, "
|
||||
+ " l.repayment_period_frequency_enum as repaymentFrequencyType, l.interest_period_frequency_enum as interestRateFrequencyType, "
|
||||
+ " l.term_frequency as termFrequency, l.term_period_frequency_enum as termPeriodFrequencyType, "
|
||||
+ " l.amortization_method_enum as amortizationType, l.interest_method_enum as interestType, l.interest_calculated_in_period_enum as interestCalculationPeriodType,"
|
||||
+ " l.allow_partial_period_interest_calcualtion as allowPartialPeriodInterestCalcualtion,"
|
||||
@@ -600,9 +600,15 @@ public class LoanReadPlatformServiceImpl implements LoanReadPlatformService {
|
||||
+ " l.interest_recalculation_enabled as isInterestRecalculationEnabled, "
|
||||
+ " lir.id as lirId, lir.loan_id as loanId, lir.compound_type_enum as compoundType, lir.reschedule_strategy_enum as rescheduleStrategy, "
|
||||
+ " lir.rest_frequency_type_enum as restFrequencyEnum, lir.rest_frequency_interval as restFrequencyInterval, "
|
||||
+ " lir.rest_freqency_date as restFrequencyDate, "
|
||||
+ " lir.rest_frequency_nth_day_enum as restFrequencyNthDayEnum, "
|
||||
+ " lir.rest_frequency_weekday_enum as restFrequencyWeekDayEnum, "
|
||||
+ " lir.rest_frequency_on_day as restFrequencyOnDay, "
|
||||
+ " lir.compounding_frequency_type_enum as compoundingFrequencyEnum, lir.compounding_frequency_interval as compoundingInterval, "
|
||||
+ " lir.compounding_freqency_date as compoundingFrequencyDate, "
|
||||
+ " lir.compounding_frequency_nth_day_enum as compoundingFrequencyNthDayEnum, "
|
||||
+ " lir.compounding_frequency_weekday_enum as compoundingFrequencyWeekDayEnum, "
|
||||
+ " lir.compounding_frequency_on_day as compoundingFrequencyOnDay, "
|
||||
+ " lir.is_compounding_to_be_posted_as_transaction as isCompoundingToBePostedAsTransaction, "
|
||||
+ " lir.allow_compounding_on_eod as allowCompoundingOnEod, "
|
||||
+ " l.is_floating_interest_rate as isFloatingInterestRate, "
|
||||
+ " l.interest_rate_differential as interestRateDifferential, "
|
||||
+ " l.create_standing_instruction_at_disbursement as createStandingInstructionAtDisbursement, "
|
||||
@@ -752,14 +758,6 @@ public class LoanReadPlatformServiceImpl implements LoanReadPlatformService {
|
||||
final int repaymentFrequencyTypeInt = JdbcSupport.getInteger(rs, "repaymentFrequencyType");
|
||||
final EnumOptionData repaymentFrequencyType = LoanEnumerations.repaymentFrequencyType(repaymentFrequencyTypeInt);
|
||||
|
||||
final Integer repaymentFrequencyNthDayTypeInt = JdbcSupport.getInteger(rs, "repaymentFrequencyNthDayType");
|
||||
final EnumOptionData repaymentFrequencyNthDayType = LoanEnumerations
|
||||
.repaymentFrequencyNthDayType(repaymentFrequencyNthDayTypeInt);
|
||||
|
||||
final Integer repaymentFrequencyDayOfWeekTypeInt = JdbcSupport.getInteger(rs, "repaymentFrequencyDayOfWeekType");
|
||||
final EnumOptionData repaymentFrequencyDayOfWeekType = LoanEnumerations
|
||||
.repaymentFrequencyDayOfWeekType(repaymentFrequencyDayOfWeekTypeInt);
|
||||
|
||||
final int interestRateFrequencyTypeInt = JdbcSupport.getInteger(rs, "interestRateFrequencyType");
|
||||
final EnumOptionData interestRateFrequencyType = LoanEnumerations.interestRateFrequencyType(interestRateFrequencyTypeInt);
|
||||
|
||||
@@ -877,7 +875,18 @@ public class LoanReadPlatformServiceImpl implements LoanReadPlatformService {
|
||||
final int restFrequencyEnumValue = JdbcSupport.getInteger(rs, "restFrequencyEnum");
|
||||
final EnumOptionData restFrequencyType = LoanEnumerations.interestRecalculationFrequencyType(restFrequencyEnumValue);
|
||||
final int restFrequencyInterval = JdbcSupport.getInteger(rs, "restFrequencyInterval");
|
||||
final LocalDate restFrequencyDate = JdbcSupport.getLocalDate(rs, "restFrequencyDate");
|
||||
final Integer restFrequencyNthDayEnumValue = JdbcSupport.getInteger(rs, "restFrequencyNthDayEnum");
|
||||
EnumOptionData restFrequencyNthDayEnum = null;
|
||||
if (restFrequencyNthDayEnumValue != null) {
|
||||
restFrequencyNthDayEnum = LoanEnumerations.interestRecalculationCompoundingNthDayType(restFrequencyNthDayEnumValue);
|
||||
}
|
||||
final Integer restFrequencyWeekDayEnumValue = JdbcSupport.getInteger(rs, "restFrequencyWeekDayEnum");
|
||||
EnumOptionData restFrequencyWeekDayEnum = null;
|
||||
if (restFrequencyWeekDayEnumValue != null) {
|
||||
restFrequencyWeekDayEnum = LoanEnumerations
|
||||
.interestRecalculationCompoundingDayOfWeekType(restFrequencyWeekDayEnumValue);
|
||||
}
|
||||
final Integer restFrequencyOnDay = JdbcSupport.getInteger(rs, "restFrequencyOnDay");
|
||||
final CalendarData compoundingCalendarData = null;
|
||||
final Integer compoundingFrequencyEnumValue = JdbcSupport.getInteger(rs, "compoundingFrequencyEnum");
|
||||
EnumOptionData compoundingFrequencyType = null;
|
||||
@@ -885,25 +894,41 @@ public class LoanReadPlatformServiceImpl implements LoanReadPlatformService {
|
||||
compoundingFrequencyType = LoanEnumerations.interestRecalculationFrequencyType(compoundingFrequencyEnumValue);
|
||||
}
|
||||
final Integer compoundingInterval = JdbcSupport.getInteger(rs, "compoundingInterval");
|
||||
final LocalDate compoundingFrequencyDate = JdbcSupport.getLocalDate(rs, "compoundingFrequencyDate");
|
||||
final Integer compoundingFrequencyNthDayEnumValue = JdbcSupport.getInteger(rs, "compoundingFrequencyNthDayEnum");
|
||||
EnumOptionData compoundingFrequencyNthDayEnum = null;
|
||||
if (compoundingFrequencyNthDayEnumValue != null) {
|
||||
compoundingFrequencyNthDayEnum = LoanEnumerations
|
||||
.interestRecalculationCompoundingNthDayType(compoundingFrequencyNthDayEnumValue);
|
||||
}
|
||||
final Integer compoundingFrequencyWeekDayEnumValue = JdbcSupport.getInteger(rs, "compoundingFrequencyWeekDayEnum");
|
||||
EnumOptionData compoundingFrequencyWeekDayEnum = null;
|
||||
if (compoundingFrequencyWeekDayEnumValue != null) {
|
||||
compoundingFrequencyWeekDayEnum = LoanEnumerations
|
||||
.interestRecalculationCompoundingDayOfWeekType(compoundingFrequencyWeekDayEnumValue);
|
||||
}
|
||||
final Integer compoundingFrequencyOnDay = JdbcSupport.getInteger(rs, "compoundingFrequencyOnDay");
|
||||
|
||||
final Boolean isCompoundingToBePostedAsTransaction = rs.getBoolean("isCompoundingToBePostedAsTransaction");
|
||||
final Boolean allowCompoundingOnEod = rs.getBoolean("allowCompoundingOnEod");
|
||||
interestRecalculationData = new LoanInterestRecalculationData(lprId, productId, interestRecalculationCompoundingType,
|
||||
rescheduleStrategyType, calendarData, restFrequencyType, restFrequencyInterval, restFrequencyDate,
|
||||
compoundingCalendarData, compoundingFrequencyType, compoundingInterval, compoundingFrequencyDate);
|
||||
rescheduleStrategyType, calendarData, restFrequencyType, restFrequencyInterval, restFrequencyNthDayEnum,
|
||||
restFrequencyWeekDayEnum, restFrequencyOnDay, compoundingCalendarData, compoundingFrequencyType,
|
||||
compoundingInterval, compoundingFrequencyNthDayEnum, compoundingFrequencyWeekDayEnum, compoundingFrequencyOnDay,
|
||||
isCompoundingToBePostedAsTransaction, allowCompoundingOnEod);
|
||||
}
|
||||
|
||||
return LoanAccountData.basicLoanDetails(id, accountNo, status, externalId, clientId, clientAccountNo, clientName,
|
||||
clientOfficeId, groupData, loanType, loanProductId, loanProductName, loanProductDescription,
|
||||
isLoanProductLinkedToFloatingRate, fundId, fundName, loanPurposeId, loanPurposeName, loanOfficerId, loanOfficerName,
|
||||
currencyData, proposedPrincipal, principal, approvedPrincipal, totalOverpaid, inArrearsTolerance, termFrequency,
|
||||
termPeriodFrequencyType, numberOfRepayments, repaymentEvery, repaymentFrequencyType, repaymentFrequencyNthDayType,
|
||||
repaymentFrequencyDayOfWeekType, transactionStrategyId, transactionStrategyName, amortizationType,
|
||||
interestRatePerPeriod, interestRateFrequencyType, annualInterestRate, interestType, isFloatingInterestRate,
|
||||
interestRateDifferential, interestCalculationPeriodType, allowPartialPeriodInterestCalcualtion,
|
||||
expectedFirstRepaymentOnDate, graceOnPrincipalPayment, recurringMoratoriumOnPrincipalPeriods, graceOnInterestPayment, graceOnInterestCharged,
|
||||
interestChargedFromDate, timeline, loanSummary, feeChargesDueAtDisbursementCharged, syncDisbursementWithMeeting,
|
||||
loanCounter, loanProductCounter, multiDisburseLoan, canDefineInstallmentAmount, fixedEmiAmount, outstandingLoanBalance,
|
||||
inArrears, graceOnArrearsAgeing, isNPA, daysInMonthType, daysInYearType, isInterestRecalculationEnabled,
|
||||
termPeriodFrequencyType, numberOfRepayments, repaymentEvery, repaymentFrequencyType, null, null, transactionStrategyId,
|
||||
transactionStrategyName, amortizationType, interestRatePerPeriod, interestRateFrequencyType, annualInterestRate,
|
||||
interestType, isFloatingInterestRate, interestRateDifferential, interestCalculationPeriodType,
|
||||
allowPartialPeriodInterestCalcualtion, expectedFirstRepaymentOnDate, graceOnPrincipalPayment,
|
||||
recurringMoratoriumOnPrincipalPeriods, graceOnInterestPayment, graceOnInterestCharged, interestChargedFromDate,
|
||||
timeline, loanSummary, feeChargesDueAtDisbursementCharged, syncDisbursementWithMeeting, loanCounter,
|
||||
loanProductCounter, multiDisburseLoan, canDefineInstallmentAmount, fixedEmiAmount, outstandingLoanBalance, inArrears,
|
||||
graceOnArrearsAgeing, isNPA, daysInMonthType, daysInYearType, isInterestRecalculationEnabled,
|
||||
interestRecalculationData, createStandingInstructionAtDisbursement, isvariableInstallmentsAllowed, minimumGap,
|
||||
maximumGap);
|
||||
}
|
||||
@@ -1569,10 +1594,11 @@ public class LoanReadPlatformServiceImpl implements LoanReadPlatformService {
|
||||
sqlBuilder
|
||||
.append("select ")
|
||||
.append(mapper.schema())
|
||||
.append(" where ((ls.fee_charges_amount <> if(ls.accrual_fee_charges_derived is null,0, ls.accrual_fee_charges_derived))")
|
||||
.append(" where (recaldet.is_compounding_to_be_posted_as_transaction is null or recaldet.is_compounding_to_be_posted_as_transaction = 0) ")
|
||||
.append(" and (((ls.fee_charges_amount <> if(ls.accrual_fee_charges_derived is null,0, ls.accrual_fee_charges_derived))")
|
||||
.append(" or ( ls.penalty_charges_amount <> if(ls.accrual_penalty_charges_derived is null,0,ls.accrual_penalty_charges_derived))")
|
||||
.append(" or ( ls.interest_amount <> if(ls.accrual_interest_derived is null,0,ls.accrual_interest_derived)))")
|
||||
.append(" and loan.loan_status_id=:active and mpl.accounting_type=:type and loan.is_npa=0 and ls.duedate <= CURDATE() ");
|
||||
.append(" and loan.loan_status_id=:active and mpl.accounting_type=:type and loan.is_npa=0 and ls.duedate <= CURDATE()) ");
|
||||
if(organisationStartDate != null){
|
||||
sqlBuilder.append(" and ls.duedate > :organisationstartdate ");
|
||||
}
|
||||
@@ -1594,11 +1620,12 @@ public class LoanReadPlatformServiceImpl implements LoanReadPlatformService {
|
||||
sqlBuilder
|
||||
.append("select ")
|
||||
.append(mapper.schema())
|
||||
.append(" where ((ls.fee_charges_amount <> if(ls.accrual_fee_charges_derived is null,0, ls.accrual_fee_charges_derived))")
|
||||
.append(" where (recaldet.is_compounding_to_be_posted_as_transaction is null or recaldet.is_compounding_to_be_posted_as_transaction = 0) ")
|
||||
.append(" and (((ls.fee_charges_amount <> if(ls.accrual_fee_charges_derived is null,0, ls.accrual_fee_charges_derived))")
|
||||
.append(" or (ls.penalty_charges_amount <> if(ls.accrual_penalty_charges_derived is null,0,ls.accrual_penalty_charges_derived))")
|
||||
.append(" or (ls.interest_amount <> if(ls.accrual_interest_derived is null,0,ls.accrual_interest_derived)))")
|
||||
.append(" and loan.loan_status_id=:active and mpl.accounting_type=:type and (loan.closedon_date <= :tilldate or loan.closedon_date is null)")
|
||||
.append(" and loan.is_npa=0 and (ls.duedate <= :tilldate or (ls.duedate > :tilldate and ls.fromdate < :tilldate)) ");
|
||||
.append(" and loan.is_npa=0 and (ls.duedate <= :tilldate or (ls.duedate > :tilldate and ls.fromdate < :tilldate))) ");
|
||||
if(organisationStartDate != null){
|
||||
sqlBuilder.append(" and ls.duedate > :organisationstartdate ");
|
||||
}
|
||||
@@ -1632,7 +1659,8 @@ public class LoanReadPlatformServiceImpl implements LoanReadPlatformService {
|
||||
.append(" from m_loan_repayment_schedule ls ").append(" left join m_loan loan on loan.id=ls.loan_id ")
|
||||
.append(" left join m_product_loan mpl on mpl.id = loan.product_id")
|
||||
.append(" left join m_client mc on mc.id = loan.client_id ").append(" left join m_group mg on mg.id = loan.group_id")
|
||||
.append(" left join m_currency curr on curr.code = loan.currency_code");
|
||||
.append(" left join m_currency curr on curr.code = loan.currency_code")
|
||||
.append(" left join m_loan_recalculation_details as recaldet on loan.id = recaldet.loan_id ");
|
||||
return sqlBuilder.toString();
|
||||
}
|
||||
|
||||
@@ -1693,7 +1721,8 @@ public class LoanReadPlatformServiceImpl implements LoanReadPlatformService {
|
||||
.append(" from m_loan_repayment_schedule ls ").append(" left join m_loan loan on loan.id=ls.loan_id ")
|
||||
.append(" left join m_product_loan mpl on mpl.id = loan.product_id")
|
||||
.append(" left join m_client mc on mc.id = loan.client_id ").append(" left join m_group mg on mg.id = loan.group_id")
|
||||
.append(" left join m_currency curr on curr.code = loan.currency_code");
|
||||
.append(" left join m_currency curr on curr.code = loan.currency_code")
|
||||
.append(" left join m_loan_recalculation_details as recaldet on loan.id = recaldet.loan_id ");
|
||||
return sqlBuilder.toString();
|
||||
}
|
||||
|
||||
@@ -2034,4 +2063,24 @@ public class LoanReadPlatformServiceImpl implements LoanReadPlatformService {
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public Collection<Long> retrieveLoanIdsWithPendingIncomePostingTransactions() {
|
||||
StringBuilder sqlBuilder = new StringBuilder()
|
||||
.append(" select distinct loan.id ")
|
||||
.append(" from m_loan as loan ")
|
||||
.append(" inner join m_loan_recalculation_details as recdet on (recdet.loan_id = loan.id and recdet.is_compounding_to_be_posted_as_transaction is not null and recdet.is_compounding_to_be_posted_as_transaction = 1) ")
|
||||
.append(" inner join m_loan_repayment_schedule as repsch on repsch.loan_id = loan.id ")
|
||||
.append(" inner join m_loan_interest_recalculation_additional_details as adddet on adddet.loan_repayment_schedule_id = repsch.id ")
|
||||
.append(" left join m_loan_transaction as trans on (trans.is_reversed <> 1 and trans.transaction_type_enum = 19 and trans.loan_id = loan.id and trans.transaction_date = adddet.effective_date) ")
|
||||
.append(" where loan.loan_status_id = 300 ")
|
||||
.append(" and adddet.effective_date is not null ")
|
||||
.append(" and trans.transaction_date is null ")
|
||||
.append(" and adddet.effective_date < ? ");
|
||||
try {
|
||||
String currentdate = formatter.print(DateUtils.getLocalDateOfTenant());
|
||||
return this.jdbcTemplate.queryForList(sqlBuilder.toString(), Long.class, new Object[] { currentdate });
|
||||
} catch (final EmptyResultDataAccessException e) {
|
||||
return null;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
+29
-25
@@ -90,14 +90,14 @@ import org.apache.fineract.portfolio.charge.domain.ChargeRepositoryWrapper;
|
||||
import org.apache.fineract.portfolio.charge.exception.ChargeCannotBeUpdatedException;
|
||||
import org.apache.fineract.portfolio.charge.exception.LoanChargeCannotBeAddedException;
|
||||
import org.apache.fineract.portfolio.charge.exception.LoanChargeCannotBeDeletedException;
|
||||
import org.apache.fineract.portfolio.charge.exception.LoanChargeCannotBePayedException;
|
||||
import org.apache.fineract.portfolio.charge.exception.LoanChargeCannotBeUpdatedException;
|
||||
import org.apache.fineract.portfolio.charge.exception.LoanChargeCannotBeWaivedException;
|
||||
import org.apache.fineract.portfolio.charge.exception.LoanChargeNotFoundException;
|
||||
import org.apache.fineract.portfolio.charge.exception.LoanChargeCannotBeDeletedException.LOAN_CHARGE_CANNOT_BE_DELETED_REASON;
|
||||
import org.apache.fineract.portfolio.charge.exception.LoanChargeCannotBePayedException;
|
||||
import org.apache.fineract.portfolio.charge.exception.LoanChargeCannotBePayedException.LOAN_CHARGE_CANNOT_BE_PAYED_REASON;
|
||||
import org.apache.fineract.portfolio.charge.exception.LoanChargeCannotBeUpdatedException;
|
||||
import org.apache.fineract.portfolio.charge.exception.LoanChargeCannotBeUpdatedException.LOAN_CHARGE_CANNOT_BE_UPDATED_REASON;
|
||||
import org.apache.fineract.portfolio.charge.exception.LoanChargeCannotBeWaivedException;
|
||||
import org.apache.fineract.portfolio.charge.exception.LoanChargeCannotBeWaivedException.LOAN_CHARGE_CANNOT_BE_WAIVED_REASON;
|
||||
import org.apache.fineract.portfolio.charge.exception.LoanChargeNotFoundException;
|
||||
import org.apache.fineract.portfolio.client.domain.Client;
|
||||
import org.apache.fineract.portfolio.client.exception.ClientNotActiveException;
|
||||
import org.apache.fineract.portfolio.collectionsheet.command.CollectionSheetBulkDisbursalCommand;
|
||||
@@ -126,6 +126,7 @@ import org.apache.fineract.portfolio.loanaccount.domain.LoanChargeRepository;
|
||||
import org.apache.fineract.portfolio.loanaccount.domain.LoanDisbursementDetails;
|
||||
import org.apache.fineract.portfolio.loanaccount.domain.LoanEvent;
|
||||
import org.apache.fineract.portfolio.loanaccount.domain.LoanInstallmentCharge;
|
||||
import org.apache.fineract.portfolio.loanaccount.domain.LoanInterestRecalcualtionAdditionalDetails;
|
||||
import org.apache.fineract.portfolio.loanaccount.domain.LoanLifecycleStateMachine;
|
||||
import org.apache.fineract.portfolio.loanaccount.domain.LoanOverdueInstallmentCharge;
|
||||
import org.apache.fineract.portfolio.loanaccount.domain.LoanRepaymentScheduleInstallment;
|
||||
@@ -304,7 +305,7 @@ public class LoanWritePlatformServiceJpaRepositoryImpl implements LoanWritePlatf
|
||||
|
||||
final Loan loan = this.loanAssembler.assembleFrom(loanId);
|
||||
checkClientOrGroupActive(loan);
|
||||
|
||||
|
||||
final LocalDate nextPossibleRepaymentDate = loan.getNextPossibleRepaymentDateForRescheduling();
|
||||
final Date rescheduledRepaymentDate = command.DateValueOfParameterNamed("adjustRepaymentDate");
|
||||
|
||||
@@ -336,8 +337,9 @@ public class LoanWritePlatformServiceJpaRepositoryImpl implements LoanWritePlatf
|
||||
final Map<String, Object> changes = new LinkedHashMap<>();
|
||||
|
||||
final PaymentDetail paymentDetail = this.paymentDetailWritePlatformService.createAndPersistPaymentDetail(command, changes);
|
||||
|
||||
final Boolean isPaymnetypeApplicableforDisbursementCharge=configurationDomainService.isPaymnetypeApplicableforDisbursementCharge();
|
||||
|
||||
final Boolean isPaymnetypeApplicableforDisbursementCharge = configurationDomainService
|
||||
.isPaymnetypeApplicableforDisbursementCharge();
|
||||
|
||||
updateLoanCounters(loan, actualDisbursementDate);
|
||||
Money amountBeforeAdjust = loan.getPrincpal();
|
||||
@@ -366,10 +368,10 @@ public class LoanWritePlatformServiceJpaRepositoryImpl implements LoanWritePlatf
|
||||
this.loanScheduleHistoryWritePlatformService.createAndSaveLoanScheduleArchive(loan.fetchRepaymentScheduleInstallments(),
|
||||
loan, null);
|
||||
}
|
||||
if(isPaymnetypeApplicableforDisbursementCharge){
|
||||
changedTransactionDetail = loan.disburse(currentUser, command, changes, scheduleGeneratorDTO,paymentDetail);
|
||||
}else{
|
||||
changedTransactionDetail = loan.disburse(currentUser, command, changes, scheduleGeneratorDTO,null);
|
||||
if (isPaymnetypeApplicableforDisbursementCharge) {
|
||||
changedTransactionDetail = loan.disburse(currentUser, command, changes, scheduleGeneratorDTO, paymentDetail);
|
||||
} else {
|
||||
changedTransactionDetail = loan.disburse(currentUser, command, changes, scheduleGeneratorDTO, null);
|
||||
}
|
||||
}
|
||||
if (!changes.isEmpty()) {
|
||||
@@ -549,7 +551,7 @@ public class LoanWritePlatformServiceJpaRepositoryImpl implements LoanWritePlatf
|
||||
final SingleDisbursalCommand[] disbursalCommand = bulkDisbursalCommand.getDisburseTransactions();
|
||||
final Map<String, Object> changes = new LinkedHashMap<>();
|
||||
if (disbursalCommand == null) { return changes; }
|
||||
|
||||
|
||||
final LocalDate nextPossibleRepaymentDate = null;
|
||||
final Date rescheduledRepaymentDate = null;
|
||||
|
||||
@@ -597,15 +599,16 @@ public class LoanWritePlatformServiceJpaRepositoryImpl implements LoanWritePlatf
|
||||
}
|
||||
LocalDate recalculateFrom = null;
|
||||
final ScheduleGeneratorDTO scheduleGeneratorDTO = this.loanUtilService.buildScheduleGeneratorDTO(loan, recalculateFrom);
|
||||
regenerateScheduleOnDisbursement(command, loan, recalculateSchedule, scheduleGeneratorDTO, nextPossibleRepaymentDate, rescheduledRepaymentDate);
|
||||
regenerateScheduleOnDisbursement(command, loan, recalculateSchedule, scheduleGeneratorDTO, nextPossibleRepaymentDate,
|
||||
rescheduledRepaymentDate);
|
||||
if (loan.repaymentScheduleDetail().isInterestRecalculationEnabled()) {
|
||||
this.loanScheduleHistoryWritePlatformService.createAndSaveLoanScheduleArchive(
|
||||
loan.fetchRepaymentScheduleInstallments(), loan, null);
|
||||
}
|
||||
if(configurationDomainService.isPaymnetypeApplicableforDisbursementCharge()){
|
||||
changedTransactionDetail = loan.disburse(currentUser, command, changes, scheduleGeneratorDTO,paymentDetail);
|
||||
}else{
|
||||
changedTransactionDetail = loan.disburse(currentUser, command, changes, scheduleGeneratorDTO,null);
|
||||
if (configurationDomainService.isPaymnetypeApplicableforDisbursementCharge()) {
|
||||
changedTransactionDetail = loan.disburse(currentUser, command, changes, scheduleGeneratorDTO, paymentDetail);
|
||||
} else {
|
||||
changedTransactionDetail = loan.disburse(currentUser, command, changes, scheduleGeneratorDTO, null);
|
||||
}
|
||||
}
|
||||
if (!changes.isEmpty()) {
|
||||
@@ -1990,8 +1993,7 @@ public class LoanWritePlatformServiceJpaRepositoryImpl implements LoanWritePlatf
|
||||
// loop through each loan to reschedule the repayment dates
|
||||
for (final Loan loan : loans) {
|
||||
if (loan != null) {
|
||||
|
||||
if(loan.getExpectedFirstRepaymentOnDate() != null && loan.getExpectedFirstRepaymentOnDate().equals(presentMeetingDate)){
|
||||
if (loan.getExpectedFirstRepaymentOnDate() != null && loan.getExpectedFirstRepaymentOnDate().equals(presentMeetingDate)) {
|
||||
final String defaultUserMessage = "Meeting calendar date update is not supported since its a first repayment date";
|
||||
throw new CalendarParameterUpdateNotSupportedException("meeting.for.first.repayment.date", defaultUserMessage,
|
||||
loan.getExpectedFirstRepaymentOnDate(), presentMeetingDate);
|
||||
@@ -2337,9 +2339,10 @@ public class LoanWritePlatformServiceJpaRepositoryImpl implements LoanWritePlatf
|
||||
BigDecimal interest = BigDecimal.ZERO;
|
||||
BigDecimal feeCharges = BigDecimal.ZERO;
|
||||
BigDecimal penaltyCharges = BigDecimal.ONE;
|
||||
final List<LoanInterestRecalcualtionAdditionalDetails> compoundingDetails = null;
|
||||
LoanRepaymentScheduleInstallment newEntry = new LoanRepaymentScheduleInstallment(loan, installments.size() + 1,
|
||||
lastInstallment.getDueDate(), lastChargeDate, principal, interest, feeCharges, penaltyCharges,
|
||||
recalculatedInterestComponent);
|
||||
recalculatedInterestComponent, compoundingDetails);
|
||||
installments.add(newEntry);
|
||||
}
|
||||
}
|
||||
@@ -2548,8 +2551,8 @@ public class LoanWritePlatformServiceJpaRepositoryImpl implements LoanWritePlatf
|
||||
|
||||
if (command.entityId() != null) {
|
||||
|
||||
changedTransactionDetail = loan.updateDisbursementDateAndAmountForTranche(loanDisbursementDetails, command,
|
||||
changes, scheduleGeneratorDTO, currentUser);
|
||||
changedTransactionDetail = loan.updateDisbursementDateAndAmountForTranche(loanDisbursementDetails, command, changes,
|
||||
scheduleGeneratorDTO, currentUser);
|
||||
} else {
|
||||
// BigDecimal setAmount = loan.getApprovedPrincipal();
|
||||
Collection<LoanDisbursementDetails> loanDisburseDetails = loan.getDisbursementDetails();
|
||||
@@ -2735,8 +2738,8 @@ public class LoanWritePlatformServiceJpaRepositoryImpl implements LoanWritePlatf
|
||||
AppUser currentUser = getAppUserIfPresent();
|
||||
final LocalDate actualDisbursementDate = command.localDateValueOfParameterNamed("actualDisbursementDate");
|
||||
BigDecimal emiAmount = command.bigDecimalValueOfParameterNamed(LoanApiConstants.emiAmountParameterName);
|
||||
loan.regenerateScheduleOnDisbursement(scheduleGeneratorDTO, recalculateSchedule, actualDisbursementDate, emiAmount, currentUser,
|
||||
nextPossibleRepaymentDate, rescheduledRepaymentDate);
|
||||
loan.regenerateScheduleOnDisbursement(scheduleGeneratorDTO, recalculateSchedule, actualDisbursementDate, emiAmount, currentUser,
|
||||
nextPossibleRepaymentDate, rescheduledRepaymentDate);
|
||||
}
|
||||
|
||||
private List<LoanRepaymentScheduleInstallment> retrieveRepaymentScheduleFromModel(LoanScheduleModel model) {
|
||||
@@ -2747,7 +2750,8 @@ public class LoanWritePlatformServiceJpaRepositoryImpl implements LoanWritePlatf
|
||||
scheduledLoanInstallment.periodNumber(), scheduledLoanInstallment.periodFromDate(),
|
||||
scheduledLoanInstallment.periodDueDate(), scheduledLoanInstallment.principalDue(),
|
||||
scheduledLoanInstallment.interestDue(), scheduledLoanInstallment.feeChargesDue(),
|
||||
scheduledLoanInstallment.penaltyChargesDue(), scheduledLoanInstallment.isRecalculatedInterestComponent());
|
||||
scheduledLoanInstallment.penaltyChargesDue(), scheduledLoanInstallment.isRecalculatedInterestComponent(),
|
||||
scheduledLoanInstallment.getLoanCompoundingDetails());
|
||||
installments.add(installment);
|
||||
}
|
||||
}
|
||||
|
||||
+8
-2
@@ -86,12 +86,17 @@ public interface LoanProductConstants {
|
||||
public static final String rescheduleStrategyMethodParameterName = "rescheduleStrategyMethod";
|
||||
public static final String recalculationRestFrequencyTypeParameterName = "recalculationRestFrequencyType";
|
||||
public static final String recalculationRestFrequencyIntervalParameterName = "recalculationRestFrequencyInterval";
|
||||
public static final String recalculationRestFrequencyDateParamName = "recalculationRestFrequencyDate";
|
||||
public static final String recalculationRestFrequencyWeekdayParamName = "recalculationRestFrequencyDayOfWeekType";
|
||||
public static final String recalculationRestFrequencyNthDayParamName = "recalculationRestFrequencyNthDayType";
|
||||
public static final String recalculationRestFrequencyOnDayParamName = "recalculationRestFrequencyOnDayType";
|
||||
public static final String isArrearsBasedOnOriginalScheduleParamName = "isArrearsBasedOnOriginalSchedule";
|
||||
public static final String preClosureInterestCalculationStrategyParamName = "preClosureInterestCalculationStrategy";
|
||||
public static final String recalculationCompoundingFrequencyTypeParameterName = "recalculationCompoundingFrequencyType";
|
||||
public static final String recalculationCompoundingFrequencyIntervalParameterName = "recalculationCompoundingFrequencyInterval";
|
||||
public static final String recalculationCompoundingFrequencyDateParamName = "recalculationCompoundingFrequencyDate";
|
||||
public static final String recalculationCompoundingFrequencyWeekdayParamName = "recalculationCompoundingFrequencyDayOfWeekType";
|
||||
public static final String recalculationCompoundingFrequencyNthDayParamName = "recalculationCompoundingFrequencyNthDayType";
|
||||
public static final String recalculationCompoundingFrequencyOnDayParamName = "recalculationCompoundingFrequencyOnDayType";
|
||||
public static final String isCompoundingToBePostedAsTransactionParamName = "isCompoundingToBePostedAsTransaction";
|
||||
|
||||
// Guarantee related
|
||||
public static final String holdGuaranteeFundsParamName = "holdGuaranteeFunds";
|
||||
@@ -115,6 +120,7 @@ public interface LoanProductConstants {
|
||||
public static final String inArrearsToleranceParamName = "inArrearsTolerance";
|
||||
public static final String repaymentEveryParamName = "repaymentEvery";
|
||||
public static final String graceOnPrincipalAndInterestPaymentParamName = "graceOnPrincipalAndInterestPayment";
|
||||
public static final String allowCompoundingOnEodParamName = "allowCompoundingOnEod";
|
||||
|
||||
//Variable Installments Settings
|
||||
public static final String allowVariableInstallmentsParamName = "allowVariableInstallments" ;
|
||||
|
||||
+6
-1
@@ -298,6 +298,10 @@ public class LoanProductsApiResource {
|
||||
final List<EnumOptionData> rescheduleStrategyTypeOptions = dropdownReadPlatformService.retrieveRescheduleStrategyTypeOptions();
|
||||
final List<EnumOptionData> interestRecalculationFrequencyTypeOptions = dropdownReadPlatformService
|
||||
.retrieveInterestRecalculationFrequencyTypeOptions();
|
||||
final List<EnumOptionData> interestRecalculationNthDayTypeOptions = dropdownReadPlatformService
|
||||
.retrieveInterestRecalculationNthDayTypeOptions();
|
||||
final List<EnumOptionData> interestRecalculationDayOfWeekTypeOptions = dropdownReadPlatformService
|
||||
.retrieveInterestRecalculationDayOfWeekTypeOptions();
|
||||
final List<EnumOptionData> preCloseInterestCalculationStrategyOptions = dropdownReadPlatformService
|
||||
.retrivePreCloseInterestCalculationStrategyOptions();
|
||||
final List<FloatingRateData> floatingRateOptions = this.floatingRateReadPlatformService.retrieveLookupActive();
|
||||
@@ -307,7 +311,8 @@ public class LoanProductsApiResource {
|
||||
interestRateFrequencyTypeOptions, fundOptions, transactionProcessingStrategyOptions, accountOptions,
|
||||
accountingRuleTypeOptions, loanCycleValueConditionTypeOptions, daysInMonthTypeOptions, daysInYearTypeOptions,
|
||||
interestRecalculationCompoundingTypeOptions, rescheduleStrategyTypeOptions, interestRecalculationFrequencyTypeOptions,
|
||||
preCloseInterestCalculationStrategyOptions, floatingRateOptions);
|
||||
preCloseInterestCalculationStrategyOptions, floatingRateOptions, interestRecalculationNthDayTypeOptions,
|
||||
interestRecalculationDayOfWeekTypeOptions);
|
||||
}
|
||||
|
||||
}
|
||||
+46
-7
@@ -159,6 +159,10 @@ public class LoanProductData {
|
||||
@SuppressWarnings("unused")
|
||||
private final List<EnumOptionData> interestRecalculationCompoundingTypeOptions;
|
||||
@SuppressWarnings("unused")
|
||||
private final List<EnumOptionData> interestRecalculationNthDayTypeOptions;
|
||||
@SuppressWarnings("unused")
|
||||
private final List<EnumOptionData> interestRecalculationDayOfWeekTypeOptions;
|
||||
@SuppressWarnings("unused")
|
||||
private final List<EnumOptionData> rescheduleStrategyTypeOptions;
|
||||
@SuppressWarnings("unused")
|
||||
private final List<EnumOptionData> preClosureInterestCalculationStrategyOptions;
|
||||
@@ -585,6 +589,8 @@ public class LoanProductData {
|
||||
this.interestRecalculationCompoundingTypeOptions = null;
|
||||
this.rescheduleStrategyTypeOptions = null;
|
||||
this.interestRecalculationFrequencyTypeOptions = null;
|
||||
this.interestRecalculationNthDayTypeOptions = null;
|
||||
this.interestRecalculationDayOfWeekTypeOptions = null;
|
||||
|
||||
this.canDefineInstallmentAmount = canDefineInstallmentAmount;
|
||||
this.installmentAmountInMultiplesOf = installmentAmountInMultiplesOf;
|
||||
@@ -602,7 +608,9 @@ public class LoanProductData {
|
||||
final List<EnumOptionData> valueConditionTypeOptions, final List<EnumOptionData> daysInMonthTypeOptions,
|
||||
final List<EnumOptionData> daysInYearTypeOptions, final List<EnumOptionData> interestRecalculationCompoundingTypeOptions,
|
||||
final List<EnumOptionData> rescheduleStrategyTypeOptions, final List<EnumOptionData> interestRecalculationFrequencyTypeOptions,
|
||||
final List<EnumOptionData> preCloseInterestCalculationStrategyOptions, final List<FloatingRateData> floatingRateOptions) {
|
||||
final List<EnumOptionData> preCloseInterestCalculationStrategyOptions, final List<FloatingRateData> floatingRateOptions,
|
||||
final List<EnumOptionData> interestRecalculationNthDayTypeOptions,
|
||||
final List<EnumOptionData> interestRecalculationDayOfWeekTypeOptions) {
|
||||
this.id = productData.id;
|
||||
this.name = productData.name;
|
||||
this.shortName = productData.shortName;
|
||||
@@ -686,6 +694,8 @@ public class LoanProductData {
|
||||
this.amortizationTypeOptions = amortizationTypeOptions;
|
||||
this.interestTypeOptions = interestTypeOptions;
|
||||
this.interestCalculationPeriodTypeOptions = interestCalculationPeriodTypeOptions;
|
||||
this.interestRecalculationNthDayTypeOptions = interestRecalculationNthDayTypeOptions;
|
||||
this.interestRecalculationDayOfWeekTypeOptions = interestRecalculationDayOfWeekTypeOptions;
|
||||
this.repaymentFrequencyTypeOptions = repaymentFrequencyTypeOptions;
|
||||
this.interestRateFrequencyTypeOptions = interestRateFrequencyTypeOptions;
|
||||
|
||||
@@ -946,8 +956,11 @@ public class LoanProductData {
|
||||
final CalendarData compoundingCalendarData = null;
|
||||
return new LoanInterestRecalculationData(id, loanId, getInterestRecalculationCompoundingType(), getRescheduleStrategyType(),
|
||||
calendarData, getRecalculationRestFrequencyType(), getRecalculationRestFrequencyInterval(),
|
||||
getRecalculationRestFrequencyDate(), compoundingCalendarData, getRecalculationCompoundingFrequencyType(),
|
||||
getRecalculationCompoundingFrequencyInterval(), getRecalculationCompoundingFrequencyDate());
|
||||
getInterestRecalculationRestNthDayType(), getInterestRecalculationRestWeekDayType(),
|
||||
getInterestRecalculationRestOnDayType(), compoundingCalendarData, getRecalculationCompoundingFrequencyType(),
|
||||
getRecalculationCompoundingFrequencyInterval(), getInterestRecalculationCompoundingNthDayType(),
|
||||
getInterestRecalculationCompoundingWeekDayType(), getInterestRecalculationCompoundingOnDayType(),
|
||||
isCompoundingToBePostedAsTransaction(), allowCompoundingOnEod());
|
||||
}
|
||||
|
||||
private EnumOptionData getRescheduleStrategyType() {
|
||||
@@ -960,8 +973,16 @@ public class LoanProductData {
|
||||
return null;
|
||||
}
|
||||
|
||||
private LocalDate getRecalculationRestFrequencyDate() {
|
||||
if (isInterestRecalculationEnabled()) { return this.interestRecalculationData.getRecalculationRestFrequencyDate(); }
|
||||
private EnumOptionData getInterestRecalculationCompoundingNthDayType() {
|
||||
if (isInterestRecalculationEnabled()) { return this.interestRecalculationData.getRecalculationCompoundingFrequencyNthDay(); }
|
||||
return null;
|
||||
}
|
||||
private EnumOptionData getInterestRecalculationCompoundingWeekDayType() {
|
||||
if (isInterestRecalculationEnabled()) { return this.interestRecalculationData.getRecalculationCompoundingFrequencyWeekday(); }
|
||||
return null;
|
||||
}
|
||||
private Integer getInterestRecalculationCompoundingOnDayType() {
|
||||
if (isInterestRecalculationEnabled()) { return this.interestRecalculationData.getRecalculationCompoundingFrequencyOnDay(); }
|
||||
return null;
|
||||
}
|
||||
|
||||
@@ -975,8 +996,18 @@ public class LoanProductData {
|
||||
return null;
|
||||
}
|
||||
|
||||
private LocalDate getRecalculationCompoundingFrequencyDate() {
|
||||
if (isInterestRecalculationEnabled()) { return this.interestRecalculationData.getRecalculationCompoundingFrequencyDate(); }
|
||||
private EnumOptionData getInterestRecalculationRestNthDayType() {
|
||||
if (isInterestRecalculationEnabled()) { return this.interestRecalculationData.getRecalculationRestFrequencyNthDay(); }
|
||||
return null;
|
||||
}
|
||||
|
||||
private EnumOptionData getInterestRecalculationRestWeekDayType() {
|
||||
if (isInterestRecalculationEnabled()) { return this.interestRecalculationData.getRecalculationRestFrequencyWeekday(); }
|
||||
return null;
|
||||
}
|
||||
|
||||
private Integer getInterestRecalculationRestOnDayType() {
|
||||
if (isInterestRecalculationEnabled()) { return this.interestRecalculationData.getRecalculationRestFrequencyOnDay(); }
|
||||
return null;
|
||||
}
|
||||
|
||||
@@ -989,6 +1020,14 @@ public class LoanProductData {
|
||||
if (isInterestRecalculationEnabled()) { return this.interestRecalculationData.getRecalculationCompoundingFrequencyInterval(); }
|
||||
return null;
|
||||
}
|
||||
public Boolean isCompoundingToBePostedAsTransaction() {
|
||||
if (isInterestRecalculationEnabled()) { return this.interestRecalculationData.isCompoundingToBePostedAsTransaction(); }
|
||||
return null;
|
||||
}
|
||||
public Boolean allowCompoundingOnEod() {
|
||||
if (isInterestRecalculationEnabled()) { return this.interestRecalculationData.allowCompoundingOnEod(); }
|
||||
return null;
|
||||
}
|
||||
|
||||
public boolean canDefineInstallmentAmount() {
|
||||
return this.canDefineInstallmentAmount;
|
||||
|
||||
+58
-18
@@ -26,7 +26,6 @@ import org.apache.fineract.infrastructure.core.data.EnumOptionData;
|
||||
import org.apache.fineract.portfolio.loanproduct.domain.InterestRecalculationCompoundingMethod;
|
||||
import org.apache.fineract.portfolio.loanproduct.domain.LoanPreClosureInterestCalculationStrategy;
|
||||
import org.apache.fineract.portfolio.loanproduct.domain.LoanRescheduleStrategyMethod;
|
||||
import org.joda.time.LocalDate;
|
||||
|
||||
public class LoanProductInterestRecalculationData {
|
||||
|
||||
@@ -38,33 +37,48 @@ public class LoanProductInterestRecalculationData {
|
||||
private final EnumOptionData rescheduleStrategyType;
|
||||
private final EnumOptionData recalculationRestFrequencyType;
|
||||
private final Integer recalculationRestFrequencyInterval;
|
||||
private final LocalDate recalculationRestFrequencyDate;
|
||||
private final EnumOptionData recalculationRestFrequencyNthDay;
|
||||
private final EnumOptionData recalculationRestFrequencyWeekday;
|
||||
private final Integer recalculationRestFrequencyOnDay;
|
||||
private final EnumOptionData recalculationCompoundingFrequencyType;
|
||||
private final Integer recalculationCompoundingFrequencyInterval;
|
||||
private final LocalDate recalculationCompoundingFrequencyDate;
|
||||
private final EnumOptionData recalculationCompoundingFrequencyNthDay;
|
||||
private final EnumOptionData recalculationCompoundingFrequencyWeekday;
|
||||
private final Integer recalculationCompoundingFrequencyOnDay;
|
||||
@SuppressWarnings("unused")
|
||||
private final boolean isArrearsBasedOnOriginalSchedule;
|
||||
private final boolean isCompoundingToBePostedAsTransaction;
|
||||
@SuppressWarnings("unused")
|
||||
private final EnumOptionData preClosureInterestCalculationStrategy;
|
||||
private final boolean allowCompoundingOnEod;
|
||||
|
||||
public LoanProductInterestRecalculationData(final Long id, final Long productId,
|
||||
final EnumOptionData interestRecalculationCompoundingType, final EnumOptionData rescheduleStrategyType,
|
||||
final EnumOptionData recalculationRestFrequencyType, final Integer recalculationRestFrequencyInterval,
|
||||
final LocalDate recalculationRestFrequencyDate, final EnumOptionData recalculationCompoundingFrequencyType,
|
||||
final Integer recalculationCompoundingFrequencyInterval, final LocalDate recalculationCompoundingFrequencyDate,
|
||||
final boolean isArrearsBasedOnOriginalSchedule, final EnumOptionData preCloseInterestCalculationStrategy) {
|
||||
final EnumOptionData recalculationRestFrequencyNthDay, final EnumOptionData recalculationRestFrequencyWeekday,
|
||||
final Integer recalculationRestFrequencyOnDay, final EnumOptionData recalculationCompoundingFrequencyType,
|
||||
final Integer recalculationCompoundingFrequencyInterval, final EnumOptionData recalculationCompoundingFrequencyNthDay,
|
||||
final EnumOptionData recalculationCompoundingFrequencyWeekday, final Integer recalculationCompoundingFrequencyOnDay,
|
||||
final boolean isArrearsBasedOnOriginalSchedule, boolean isCompoundingToBePostedAsTransaction,
|
||||
final EnumOptionData preCloseInterestCalculationStrategy, final boolean allowCompoundingOnEod) {
|
||||
this.id = id;
|
||||
this.productId = productId;
|
||||
this.interestRecalculationCompoundingType = interestRecalculationCompoundingType;
|
||||
this.rescheduleStrategyType = rescheduleStrategyType;
|
||||
this.recalculationRestFrequencyType = recalculationRestFrequencyType;
|
||||
this.recalculationRestFrequencyInterval = recalculationRestFrequencyInterval;
|
||||
this.recalculationRestFrequencyDate = recalculationRestFrequencyDate;
|
||||
this.recalculationRestFrequencyNthDay = recalculationRestFrequencyNthDay;
|
||||
this.recalculationRestFrequencyOnDay = recalculationRestFrequencyOnDay;
|
||||
this.recalculationRestFrequencyWeekday = recalculationRestFrequencyWeekday;
|
||||
this.recalculationCompoundingFrequencyType = recalculationCompoundingFrequencyType;
|
||||
this.recalculationCompoundingFrequencyInterval = recalculationCompoundingFrequencyInterval;
|
||||
this.recalculationCompoundingFrequencyDate = recalculationCompoundingFrequencyDate;
|
||||
this.recalculationCompoundingFrequencyNthDay = recalculationCompoundingFrequencyNthDay;
|
||||
this.recalculationCompoundingFrequencyOnDay = recalculationCompoundingFrequencyOnDay;
|
||||
this.recalculationCompoundingFrequencyWeekday = recalculationCompoundingFrequencyWeekday;
|
||||
this.isArrearsBasedOnOriginalSchedule = isArrearsBasedOnOriginalSchedule;
|
||||
this.preClosureInterestCalculationStrategy = preCloseInterestCalculationStrategy;
|
||||
this.isCompoundingToBePostedAsTransaction = isCompoundingToBePostedAsTransaction;
|
||||
this.allowCompoundingOnEod = allowCompoundingOnEod;
|
||||
}
|
||||
|
||||
public static LoanProductInterestRecalculationData sensibleDefaultsForNewLoanProductCreation() {
|
||||
@@ -74,16 +88,24 @@ public class LoanProductInterestRecalculationData {
|
||||
final EnumOptionData rescheduleStrategyType = rescheduleStrategyType(LoanRescheduleStrategyMethod.REDUCE_EMI_AMOUNT);
|
||||
final EnumOptionData recalculationRestFrequencyType = null;
|
||||
final Integer recalculationRestFrequencyInterval = null;
|
||||
final LocalDate recalculationRestFrequencyDate = null;
|
||||
final EnumOptionData recalculationRestFrequencyNthDay = null;
|
||||
final EnumOptionData recalculationRestFrequencyWeekday = null;
|
||||
final Integer recalculationRestFrequencyOnDay = null;
|
||||
final EnumOptionData recalculationCompoundingFrequencyType = null;
|
||||
final Integer recalculationCompoundingFrequencyInterval = null;
|
||||
final LocalDate recalculationCompoundingFrequencyDate = null;
|
||||
final EnumOptionData recalculationCompoundingFrequencyNthDay = null;
|
||||
final EnumOptionData recalculationCompoundingFrequencyWeekday = null;
|
||||
final Integer recalculationCompoundingFrequencyOnDay = null;
|
||||
final boolean isArrearsBasedOnOriginalSchedule = false;
|
||||
final boolean isCompoundingToBePostedAsTransaction = false;
|
||||
final EnumOptionData preCloseInterestCalculationStrategy = preCloseInterestCalculationStrategy(LoanPreClosureInterestCalculationStrategy.TILL_PRE_CLOSURE_DATE);
|
||||
final boolean allowCompoundingOnEod = false;
|
||||
return new LoanProductInterestRecalculationData(id, productId, interestRecalculationCompoundingType, rescheduleStrategyType,
|
||||
recalculationRestFrequencyType, recalculationRestFrequencyInterval, recalculationRestFrequencyDate,
|
||||
recalculationCompoundingFrequencyType, recalculationCompoundingFrequencyInterval, recalculationCompoundingFrequencyDate,
|
||||
isArrearsBasedOnOriginalSchedule, preCloseInterestCalculationStrategy);
|
||||
recalculationRestFrequencyType, recalculationRestFrequencyInterval, recalculationRestFrequencyNthDay,
|
||||
recalculationRestFrequencyWeekday, recalculationRestFrequencyOnDay, recalculationCompoundingFrequencyType,
|
||||
recalculationCompoundingFrequencyInterval, recalculationCompoundingFrequencyNthDay,
|
||||
recalculationCompoundingFrequencyWeekday, recalculationCompoundingFrequencyOnDay, isArrearsBasedOnOriginalSchedule,
|
||||
isCompoundingToBePostedAsTransaction, preCloseInterestCalculationStrategy, allowCompoundingOnEod);
|
||||
}
|
||||
|
||||
public EnumOptionData getInterestRecalculationCompoundingType() {
|
||||
@@ -92,10 +114,7 @@ public class LoanProductInterestRecalculationData {
|
||||
|
||||
public EnumOptionData getRescheduleStrategyType() {
|
||||
return this.rescheduleStrategyType;
|
||||
}
|
||||
|
||||
public LocalDate getRecalculationRestFrequencyDate() {
|
||||
return this.recalculationRestFrequencyDate;
|
||||
}
|
||||
|
||||
public EnumOptionData getRecalculationRestFrequencyType() {
|
||||
@@ -114,8 +133,29 @@ public class LoanProductInterestRecalculationData {
|
||||
return this.recalculationCompoundingFrequencyInterval;
|
||||
}
|
||||
|
||||
public LocalDate getRecalculationCompoundingFrequencyDate() {
|
||||
return this.recalculationCompoundingFrequencyDate;
|
||||
public EnumOptionData getRecalculationRestFrequencyNthDay() {
|
||||
return this.recalculationRestFrequencyNthDay;
|
||||
}
|
||||
public EnumOptionData getRecalculationRestFrequencyWeekday() {
|
||||
return this.recalculationRestFrequencyWeekday;
|
||||
}
|
||||
public Integer getRecalculationRestFrequencyOnDay() {
|
||||
return this.recalculationRestFrequencyOnDay;
|
||||
}
|
||||
public EnumOptionData getRecalculationCompoundingFrequencyNthDay() {
|
||||
return this.recalculationCompoundingFrequencyNthDay;
|
||||
}
|
||||
|
||||
public EnumOptionData getRecalculationCompoundingFrequencyWeekday() {
|
||||
return this.recalculationCompoundingFrequencyWeekday;
|
||||
}
|
||||
public Integer getRecalculationCompoundingFrequencyOnDay() {
|
||||
return this.recalculationCompoundingFrequencyOnDay;
|
||||
}
|
||||
public boolean isCompoundingToBePostedAsTransaction() {
|
||||
return this.isCompoundingToBePostedAsTransaction;
|
||||
}
|
||||
public boolean allowCompoundingOnEod() {
|
||||
return this.allowCompoundingOnEod;
|
||||
}
|
||||
}
|
||||
|
||||
+200
-72
@@ -18,7 +18,6 @@
|
||||
*/
|
||||
package org.apache.fineract.portfolio.loanproduct.domain;
|
||||
|
||||
import java.util.Date;
|
||||
import java.util.Map;
|
||||
|
||||
import javax.persistence.Column;
|
||||
@@ -26,12 +25,9 @@ import javax.persistence.Entity;
|
||||
import javax.persistence.JoinColumn;
|
||||
import javax.persistence.OneToOne;
|
||||
import javax.persistence.Table;
|
||||
import javax.persistence.Temporal;
|
||||
import javax.persistence.TemporalType;
|
||||
|
||||
import org.apache.fineract.infrastructure.core.api.JsonCommand;
|
||||
import org.apache.fineract.portfolio.loanproduct.LoanProductConstants;
|
||||
import org.joda.time.LocalDate;
|
||||
import org.springframework.data.jpa.domain.AbstractPersistable;
|
||||
|
||||
/**
|
||||
@@ -66,9 +62,14 @@ public class LoanProductInterestRecalculationDetails extends AbstractPersistable
|
||||
@Column(name = "rest_frequency_interval", nullable = false)
|
||||
private Integer restInterval;
|
||||
|
||||
@Temporal(TemporalType.DATE)
|
||||
@Column(name = "rest_freqency_date")
|
||||
private Date restFrequencyDate;
|
||||
@Column(name = "rest_frequency_nth_day_enum", nullable = true)
|
||||
private Integer restFrequencyNthDay;
|
||||
|
||||
@Column(name = "rest_frequency_weekday_enum", nullable = true)
|
||||
private Integer restFrequencyWeekday;
|
||||
|
||||
@Column(name = "rest_frequency_on_day", nullable = true)
|
||||
private Integer restFrequencyOnDay;
|
||||
|
||||
@Column(name = "compounding_frequency_type_enum", nullable = true)
|
||||
private Integer compoundingFrequencyType;
|
||||
@@ -76,9 +77,14 @@ public class LoanProductInterestRecalculationDetails extends AbstractPersistable
|
||||
@Column(name = "compounding_frequency_interval", nullable = true)
|
||||
private Integer compoundingInterval;
|
||||
|
||||
@Temporal(TemporalType.DATE)
|
||||
@Column(name = "compounding_freqency_date")
|
||||
private Date compoundingFrequencyDate;
|
||||
@Column(name = "compounding_frequency_nth_day_enum", nullable = true)
|
||||
private Integer compoundingFrequencyNthDay;
|
||||
|
||||
@Column(name = "compounding_frequency_weekday_enum", nullable = true)
|
||||
private Integer compoundingFrequencyWeekday;
|
||||
|
||||
@Column(name = "compounding_frequency_on_day", nullable = true)
|
||||
private Integer compoundingFrequencyOnDay;
|
||||
|
||||
@Column(name = "arrears_based_on_original_schedule")
|
||||
private boolean isArrearsBasedOnOriginalSchedule;
|
||||
@@ -86,6 +92,12 @@ public class LoanProductInterestRecalculationDetails extends AbstractPersistable
|
||||
@Column(name = "pre_close_interest_calculation_strategy")
|
||||
private Integer preClosureInterestCalculationStrategy;
|
||||
|
||||
@Column(name = "is_compounding_to_be_posted_as_transaction")
|
||||
private Boolean isCompoundingToBePostedAsTransaction;
|
||||
|
||||
@Column(name = "allow_compounding_on_eod")
|
||||
private Boolean allowCompoundingOnEod;
|
||||
|
||||
protected LoanProductInterestRecalculationDetails() {
|
||||
//
|
||||
}
|
||||
@@ -100,19 +112,16 @@ public class LoanProductInterestRecalculationDetails extends AbstractPersistable
|
||||
|
||||
final Integer recurrenceFrequency = command
|
||||
.integerValueOfParameterNamed(LoanProductConstants.recalculationRestFrequencyTypeParameterName);
|
||||
final LocalDate recurrenceOnLocalDate = command
|
||||
.localDateValueOfParameterNamed(LoanProductConstants.recalculationRestFrequencyDateParamName);
|
||||
final Integer recurrenceOnNthDay = command
|
||||
.integerValueOfParameterNamed(LoanProductConstants.recalculationRestFrequencyNthDayParamName);
|
||||
final Integer recurrenceOnDay = command.integerValueOfParameterNamed(LoanProductConstants.recalculationRestFrequencyOnDayParamName);
|
||||
final Integer recurrenceOnWeekday = command
|
||||
.integerValueOfParameterNamed(LoanProductConstants.recalculationRestFrequencyWeekdayParamName);
|
||||
Integer recurrenceInterval = command
|
||||
.integerValueOfParameterNamed(LoanProductConstants.recalculationRestFrequencyIntervalParameterName);
|
||||
final boolean isArrearsBasedOnOriginalSchedule = command
|
||||
.booleanPrimitiveValueOfParameterNamed(LoanProductConstants.isArrearsBasedOnOriginalScheduleParamName);
|
||||
RecalculationFrequencyType frequencyType = RecalculationFrequencyType.fromInt(recurrenceFrequency);
|
||||
Date recurrenceOnDate = null;
|
||||
if (recurrenceOnLocalDate != null) {
|
||||
if (!frequencyType.isSameAsRepayment()) {
|
||||
recurrenceOnDate = recurrenceOnLocalDate.toDate();
|
||||
}
|
||||
}
|
||||
if (frequencyType.isSameAsRepayment()) {
|
||||
recurrenceInterval = 0;
|
||||
}
|
||||
@@ -121,7 +130,10 @@ public class LoanProductInterestRecalculationDetails extends AbstractPersistable
|
||||
.fromInt(interestRecalculationCompoundingMethod);
|
||||
Integer compoundingRecurrenceFrequency = null;
|
||||
Integer compoundingInterval = null;
|
||||
Date recurrenceOnCompoundingDate = null;
|
||||
Integer compoundingRecurrenceOnNthDay = null;
|
||||
Integer compoundingRecurrenceOnDay = null;
|
||||
Integer compoundingRecurrenceOnWeekday = null;
|
||||
boolean allowCompoundingOnEod = false;
|
||||
if (compoundingMethod.isCompoundingEnabled()) {
|
||||
compoundingRecurrenceFrequency = command
|
||||
.integerValueOfParameterNamed(LoanProductConstants.recalculationCompoundingFrequencyTypeParameterName);
|
||||
@@ -131,14 +143,14 @@ public class LoanProductInterestRecalculationDetails extends AbstractPersistable
|
||||
if (compoundingFrequencyType.isSameAsRepayment()) {
|
||||
recurrenceInterval = 0;
|
||||
}
|
||||
final LocalDate compoundingRecurrenceOnLocalDate = command
|
||||
.localDateValueOfParameterNamed(LoanProductConstants.recalculationCompoundingFrequencyDateParamName);
|
||||
|
||||
if (compoundingRecurrenceOnLocalDate != null) {
|
||||
if (!compoundingFrequencyType.isSameAsRepayment()) {
|
||||
recurrenceOnCompoundingDate = compoundingRecurrenceOnLocalDate.toDate();
|
||||
}
|
||||
}
|
||||
compoundingRecurrenceOnNthDay = command
|
||||
.integerValueOfParameterNamed(LoanProductConstants.recalculationCompoundingFrequencyNthDayParamName);
|
||||
compoundingRecurrenceOnDay = command
|
||||
.integerValueOfParameterNamed(LoanProductConstants.recalculationCompoundingFrequencyOnDayParamName);
|
||||
compoundingRecurrenceOnWeekday = command
|
||||
.integerValueOfParameterNamed(LoanProductConstants.recalculationCompoundingFrequencyWeekdayParamName);
|
||||
if (!compoundingFrequencyType.isDaily())
|
||||
allowCompoundingOnEod = command.booleanPrimitiveValueOfParameterNamed(LoanProductConstants.allowCompoundingOnEodParamName);
|
||||
}
|
||||
|
||||
Integer preCloseInterestCalculationStrategy = command
|
||||
@@ -147,25 +159,39 @@ public class LoanProductInterestRecalculationDetails extends AbstractPersistable
|
||||
preCloseInterestCalculationStrategy = LoanPreClosureInterestCalculationStrategy.TILL_PRE_CLOSURE_DATE.getValue();
|
||||
}
|
||||
|
||||
final boolean isCompoundingToBePostedAsTransaction = command
|
||||
.booleanPrimitiveValueOfParameterNamed(LoanProductConstants.isCompoundingToBePostedAsTransactionParamName);
|
||||
|
||||
return new LoanProductInterestRecalculationDetails(interestRecalculationCompoundingMethod, loanRescheduleStrategyMethod,
|
||||
recurrenceFrequency, recurrenceInterval, recurrenceOnDate, compoundingRecurrenceFrequency, compoundingInterval,
|
||||
recurrenceOnCompoundingDate, isArrearsBasedOnOriginalSchedule, preCloseInterestCalculationStrategy);
|
||||
recurrenceFrequency, recurrenceInterval, recurrenceOnNthDay, recurrenceOnDay, recurrenceOnWeekday,
|
||||
compoundingRecurrenceFrequency, compoundingInterval, compoundingRecurrenceOnNthDay, compoundingRecurrenceOnDay,
|
||||
compoundingRecurrenceOnWeekday, isArrearsBasedOnOriginalSchedule, preCloseInterestCalculationStrategy,
|
||||
isCompoundingToBePostedAsTransaction, allowCompoundingOnEod);
|
||||
}
|
||||
|
||||
private LoanProductInterestRecalculationDetails(final Integer interestRecalculationCompoundingMethod,
|
||||
final Integer rescheduleStrategyMethod, final Integer restFrequencyType, final Integer restInterval,
|
||||
final Date restFrequencyDate, Integer compoundingFrequencyType, Integer compoundingInterval, Date compoundingFrequencyDate,
|
||||
final boolean isArrearsBasedOnOriginalSchedule, final Integer preCloseInterestCalculationStrategy) {
|
||||
final Integer restFrequencyNthDay, final Integer restFrequencyOnDay, final Integer restFrequencyWeekday,
|
||||
Integer compoundingFrequencyType, Integer compoundingInterval, final Integer compoundingFrequencyNthDay,
|
||||
final Integer compoundingFrequencyOnDay, final Integer compoundingFrequencyWeekday,
|
||||
final boolean isArrearsBasedOnOriginalSchedule, final Integer preCloseInterestCalculationStrategy,
|
||||
final boolean isCompoundingToBePostedAsTransaction, final boolean allowCompoundingOnEod) {
|
||||
this.interestRecalculationCompoundingMethod = interestRecalculationCompoundingMethod;
|
||||
this.rescheduleStrategyMethod = rescheduleStrategyMethod;
|
||||
this.restFrequencyType = restFrequencyType;
|
||||
this.restInterval = restInterval;
|
||||
this.restFrequencyDate = restFrequencyDate;
|
||||
this.compoundingFrequencyDate = compoundingFrequencyDate;
|
||||
this.restFrequencyNthDay = restFrequencyNthDay;
|
||||
this.restFrequencyOnDay = restFrequencyOnDay;
|
||||
this.restFrequencyWeekday = restFrequencyWeekday;
|
||||
this.compoundingFrequencyType = compoundingFrequencyType;
|
||||
this.compoundingInterval = compoundingInterval;
|
||||
this.compoundingFrequencyNthDay = compoundingFrequencyNthDay;
|
||||
this.compoundingFrequencyOnDay = compoundingFrequencyOnDay;
|
||||
this.compoundingFrequencyWeekday = compoundingFrequencyWeekday;
|
||||
this.isArrearsBasedOnOriginalSchedule = isArrearsBasedOnOriginalSchedule;
|
||||
this.preClosureInterestCalculationStrategy = preCloseInterestCalculationStrategy;
|
||||
this.isCompoundingToBePostedAsTransaction = isCompoundingToBePostedAsTransaction;
|
||||
this.allowCompoundingOnEod = allowCompoundingOnEod;
|
||||
}
|
||||
|
||||
public void updateProduct(final LoanProduct loanProduct) {
|
||||
@@ -209,7 +235,9 @@ public class LoanProductInterestRecalculationDetails extends AbstractPersistable
|
||||
RecalculationFrequencyType frequencyType = RecalculationFrequencyType.fromInt(this.restFrequencyType);
|
||||
if (frequencyType.isSameAsRepayment()) {
|
||||
this.restInterval = 0;
|
||||
this.restFrequencyDate = null;
|
||||
this.restFrequencyNthDay = null;
|
||||
this.restFrequencyWeekday = null;
|
||||
this.restFrequencyOnDay = null;
|
||||
} else {
|
||||
if (command.isChangeInIntegerParameterNamed(LoanProductConstants.recalculationRestFrequencyIntervalParameterName,
|
||||
this.restInterval)) {
|
||||
@@ -220,16 +248,46 @@ public class LoanProductInterestRecalculationDetails extends AbstractPersistable
|
||||
this.restInterval = newValue;
|
||||
}
|
||||
|
||||
if (command.isChangeInLocalDateParameterNamed(LoanProductConstants.recalculationRestFrequencyDateParamName,
|
||||
getRestFrequencyLocalDate())) {
|
||||
final LocalDate newValue = command
|
||||
.localDateValueOfParameterNamed(LoanProductConstants.recalculationRestFrequencyDateParamName);
|
||||
Date recurrenceOnDate = null;
|
||||
if (newValue != null) {
|
||||
recurrenceOnDate = newValue.toDate();
|
||||
}
|
||||
actualChanges.put(LoanProductConstants.recalculationRestFrequencyDateParamName, newValue);
|
||||
this.restFrequencyDate = recurrenceOnDate;
|
||||
if (command.isChangeInIntegerParameterNamed(LoanProductConstants.recalculationRestFrequencyNthDayParamName,
|
||||
getRestFrequencyNthDay())) {
|
||||
Integer newValue = command.integerValueOfParameterNamed(LoanProductConstants.recalculationRestFrequencyNthDayParamName);
|
||||
actualChanges.put(LoanProductConstants.recalculationRestFrequencyNthDayParamName, newValue);
|
||||
actualChanges.put("locale", localeAsInput);
|
||||
this.restFrequencyNthDay = newValue;
|
||||
this.restFrequencyOnDay = null;
|
||||
}
|
||||
if (command.isChangeInIntegerParameterNamed(LoanProductConstants.recalculationRestFrequencyWeekdayParamName,
|
||||
getRestFrequencyWeekday())) {
|
||||
Integer newValue = command.integerValueOfParameterNamed(LoanProductConstants.recalculationRestFrequencyWeekdayParamName);
|
||||
actualChanges.put(LoanProductConstants.recalculationRestFrequencyWeekdayParamName, newValue);
|
||||
actualChanges.put("locale", localeAsInput);
|
||||
this.restFrequencyWeekday = newValue;
|
||||
this.restFrequencyOnDay = null;
|
||||
}
|
||||
if (command.isChangeInIntegerParameterNamed(LoanProductConstants.recalculationRestFrequencyOnDayParamName,
|
||||
getRestFrequencyOnDay())) {
|
||||
Integer newValue = command.integerValueOfParameterNamed(LoanProductConstants.recalculationRestFrequencyOnDayParamName);
|
||||
actualChanges.put(LoanProductConstants.recalculationRestFrequencyOnDayParamName, newValue);
|
||||
actualChanges.put("locale", localeAsInput);
|
||||
this.restFrequencyOnDay = newValue;
|
||||
this.restFrequencyNthDay = null;
|
||||
this.restFrequencyWeekday = null;
|
||||
}
|
||||
|
||||
if (frequencyType.isWeekly()) {
|
||||
this.restFrequencyNthDay = null;
|
||||
this.restFrequencyOnDay = null;
|
||||
} else if (frequencyType.isMonthly()) {
|
||||
if(command.integerValueOfParameterNamed(LoanProductConstants.recalculationRestFrequencyOnDayParamName) != null) {
|
||||
this.restFrequencyNthDay = null;
|
||||
this.restFrequencyWeekday = null;
|
||||
} else {
|
||||
this.restFrequencyOnDay = null;
|
||||
}
|
||||
} else if (frequencyType.isDaily()) {
|
||||
this.restFrequencyNthDay = null;
|
||||
this.restFrequencyWeekday = null;
|
||||
this.restFrequencyOnDay = null;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -247,7 +305,9 @@ public class LoanProductInterestRecalculationDetails extends AbstractPersistable
|
||||
RecalculationFrequencyType compoundingfrequencyType = RecalculationFrequencyType.fromInt(this.compoundingFrequencyType);
|
||||
if (compoundingfrequencyType.isSameAsRepayment()) {
|
||||
this.compoundingInterval = null;
|
||||
this.compoundingFrequencyDate = null;
|
||||
this.compoundingFrequencyNthDay = null;
|
||||
this.compoundingFrequencyWeekday = null;
|
||||
this.compoundingFrequencyOnDay = null;
|
||||
} else {
|
||||
if (command.isChangeInIntegerParameterNamed(LoanProductConstants.recalculationCompoundingFrequencyIntervalParameterName,
|
||||
this.compoundingInterval)) {
|
||||
@@ -257,22 +317,66 @@ public class LoanProductInterestRecalculationDetails extends AbstractPersistable
|
||||
this.compoundingInterval = newValue;
|
||||
}
|
||||
|
||||
if (command.isChangeInLocalDateParameterNamed(LoanProductConstants.recalculationCompoundingFrequencyDateParamName,
|
||||
getCompoundingFrequencyLocalDate())) {
|
||||
final LocalDate newValue = command
|
||||
.localDateValueOfParameterNamed(LoanProductConstants.recalculationCompoundingFrequencyDateParamName);
|
||||
Date recurrenceOnDate = null;
|
||||
if (newValue != null) {
|
||||
recurrenceOnDate = newValue.toDate();
|
||||
}
|
||||
actualChanges.put(LoanProductConstants.recalculationCompoundingFrequencyDateParamName, newValue);
|
||||
this.compoundingFrequencyDate = recurrenceOnDate;
|
||||
if (command.isChangeInIntegerParameterNamed(LoanProductConstants.recalculationCompoundingFrequencyNthDayParamName,
|
||||
getCompoundingFrequencyNthDay())) {
|
||||
Integer newValue = command
|
||||
.integerValueOfParameterNamed(LoanProductConstants.recalculationCompoundingFrequencyNthDayParamName);
|
||||
actualChanges.put(LoanProductConstants.recalculationCompoundingFrequencyNthDayParamName, newValue);
|
||||
actualChanges.put("locale", localeAsInput);
|
||||
this.compoundingFrequencyNthDay = newValue;
|
||||
this.compoundingFrequencyOnDay = null;
|
||||
}
|
||||
if (command.isChangeInIntegerParameterNamed(LoanProductConstants.recalculationCompoundingFrequencyWeekdayParamName,
|
||||
getCompoundingFrequencyWeekday())) {
|
||||
Integer newValue = command
|
||||
.integerValueOfParameterNamed(LoanProductConstants.recalculationCompoundingFrequencyWeekdayParamName);
|
||||
actualChanges.put(LoanProductConstants.recalculationCompoundingFrequencyWeekdayParamName, newValue);
|
||||
actualChanges.put("locale", localeAsInput);
|
||||
this.compoundingFrequencyWeekday = newValue;
|
||||
this.compoundingFrequencyOnDay = null;
|
||||
}
|
||||
if (command.isChangeInIntegerParameterNamed(LoanProductConstants.recalculationCompoundingFrequencyOnDayParamName,
|
||||
getCompoundingFrequencyOnDay())) {
|
||||
Integer newValue = command
|
||||
.integerValueOfParameterNamed(LoanProductConstants.recalculationCompoundingFrequencyOnDayParamName);
|
||||
actualChanges.put(LoanProductConstants.recalculationCompoundingFrequencyOnDayParamName, newValue);
|
||||
actualChanges.put("locale", localeAsInput);
|
||||
this.compoundingFrequencyOnDay = newValue;
|
||||
this.compoundingFrequencyNthDay = null;
|
||||
this.compoundingFrequencyWeekday = null;
|
||||
}
|
||||
|
||||
if (compoundingfrequencyType.isWeekly()) {
|
||||
this.compoundingFrequencyNthDay = null;
|
||||
this.compoundingFrequencyOnDay = null;
|
||||
} else if (compoundingfrequencyType.isMonthly()) {
|
||||
if(command.integerValueOfParameterNamed(LoanProductConstants.recalculationCompoundingFrequencyOnDayParamName) != null) {
|
||||
this.compoundingFrequencyNthDay = null;
|
||||
this.compoundingFrequencyWeekday = null;
|
||||
} else {
|
||||
this.compoundingFrequencyOnDay = null;
|
||||
}
|
||||
} else if (compoundingfrequencyType.isDaily()) {
|
||||
this.compoundingFrequencyNthDay = null;
|
||||
this.compoundingFrequencyWeekday = null;
|
||||
this.compoundingFrequencyOnDay = null;
|
||||
}
|
||||
}
|
||||
if (!compoundingfrequencyType.isDaily()) {
|
||||
if (command.isChangeInBooleanParameterNamed(LoanProductConstants.allowCompoundingOnEodParamName, allowCompoundingOnEod())) {
|
||||
boolean newValue = command.booleanPrimitiveValueOfParameterNamed(LoanProductConstants.allowCompoundingOnEodParamName);
|
||||
actualChanges.put(LoanProductConstants.allowCompoundingOnEodParamName, newValue);
|
||||
this.allowCompoundingOnEod = newValue;
|
||||
}
|
||||
} else {
|
||||
this.allowCompoundingOnEod = false;
|
||||
}
|
||||
} else {
|
||||
this.compoundingFrequencyType = null;
|
||||
this.compoundingInterval = null;
|
||||
this.compoundingFrequencyDate = null;
|
||||
this.compoundingFrequencyNthDay = null;
|
||||
this.compoundingFrequencyWeekday = null;
|
||||
this.compoundingFrequencyOnDay = null;
|
||||
}
|
||||
|
||||
if (command.isChangeInBooleanParameterNamed(LoanProductConstants.isArrearsBasedOnOriginalScheduleParamName,
|
||||
@@ -292,15 +396,15 @@ public class LoanProductInterestRecalculationDetails extends AbstractPersistable
|
||||
actualChanges.put(LoanProductConstants.preClosureInterestCalculationStrategyParamName, newValue);
|
||||
this.preClosureInterestCalculationStrategy = newValue;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
public LocalDate getRestFrequencyLocalDate() {
|
||||
LocalDate recurrenceOnLocalDate = null;
|
||||
if (this.restFrequencyDate != null) {
|
||||
recurrenceOnLocalDate = new LocalDate(this.restFrequencyDate);
|
||||
|
||||
if (command.isChangeInBooleanParameterNamed(LoanProductConstants.isCompoundingToBePostedAsTransactionParamName,
|
||||
this.isCompoundingToBePostedAsTransaction)) {
|
||||
final boolean newValue = command
|
||||
.booleanPrimitiveValueOfParameterNamed(LoanProductConstants.isCompoundingToBePostedAsTransactionParamName);
|
||||
actualChanges.put(LoanProductConstants.isCompoundingToBePostedAsTransactionParamName, newValue);
|
||||
this.isCompoundingToBePostedAsTransaction = newValue;
|
||||
}
|
||||
return recurrenceOnLocalDate;
|
||||
|
||||
}
|
||||
|
||||
public RecalculationFrequencyType getRestFrequencyType() {
|
||||
@@ -311,14 +415,6 @@ public class LoanProductInterestRecalculationDetails extends AbstractPersistable
|
||||
return this.restInterval;
|
||||
}
|
||||
|
||||
public LocalDate getCompoundingFrequencyLocalDate() {
|
||||
LocalDate recurrenceOnLocalDate = null;
|
||||
if (this.compoundingFrequencyDate != null) {
|
||||
recurrenceOnLocalDate = new LocalDate(this.compoundingFrequencyDate);
|
||||
}
|
||||
return recurrenceOnLocalDate;
|
||||
}
|
||||
|
||||
public RecalculationFrequencyType getCompoundingFrequencyType() {
|
||||
return RecalculationFrequencyType.fromInt(this.compoundingFrequencyType);
|
||||
}
|
||||
@@ -334,4 +430,36 @@ public class LoanProductInterestRecalculationDetails extends AbstractPersistable
|
||||
public LoanPreClosureInterestCalculationStrategy preCloseInterestCalculationStrategy() {
|
||||
return LoanPreClosureInterestCalculationStrategy.fromInt(this.preClosureInterestCalculationStrategy);
|
||||
}
|
||||
|
||||
public Integer getRestFrequencyNthDay() {
|
||||
return this.restFrequencyNthDay;
|
||||
}
|
||||
|
||||
public Integer getRestFrequencyWeekday() {
|
||||
return this.restFrequencyWeekday;
|
||||
}
|
||||
|
||||
public Integer getRestFrequencyOnDay() {
|
||||
return this.restFrequencyOnDay;
|
||||
}
|
||||
|
||||
public Integer getCompoundingFrequencyNthDay() {
|
||||
return this.compoundingFrequencyNthDay;
|
||||
}
|
||||
|
||||
public Integer getCompoundingFrequencyWeekday() {
|
||||
return this.compoundingFrequencyWeekday;
|
||||
}
|
||||
|
||||
public Integer getCompoundingFrequencyOnDay() {
|
||||
return this.compoundingFrequencyOnDay;
|
||||
}
|
||||
|
||||
public Boolean getIsCompoundingToBePostedAsTransaction() {
|
||||
return this.isCompoundingToBePostedAsTransaction;
|
||||
}
|
||||
|
||||
public Boolean allowCompoundingOnEod() {
|
||||
return this.allowCompoundingOnEod;
|
||||
}
|
||||
}
|
||||
|
||||
+2
-2
@@ -346,8 +346,9 @@ public class LoanProductRelatedDetail implements LoanProductMinimumRepaymentSche
|
||||
actualChanges.put(repaymentFrequencyTypeParamName, newValue);
|
||||
actualChanges.put("locale", localeAsInput);
|
||||
this.repaymentPeriodFrequencyType = PeriodFrequencyType.fromInt(newValue);
|
||||
|
||||
}
|
||||
if (this.repaymentPeriodFrequencyType == PeriodFrequencyType.MONTHS) {
|
||||
Integer newValue = null;
|
||||
final String repaymentFrequencyNthDayTypeParamName = "repaymentFrequencyNthDayType";
|
||||
newValue = command.integerValueOfParameterNamed(repaymentFrequencyNthDayTypeParamName);
|
||||
actualChanges.put(repaymentFrequencyNthDayTypeParamName, newValue);
|
||||
@@ -357,7 +358,6 @@ public class LoanProductRelatedDetail implements LoanProductMinimumRepaymentSche
|
||||
actualChanges.put(repaymentFrequencyDayOfWeekTypeParamName, newValue);
|
||||
|
||||
actualChanges.put("locale", localeAsInput);
|
||||
}
|
||||
}
|
||||
|
||||
final String numberOfRepaymentsParamName = "numberOfRepayments";
|
||||
|
||||
+47
-22
@@ -30,13 +30,14 @@ import java.util.Map;
|
||||
import java.util.Set;
|
||||
|
||||
import org.apache.commons.lang.StringUtils;
|
||||
import org.apache.fineract.accounting.common.AccountingRuleType;
|
||||
import org.apache.fineract.accounting.common.AccountingConstants.LOAN_PRODUCT_ACCOUNTING_PARAMS;
|
||||
import org.apache.fineract.accounting.common.AccountingRuleType;
|
||||
import org.apache.fineract.infrastructure.core.data.ApiParameterError;
|
||||
import org.apache.fineract.infrastructure.core.data.DataValidatorBuilder;
|
||||
import org.apache.fineract.infrastructure.core.exception.InvalidJsonException;
|
||||
import org.apache.fineract.infrastructure.core.exception.PlatformApiDataValidationException;
|
||||
import org.apache.fineract.infrastructure.core.serialization.FromJsonHelper;
|
||||
import org.apache.fineract.portfolio.calendar.service.CalendarUtils;
|
||||
import org.apache.fineract.portfolio.common.domain.PeriodFrequencyType;
|
||||
import org.apache.fineract.portfolio.loanproduct.LoanProductConstants;
|
||||
import org.apache.fineract.portfolio.loanproduct.domain.InterestCalculationPeriodMethod;
|
||||
@@ -47,7 +48,6 @@ import org.apache.fineract.portfolio.loanproduct.domain.LoanProduct;
|
||||
import org.apache.fineract.portfolio.loanproduct.domain.LoanProductConfigurableAttributes;
|
||||
import org.apache.fineract.portfolio.loanproduct.domain.LoanProductValueConditionType;
|
||||
import org.apache.fineract.portfolio.loanproduct.domain.RecalculationFrequencyType;
|
||||
import org.joda.time.LocalDate;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.stereotype.Component;
|
||||
|
||||
@@ -90,10 +90,8 @@ public final class LoanProductDataValidator {
|
||||
LoanProductConstants.daysInYearTypeParameterName, LoanProductConstants.daysInMonthTypeParameterName,
|
||||
LoanProductConstants.rescheduleStrategyMethodParameterName,
|
||||
LoanProductConstants.interestRecalculationCompoundingMethodParameterName,
|
||||
LoanProductConstants.recalculationRestFrequencyDateParamName,
|
||||
LoanProductConstants.recalculationRestFrequencyIntervalParameterName,
|
||||
LoanProductConstants.recalculationRestFrequencyTypeParameterName,
|
||||
LoanProductConstants.recalculationCompoundingFrequencyDateParamName,
|
||||
LoanProductConstants.recalculationCompoundingFrequencyIntervalParameterName,
|
||||
LoanProductConstants.recalculationCompoundingFrequencyTypeParameterName,
|
||||
LoanProductConstants.isArrearsBasedOnOriginalScheduleParamName,
|
||||
@@ -104,7 +102,12 @@ public final class LoanProductDataValidator {
|
||||
LoanProductConstants.installmentAmountInMultiplesOfParamName,
|
||||
LoanProductConstants.preClosureInterestCalculationStrategyParamName, LoanProductConstants.allowAttributeOverridesParamName,
|
||||
LoanProductConstants.allowVariableInstallmentsParamName, LoanProductConstants.minimumGapBetweenInstallments,
|
||||
LoanProductConstants.maximumGapBetweenInstallments));
|
||||
LoanProductConstants.maximumGapBetweenInstallments, LoanProductConstants.recalculationCompoundingFrequencyWeekdayParamName,
|
||||
LoanProductConstants.recalculationCompoundingFrequencyNthDayParamName,
|
||||
LoanProductConstants.recalculationCompoundingFrequencyOnDayParamName,
|
||||
LoanProductConstants.recalculationRestFrequencyWeekdayParamName,
|
||||
LoanProductConstants.recalculationRestFrequencyNthDayParamName, LoanProductConstants.recalculationRestFrequencyOnDayParamName,
|
||||
LoanProductConstants.isCompoundingToBePostedAsTransactionParamName, LoanProductConstants.allowCompoundingOnEodParamName));
|
||||
|
||||
private final FromJsonHelper fromApiJsonHelper;
|
||||
|
||||
@@ -786,13 +789,6 @@ public final class LoanProductDataValidator {
|
||||
}
|
||||
|
||||
if (!frequencyType.isSameAsRepayment()) {
|
||||
if (loanProduct == null
|
||||
|| this.fromApiJsonHelper.parameterExists(LoanProductConstants.recalculationRestFrequencyDateParamName, element)) {
|
||||
final LocalDate recurrenceOnLocalDate = this.fromApiJsonHelper.extractLocalDateNamed(
|
||||
LoanProductConstants.recalculationRestFrequencyDateParamName, element);
|
||||
baseDataValidator.reset().parameter(LoanProductConstants.recalculationRestFrequencyDateParamName)
|
||||
.value(recurrenceOnLocalDate).notNull();
|
||||
}
|
||||
if (loanProduct == null
|
||||
|| this.fromApiJsonHelper
|
||||
.parameterExists(LoanProductConstants.recalculationRestFrequencyIntervalParameterName, element)) {
|
||||
@@ -801,6 +797,20 @@ public final class LoanProductDataValidator {
|
||||
baseDataValidator.reset().parameter(LoanProductConstants.recalculationRestFrequencyIntervalParameterName)
|
||||
.value(recurrenceInterval).notNull();
|
||||
}
|
||||
if (loanProduct == null
|
||||
|| this.fromApiJsonHelper.parameterExists(LoanProductConstants.recalculationRestFrequencyNthDayParamName, element)
|
||||
|| this.fromApiJsonHelper.parameterExists(LoanProductConstants.recalculationRestFrequencyWeekdayParamName, element)) {
|
||||
CalendarUtils.validateNthDayOfMonthFrequency(baseDataValidator,
|
||||
LoanProductConstants.recalculationRestFrequencyNthDayParamName,
|
||||
LoanProductConstants.recalculationRestFrequencyWeekdayParamName, element, this.fromApiJsonHelper);
|
||||
}
|
||||
if (loanProduct == null
|
||||
|| this.fromApiJsonHelper.parameterExists(LoanProductConstants.recalculationRestFrequencyOnDayParamName, element)) {
|
||||
final Integer recalculationRestFrequencyOnDay = this.fromApiJsonHelper.extractIntegerNamed(
|
||||
LoanProductConstants.recalculationRestFrequencyOnDayParamName, element, Locale.getDefault());
|
||||
baseDataValidator.reset().parameter(LoanProductConstants.recalculationRestFrequencyOnDayParamName)
|
||||
.value(recalculationRestFrequencyOnDay).ignoreIfNull().inMinMaxRange(1, 28);
|
||||
}
|
||||
}
|
||||
|
||||
if (compoundingMethod.isCompoundingEnabled()) {
|
||||
@@ -817,11 +827,11 @@ public final class LoanProductDataValidator {
|
||||
compoundingfrequencyType = RecalculationFrequencyType.fromInt(recalculationCompoundingFrequencyType);
|
||||
if (!compoundingfrequencyType.isSameAsRepayment()) {
|
||||
PeriodFrequencyType repaymentFrequencyType = null;
|
||||
if (loanProduct == null) {
|
||||
if (this.fromApiJsonHelper.parameterExists("repaymentFrequencyType", element)) {
|
||||
Integer repaymentFrequencyTypeVal = this.fromApiJsonHelper.extractIntegerNamed("repaymentFrequencyType",
|
||||
element, Locale.getDefault());
|
||||
repaymentFrequencyType = PeriodFrequencyType.fromInt(repaymentFrequencyTypeVal);
|
||||
} else {
|
||||
} else if (loanProduct != null) {
|
||||
repaymentFrequencyType = loanProduct.getLoanProductRelatedDetail().getRepaymentPeriodFrequencyType();
|
||||
}
|
||||
if (!compoundingfrequencyType.isSameFrequency(repaymentFrequencyType)) {
|
||||
@@ -841,14 +851,6 @@ public final class LoanProductDataValidator {
|
||||
}
|
||||
|
||||
if (!compoundingfrequencyType.isSameAsRepayment()) {
|
||||
if (loanProduct == null
|
||||
|| this.fromApiJsonHelper.parameterExists(LoanProductConstants.recalculationCompoundingFrequencyDateParamName,
|
||||
element)) {
|
||||
final LocalDate recurrenceOnLocalDate = this.fromApiJsonHelper.extractLocalDateNamed(
|
||||
LoanProductConstants.recalculationCompoundingFrequencyDateParamName, element);
|
||||
baseDataValidator.reset().parameter(LoanProductConstants.recalculationCompoundingFrequencyDateParamName)
|
||||
.value(recurrenceOnLocalDate).notNull();
|
||||
}
|
||||
if (loanProduct == null
|
||||
|| this.fromApiJsonHelper.parameterExists(
|
||||
LoanProductConstants.recalculationCompoundingFrequencyIntervalParameterName, element)) {
|
||||
@@ -864,6 +866,23 @@ public final class LoanProductDataValidator {
|
||||
baseDataValidator.reset().parameter(LoanProductConstants.recalculationCompoundingFrequencyIntervalParameterName)
|
||||
.value(recurrenceInterval).notNull().integerInMultiplesOfNumber(repaymentEvery);
|
||||
}
|
||||
if (loanProduct == null
|
||||
|| this.fromApiJsonHelper.parameterExists(LoanProductConstants.recalculationCompoundingFrequencyNthDayParamName,
|
||||
element)
|
||||
|| this.fromApiJsonHelper.parameterExists(LoanProductConstants.recalculationCompoundingFrequencyWeekdayParamName,
|
||||
element)) {
|
||||
CalendarUtils.validateNthDayOfMonthFrequency(baseDataValidator,
|
||||
LoanProductConstants.recalculationCompoundingFrequencyNthDayParamName,
|
||||
LoanProductConstants.recalculationCompoundingFrequencyWeekdayParamName, element, this.fromApiJsonHelper);
|
||||
}
|
||||
if (loanProduct == null
|
||||
|| this.fromApiJsonHelper.parameterExists(LoanProductConstants.recalculationCompoundingFrequencyOnDayParamName,
|
||||
element)) {
|
||||
final Integer recalculationRestFrequencyOnDay = this.fromApiJsonHelper.extractIntegerNamed(
|
||||
LoanProductConstants.recalculationCompoundingFrequencyOnDayParamName, element, Locale.getDefault());
|
||||
baseDataValidator.reset().parameter(LoanProductConstants.recalculationCompoundingFrequencyOnDayParamName)
|
||||
.value(recalculationRestFrequencyOnDay).ignoreIfNull().inMinMaxRange(1, 28);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -873,6 +892,12 @@ public final class LoanProductDataValidator {
|
||||
baseDataValidator.reset().parameter(LoanProductConstants.isArrearsBasedOnOriginalScheduleParamName)
|
||||
.value(isArrearsBasedOnOriginalSchedule).notNull().isOneOfTheseValues(true, false);
|
||||
}
|
||||
if (this.fromApiJsonHelper.parameterExists(LoanProductConstants.isCompoundingToBePostedAsTransactionParamName, element)) {
|
||||
final Boolean isCompoundingToBePostedAsTransactions = this.fromApiJsonHelper.extractBooleanNamed(
|
||||
LoanProductConstants.isCompoundingToBePostedAsTransactionParamName, element);
|
||||
baseDataValidator.reset().parameter(LoanProductConstants.isCompoundingToBePostedAsTransactionParamName)
|
||||
.value(isCompoundingToBePostedAsTransactions).notNull().isOneOfTheseValues(true, false);
|
||||
}
|
||||
|
||||
final Integer preCloseInterestCalculationStrategy = this.fromApiJsonHelper.extractIntegerWithLocaleNamed(
|
||||
LoanProductConstants.preClosureInterestCalculationStrategyParamName, element);
|
||||
|
||||
+2
@@ -47,6 +47,8 @@ public interface LoanDropdownReadPlatformService {
|
||||
List<EnumOptionData> retrieveLoanCycleValueConditionTypeOptions();
|
||||
|
||||
List<EnumOptionData> retrieveInterestRecalculationCompoundingTypeOptions();
|
||||
List<EnumOptionData> retrieveInterestRecalculationNthDayTypeOptions();
|
||||
List<EnumOptionData> retrieveInterestRecalculationDayOfWeekTypeOptions();
|
||||
|
||||
List<EnumOptionData> retrieveRescheduleStrategyTypeOptions();
|
||||
|
||||
|
||||
+26
-2
@@ -31,6 +31,8 @@ import static org.apache.fineract.portfolio.loanproduct.service.LoanEnumerations
|
||||
import static org.apache.fineract.portfolio.loanproduct.service.LoanEnumerations.repaymentFrequencyNthDayType;
|
||||
import static org.apache.fineract.portfolio.loanproduct.service.LoanEnumerations.repaymentFrequencyType;
|
||||
import static org.apache.fineract.portfolio.loanproduct.service.LoanEnumerations.rescheduleStrategyType;
|
||||
import static org.apache.fineract.portfolio.loanproduct.service.LoanEnumerations.interestRecalculationCompoundingNthDayType;
|
||||
import static org.apache.fineract.portfolio.loanproduct.service.LoanEnumerations.interestRecalculationCompoundingDayOfWeekType;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.Arrays;
|
||||
@@ -112,7 +114,7 @@ public class LoanDropdownReadPlatformServiceImpl implements LoanDropdownReadPlat
|
||||
public List<EnumOptionData> retrieveRepaymentFrequencyOptionsForNthDayOfMonth() {
|
||||
final List<EnumOptionData> repaymentFrequencyOptions = Arrays.asList(repaymentFrequencyNthDayType(NthDayType.ONE),
|
||||
repaymentFrequencyNthDayType(NthDayType.TWO), repaymentFrequencyNthDayType(NthDayType.THREE),
|
||||
repaymentFrequencyNthDayType(NthDayType.FOUR));
|
||||
repaymentFrequencyNthDayType(NthDayType.FOUR), repaymentFrequencyNthDayType(NthDayType.LAST));
|
||||
return repaymentFrequencyOptions;
|
||||
}
|
||||
|
||||
@@ -138,7 +140,7 @@ public class LoanDropdownReadPlatformServiceImpl implements LoanDropdownReadPlat
|
||||
public Collection<TransactionProcessingStrategyData> retreiveTransactionProcessingStrategies() {
|
||||
|
||||
final Collection<TransactionProcessingStrategyData> strategyOptions = new ArrayList<>();
|
||||
Sort sort = new Sort("sortOrder") ;
|
||||
Sort sort = new Sort("sortOrder");
|
||||
final List<LoanTransactionProcessingStrategy> strategies = this.loanTransactionProcessingStrategyRepository.findAll(sort);
|
||||
for (final LoanTransactionProcessingStrategy strategy : strategies) {
|
||||
strategyOptions.add(strategy.toData());
|
||||
@@ -167,6 +169,28 @@ public class LoanDropdownReadPlatformServiceImpl implements LoanDropdownReadPlat
|
||||
return interestRecalculationCompoundingTypeOptions;
|
||||
}
|
||||
|
||||
@Override
|
||||
public List<EnumOptionData> retrieveInterestRecalculationNthDayTypeOptions() {
|
||||
final List<EnumOptionData> interestRecalculationCompoundingNthDayTypeOptions = Arrays.asList(
|
||||
interestRecalculationCompoundingNthDayType(NthDayType.ONE), interestRecalculationCompoundingNthDayType(NthDayType.TWO),
|
||||
interestRecalculationCompoundingNthDayType(NthDayType.THREE), interestRecalculationCompoundingNthDayType(NthDayType.FOUR),
|
||||
interestRecalculationCompoundingNthDayType(NthDayType.LAST));
|
||||
return interestRecalculationCompoundingNthDayTypeOptions;
|
||||
}
|
||||
|
||||
@Override
|
||||
public List<EnumOptionData> retrieveInterestRecalculationDayOfWeekTypeOptions() {
|
||||
final List<EnumOptionData> interestRecalculationCompoundingNthDayTypeOptions = Arrays.asList(
|
||||
interestRecalculationCompoundingDayOfWeekType(DayOfWeekType.SUNDAY),
|
||||
interestRecalculationCompoundingDayOfWeekType(DayOfWeekType.MONDAY),
|
||||
interestRecalculationCompoundingDayOfWeekType(DayOfWeekType.TUESDAY),
|
||||
interestRecalculationCompoundingDayOfWeekType(DayOfWeekType.WEDNESDAY),
|
||||
interestRecalculationCompoundingDayOfWeekType(DayOfWeekType.THURSDAY),
|
||||
interestRecalculationCompoundingDayOfWeekType(DayOfWeekType.FRIDAY),
|
||||
interestRecalculationCompoundingDayOfWeekType(DayOfWeekType.SATURDAY));
|
||||
return interestRecalculationCompoundingNthDayTypeOptions;
|
||||
}
|
||||
|
||||
@Override
|
||||
public List<EnumOptionData> retrieveRescheduleStrategyTypeOptions() {
|
||||
|
||||
|
||||
+49
@@ -172,6 +172,9 @@ public class LoanEnumerations {
|
||||
case FIVE:
|
||||
optionData = new EnumOptionData(nthDayValue, codePrefix + type.getCode(), "fifth");
|
||||
break;
|
||||
case LAST:
|
||||
optionData = new EnumOptionData(nthDayValue, codePrefix + type.getCode(), "last");
|
||||
break;
|
||||
default:
|
||||
optionData = new EnumOptionData(new Integer(0).longValue(), codePrefix + type.getCode(), "invalid");
|
||||
break;
|
||||
@@ -390,6 +393,10 @@ public class LoanEnumerations {
|
||||
optionData = new LoanTransactionEnumData(LoanTransactionType.REFUND_FOR_ACTIVE_LOAN.getValue().longValue(),
|
||||
LoanTransactionType.REFUND_FOR_ACTIVE_LOAN.getCode(), "Refund");
|
||||
break;
|
||||
case INCOME_POSTING:
|
||||
optionData = new LoanTransactionEnumData(LoanTransactionType.INCOME_POSTING.getValue().longValue(),
|
||||
LoanTransactionType.INCOME_POSTING.getCode(), "Income Posting");
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
@@ -578,6 +585,48 @@ public class LoanEnumerations {
|
||||
}
|
||||
return optionData;
|
||||
}
|
||||
public static EnumOptionData interestRecalculationCompoundingNthDayType(final Integer id) {
|
||||
if (id == null) { return null; }
|
||||
return interestRecalculationCompoundingNthDayType(NthDayType.fromInt(id));
|
||||
}
|
||||
public static EnumOptionData interestRecalculationCompoundingNthDayType(final NthDayType type) {
|
||||
final String codePrefix = "interestRecalculationCompounding.";
|
||||
long nthDayValue = type.getValue().longValue();
|
||||
EnumOptionData optionData = null;
|
||||
switch (type) {
|
||||
case ONE:
|
||||
optionData = new EnumOptionData(nthDayValue, codePrefix + type.getCode(), "first");
|
||||
break;
|
||||
case TWO:
|
||||
optionData = new EnumOptionData(nthDayValue, codePrefix + type.getCode(), "second");
|
||||
break;
|
||||
case THREE:
|
||||
optionData = new EnumOptionData(nthDayValue, codePrefix + type.getCode(), "third");
|
||||
break;
|
||||
case FOUR:
|
||||
optionData = new EnumOptionData(nthDayValue, codePrefix + type.getCode(), "fourth");
|
||||
break;
|
||||
case FIVE:
|
||||
optionData = new EnumOptionData(nthDayValue, codePrefix + type.getCode(), "fifth");
|
||||
break;
|
||||
case LAST:
|
||||
optionData = new EnumOptionData(nthDayValue, codePrefix + type.getCode(), "last");
|
||||
break;
|
||||
default:
|
||||
optionData = new EnumOptionData(new Integer(0).longValue(), codePrefix + type.getCode(), "invalid");
|
||||
break;
|
||||
}
|
||||
return optionData;
|
||||
}
|
||||
public static EnumOptionData interestRecalculationCompoundingDayOfWeekType(final Integer id) {
|
||||
if (id == null) { return null; }
|
||||
return interestRecalculationCompoundingDayOfWeekType(DayOfWeekType.fromInt(id));
|
||||
}
|
||||
public static EnumOptionData interestRecalculationCompoundingDayOfWeekType(final DayOfWeekType type) {
|
||||
final String codePrefix = "interestRecalculationCompounding.";
|
||||
EnumOptionData optionData = new EnumOptionData(type.getValue().longValue(), codePrefix + type.getCode(), type.toString());
|
||||
return optionData;
|
||||
}
|
||||
|
||||
public static EnumOptionData rescheduleStrategyType(final int id) {
|
||||
return rescheduleStrategyType(LoanRescheduleStrategyMethod.fromInt(id));
|
||||
|
||||
+40
-6
@@ -194,9 +194,16 @@ public class LoanProductReadPlatformServiceImpl implements LoanProductReadPlatfo
|
||||
+ "lpr.pre_close_interest_calculation_strategy as preCloseInterestCalculationStrategy, "
|
||||
+ "lpr.id as lprId, lpr.product_id as productId, lpr.compound_type_enum as compoundType, lpr.reschedule_strategy_enum as rescheduleStrategy, "
|
||||
+ "lpr.rest_frequency_type_enum as restFrequencyEnum, lpr.rest_frequency_interval as restFrequencyInterval, "
|
||||
+ "lpr.rest_freqency_date as restFrequencyDate, lpr.arrears_based_on_original_schedule as isArrearsBasedOnOriginalSchedule, "
|
||||
+ "lpr.rest_frequency_nth_day_enum as restFrequencyNthDayEnum, "
|
||||
+ "lpr.rest_frequency_weekday_enum as restFrequencyWeekDayEnum, "
|
||||
+ "lpr.rest_frequency_on_day as restFrequencyOnDay, "
|
||||
+ "lpr.arrears_based_on_original_schedule as isArrearsBasedOnOriginalSchedule, "
|
||||
+ "lpr.compounding_frequency_type_enum as compoundingFrequencyTypeEnum, lpr.compounding_frequency_interval as compoundingInterval, "
|
||||
+ "lpr.compounding_freqency_date as compoundingFrequencyDate, "
|
||||
+ "lpr.compounding_frequency_nth_day_enum as compoundingFrequencyNthDayEnum, "
|
||||
+ "lpr.compounding_frequency_weekday_enum as compoundingFrequencyWeekDayEnum, "
|
||||
+ "lpr.compounding_frequency_on_day as compoundingFrequencyOnDay, "
|
||||
+ "lpr.is_compounding_to_be_posted_as_transaction as isCompoundingToBePostedAsTransaction, "
|
||||
+ "lpr.allow_compounding_on_eod as allowCompoundingOnEod, "
|
||||
+ "lp.hold_guarantee_funds as holdGuaranteeFunds, "
|
||||
+ "lp.principal_threshold_for_last_installment as principalThresholdForLastInstallment, "
|
||||
+ "lpg.id as lpgId, lpg.mandatory_guarantee as mandatoryGuarantee, "
|
||||
@@ -361,23 +368,50 @@ public class LoanProductReadPlatformServiceImpl implements LoanProductReadPlatfo
|
||||
final int restFrequencyEnumValue = JdbcSupport.getInteger(rs, "restFrequencyEnum");
|
||||
final EnumOptionData restFrequencyType = LoanEnumerations.interestRecalculationFrequencyType(restFrequencyEnumValue);
|
||||
final int restFrequencyInterval = JdbcSupport.getInteger(rs, "restFrequencyInterval");
|
||||
final LocalDate restFrequencyDate = JdbcSupport.getLocalDate(rs, "restFrequencyDate");
|
||||
final Integer restFrequencyNthDayEnumValue = JdbcSupport.getInteger(rs, "restFrequencyNthDayEnum");
|
||||
EnumOptionData restFrequencyNthDayEnum = null;
|
||||
if (restFrequencyNthDayEnumValue != null) {
|
||||
restFrequencyNthDayEnum = LoanEnumerations.interestRecalculationCompoundingNthDayType(restFrequencyNthDayEnumValue);
|
||||
}
|
||||
final Integer restFrequencyWeekDayEnumValue = JdbcSupport.getInteger(rs, "restFrequencyWeekDayEnum");
|
||||
EnumOptionData restFrequencyWeekDayEnum = null;
|
||||
if (restFrequencyWeekDayEnumValue != null) {
|
||||
restFrequencyWeekDayEnum = LoanEnumerations
|
||||
.interestRecalculationCompoundingDayOfWeekType(restFrequencyWeekDayEnumValue);
|
||||
}
|
||||
final Integer restFrequencyOnDay = JdbcSupport.getInteger(rs, "restFrequencyOnDay");
|
||||
final Integer compoundingFrequencyEnumValue = JdbcSupport.getInteger(rs, "compoundingFrequencyTypeEnum");
|
||||
EnumOptionData compoundingFrequencyType = null;
|
||||
if (compoundingFrequencyEnumValue != null) {
|
||||
compoundingFrequencyType = LoanEnumerations.interestRecalculationFrequencyType(compoundingFrequencyEnumValue);
|
||||
}
|
||||
final Integer compoundingInterval = JdbcSupport.getInteger(rs, "compoundingInterval");
|
||||
final LocalDate compoundingFrequencyDate = JdbcSupport.getLocalDate(rs, "compoundingFrequencyDate");
|
||||
final Integer compoundingFrequencyNthDayEnumValue = JdbcSupport.getInteger(rs, "compoundingFrequencyNthDayEnum");
|
||||
EnumOptionData compoundingFrequencyNthDayEnum = null;
|
||||
if (compoundingFrequencyNthDayEnumValue != null) {
|
||||
compoundingFrequencyNthDayEnum = LoanEnumerations
|
||||
.interestRecalculationCompoundingNthDayType(compoundingFrequencyNthDayEnumValue);
|
||||
}
|
||||
final Integer compoundingFrequencyWeekDayEnumValue = JdbcSupport.getInteger(rs, "compoundingFrequencyWeekDayEnum");
|
||||
EnumOptionData compoundingFrequencyWeekDayEnum = null;
|
||||
if (compoundingFrequencyWeekDayEnumValue != null) {
|
||||
compoundingFrequencyWeekDayEnum = LoanEnumerations
|
||||
.interestRecalculationCompoundingDayOfWeekType(compoundingFrequencyWeekDayEnumValue);
|
||||
}
|
||||
final Integer compoundingFrequencyOnDay = JdbcSupport.getInteger(rs, "compoundingFrequencyOnDay");
|
||||
final boolean isArrearsBasedOnOriginalSchedule = rs.getBoolean("isArrearsBasedOnOriginalSchedule");
|
||||
final boolean isCompoundingToBePostedAsTransaction = rs.getBoolean("isCompoundingToBePostedAsTransaction");
|
||||
final int preCloseInterestCalculationStrategyEnumValue = JdbcSupport.getInteger(rs, "preCloseInterestCalculationStrategy");
|
||||
final EnumOptionData preCloseInterestCalculationStrategy = LoanEnumerations
|
||||
.preCloseInterestCalculationStrategy(preCloseInterestCalculationStrategyEnumValue);
|
||||
final boolean allowCompoundingOnEod = rs.getBoolean("allowCompoundingOnEod");
|
||||
|
||||
interestRecalculationData = new LoanProductInterestRecalculationData(lprId, productId,
|
||||
interestRecalculationCompoundingType, rescheduleStrategyType, restFrequencyType, restFrequencyInterval,
|
||||
restFrequencyDate, compoundingFrequencyType, compoundingInterval, compoundingFrequencyDate,
|
||||
isArrearsBasedOnOriginalSchedule, preCloseInterestCalculationStrategy);
|
||||
restFrequencyNthDayEnum, restFrequencyWeekDayEnum, restFrequencyOnDay, compoundingFrequencyType,
|
||||
compoundingInterval, compoundingFrequencyNthDayEnum, compoundingFrequencyWeekDayEnum, compoundingFrequencyOnDay,
|
||||
isArrearsBasedOnOriginalSchedule, isCompoundingToBePostedAsTransaction, preCloseInterestCalculationStrategy,
|
||||
allowCompoundingOnEod);
|
||||
}
|
||||
|
||||
final boolean amortization = rs.getBoolean("amortizationBoolean");
|
||||
|
||||
+2
-2
@@ -342,7 +342,7 @@ public class DepositApplicationProcessWritePlatformServiceJpaRepositoryImpl impl
|
||||
final String title = "recurring_savings_" + account.getId();
|
||||
|
||||
final Calendar calendar = Calendar.createRepeatingCalendar(title, calendarStartDate, CalendarType.COLLECTION.getValue(),
|
||||
CalendarFrequencyType.from(periodFrequencyType), frequency, repeatsOnDay);
|
||||
CalendarFrequencyType.from(periodFrequencyType), frequency, repeatsOnDay, null);
|
||||
calendarInstance = CalendarInstance.from(calendar, account.getId(), CalendarEntityType.SAVINGS.getValue());
|
||||
}
|
||||
if (calendarInstance == null) {
|
||||
@@ -488,7 +488,7 @@ public class DepositApplicationProcessWritePlatformServiceJpaRepositoryImpl impl
|
||||
accountId, CalendarEntityType.SAVINGS.getValue(), CalendarType.COLLECTION.getValue());
|
||||
Calendar calendar = calendarInstance.getCalendar();
|
||||
calendar.updateRepeatingCalendar(calendarStartDate, CalendarFrequencyType.from(periodFrequencyType), frequency,
|
||||
repeatsOnDay);
|
||||
repeatsOnDay, null);
|
||||
this.calendarInstanceRepository.save(calendarInstance);
|
||||
}
|
||||
|
||||
|
||||
+60
@@ -0,0 +1,60 @@
|
||||
CREATE TABLE `m_loan_interest_recalculation_additional_details` (
|
||||
`id` BIGINT NOT NULL AUTO_INCREMENT,
|
||||
`loan_repayment_schedule_id` BIGINT NOT NULL,
|
||||
`effective_date` DATE NOT NULL,
|
||||
`amount` DECIMAL(19,6) NOT NULL,
|
||||
PRIMARY KEY (`id`),
|
||||
CONSTRAINT `FK_additional_details_repayment_schedule_id` FOREIGN KEY (`loan_repayment_schedule_id`) REFERENCES `m_loan_repayment_schedule` (`id`)
|
||||
);
|
||||
|
||||
|
||||
ALTER TABLE `m_loan` DROP `repayment_frequency_nth_day_enum`, DROP `repayment_frequency_day_of_week_enum`;
|
||||
|
||||
|
||||
ALTER TABLE `m_product_loan_recalculation_details` ADD `rest_frequency_nth_day_enum` INT(5), ADD `rest_frequency_on_day` INT(5), ADD `rest_frequency_weekday_enum` INT(5),
|
||||
ADD `compounding_frequency_nth_day_enum` INT(5), ADD `compounding_frequency_on_day` INT(5), ADD `compounding_frequency_weekday_enum` INT(5), ADD `is_compounding_to_be_posted_as_transaction` TINYINT(1) NOT NULL DEFAULT '0', ADD `allow_compounding_on_eod` TINYINT(1) NOT NULL DEFAULT '0';
|
||||
|
||||
|
||||
ALTER TABLE `m_loan_recalculation_details` ADD `rest_frequency_nth_day_enum` INT(5), ADD `rest_frequency_on_day` INT(5), ADD `rest_frequency_weekday_enum` INT(5),
|
||||
ADD `compounding_frequency_nth_day_enum` INT(5), ADD `compounding_frequency_on_day` INT(5),
|
||||
ADD `is_compounding_to_be_posted_as_transaction` TINYINT(1) NOT NULL DEFAULT '0',
|
||||
ADD `compounding_frequency_weekday_enum` INT(5), ADD `allow_compounding_on_eod` TINYINT(1) NOT NULL DEFAULT '0';
|
||||
|
||||
|
||||
UPDATE m_product_loan_recalculation_details plr SET plr.compounding_frequency_weekday_enum = (WEEKDAY(plr.compounding_freqency_date) + 1) WHERE plr.compounding_frequency_type_enum = 3 AND plr.compounding_freqency_date IS NOT NULL;
|
||||
|
||||
|
||||
UPDATE m_product_loan_recalculation_details plr SET plr.compounding_frequency_on_day = DAYOFMONTH(plr.compounding_freqency_date) WHERE plr.compounding_frequency_type_enum = 4 AND plr.compounding_freqency_date IS NOT NULL;
|
||||
|
||||
|
||||
UPDATE m_loan_recalculation_details lrd SET lrd.compounding_frequency_weekday_enum = (WEEKDAY(lrd.compounding_freqency_date) + 1) WHERE lrd.compounding_frequency_type_enum = 3 AND lrd.compounding_freqency_date IS NOT NULL;
|
||||
|
||||
|
||||
UPDATE m_loan_recalculation_details lrd SET lrd.compounding_frequency_on_day = DAYOFMONTH(lrd.compounding_freqency_date) WHERE lrd.compounding_frequency_type_enum = 4 AND lrd.compounding_freqency_date IS NOT NULL;
|
||||
|
||||
|
||||
UPDATE m_product_loan_recalculation_details plr SET plr.rest_frequency_weekday_enum = (WEEKDAY(plr.rest_freqency_date) + 1) WHERE plr.rest_frequency_type_enum = 3 AND plr.rest_freqency_date IS NOT NULL;
|
||||
|
||||
|
||||
UPDATE m_product_loan_recalculation_details plr SET plr.rest_frequency_on_day = DAYOFMONTH(plr.rest_freqency_date) WHERE plr.rest_frequency_type_enum = 4 AND plr.rest_freqency_date IS NOT NULL;
|
||||
|
||||
|
||||
UPDATE m_loan_recalculation_details lrd SET lrd.rest_frequency_weekday_enum = (WEEKDAY(lrd.rest_freqency_date) + 1) WHERE lrd.rest_frequency_type_enum = 3 AND lrd.rest_freqency_date IS NOT NULL;
|
||||
|
||||
|
||||
UPDATE m_loan_recalculation_details lrd SET lrd.rest_frequency_on_day = DAYOFMONTH(lrd.rest_freqency_date) WHERE lrd.rest_frequency_type_enum = 4 AND lrd.rest_freqency_date IS NOT NULL;
|
||||
|
||||
|
||||
ALTER TABLE `m_product_loan_recalculation_details` DROP `rest_freqency_date`, DROP `compounding_freqency_date`;
|
||||
|
||||
|
||||
ALTER TABLE `m_loan_recalculation_details` DROP `rest_freqency_date`, DROP `compounding_freqency_date`;
|
||||
|
||||
|
||||
ALTER TABLE `job`
|
||||
CHANGE COLUMN `name` `name` VARCHAR(100) NOT NULL AFTER `id`,
|
||||
CHANGE COLUMN `display_name` `display_name` VARCHAR(100) NOT NULL AFTER `name`;
|
||||
|
||||
INSERT INTO `job` (`name`, `display_name`, `cron_expression`, `create_time`, `task_priority`, `group_name`, `previous_run_start_time`, `next_run_time`, `job_key`, `initializing_errorlog`, `is_active`, `currently_running`, `updates_allowed`, `scheduler_group`, `is_misfired`) VALUES ('Add Accrual Transactions For Loans With Income Posted As Transactions', 'Add Accrual Transactions For Loans With Income Posted As Transactions', '0 1 0 1/1 * ? *', now(), 5, NULL, NULL, NULL, NULL, NULL, 1, 0, 1, 3, 0);
|
||||
|
||||
UPDATE `job` SET `task_priority`=6 WHERE `name`='Update Non Performing Assets';
|
||||
+5
-1
@@ -18,9 +18,12 @@
|
||||
*/
|
||||
package org.apache.fineract.portfolio.loanaccount;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
import org.apache.fineract.organisation.monetary.domain.MonetaryCurrency;
|
||||
import org.apache.fineract.organisation.monetary.domain.Money;
|
||||
import org.apache.fineract.portfolio.loanaccount.domain.Loan;
|
||||
import org.apache.fineract.portfolio.loanaccount.domain.LoanInterestRecalcualtionAdditionalDetails;
|
||||
import org.apache.fineract.portfolio.loanaccount.domain.LoanRepaymentScheduleInstallment;
|
||||
import org.joda.time.LocalDate;
|
||||
|
||||
@@ -46,9 +49,10 @@ public class LoanRepaymentScheduleInstallmentBuilder {
|
||||
}
|
||||
|
||||
public LoanRepaymentScheduleInstallment build() {
|
||||
final List<LoanInterestRecalcualtionAdditionalDetails> compoundingDetails = null;
|
||||
final LoanRepaymentScheduleInstallment installment = new LoanRepaymentScheduleInstallment(this.loan, this.installmentNumber,
|
||||
this.fromDate, this.dueDate, this.principal.getAmount(), this.interest.getAmount(), this.feeCharges.getAmount(),
|
||||
this.penaltyCharges.getAmount(), this.recalculatedInterestComponent);
|
||||
this.penaltyCharges.getAmount(), this.recalculatedInterestComponent, compoundingDetails);
|
||||
if (this.completed) {
|
||||
installment.payPrincipalComponent(this.latestTransactionDate, this.principal);
|
||||
installment.payInterestComponent(this.latestTransactionDate, this.interest);
|
||||
|
||||
Reference in New Issue
Block a user