From 8da0842f8799cbab97d7a81ade5e839a034015d6 Mon Sep 17 00:00:00 2001 From: mariiaKraievska Date: Tue, 9 Sep 2025 00:38:14 +0300 Subject: [PATCH] FINERACT-2348: Refactor Capitalized income / Buydown fee amortization allocation calculation --- .../features/LoanBuyDownFees.feature | 220 +++++++++++++++++- .../features/LoanCapitalizedIncome.feature | 218 +++++++++++++++++ ...ortizationAllocationMappingRepository.java | 31 ++- .../LoanAmortizationAllocationService.java | 2 + ...LoanAmortizationAllocationServiceImpl.java | 5 + ...nFeeAmortizationProcessingServiceImpl.java | 63 +---- ...comeAmortizationProcessingServiceImpl.java | 63 +---- 7 files changed, 490 insertions(+), 112 deletions(-) diff --git a/fineract-e2e-tests-runner/src/test/resources/features/LoanBuyDownFees.feature b/fineract-e2e-tests-runner/src/test/resources/features/LoanBuyDownFees.feature index e1b86ba3e..e8d59eb8a 100644 --- a/fineract-e2e-tests-runner/src/test/resources/features/LoanBuyDownFees.feature +++ b/fineract-e2e-tests-runner/src/test/resources/features/LoanBuyDownFees.feature @@ -3553,4 +3553,222 @@ Feature:Feature: Buy Down Fees | 03 January 2024 | AM | 1.11 | | 04 January 2024 | AM | 1.11 | | 05 January 2024 | AM_ADJ | 0.25 | - | 06 January 2024 | AM | 0.43 | \ No newline at end of file + | 06 January 2024 | AM | 0.43 | + + @TestRailId:C4040 + Scenario: Verify Buy Down Fee amortization allocation mapping when already amortized amount is greater than should be after buy down fee adjustment + When Admin sets the business date to "1 January 2024" + And Admin creates a client with random data + When Admin creates a fully customized loan with the following data: + | LoanProduct | submitted on date | with Principal | ANNUAL interest rate % | interest type | interest calculation period | amortization type | loanTermFrequency | loanTermFrequencyType | repaymentEvery | repaymentFrequencyType | numberOfRepayments | graceOnPrincipalPayment | graceOnInterestPayment | interest free period | Payment strategy | + | LP2_PROGRESSIVE_ADVANCED_PAYMENT_ALLOCATION_BUYDOWN_FEES | 01 January 2024 | 100 | 7 | DECLINING_BALANCE | DAILY | EQUAL_INSTALLMENTS | 30 | DAYS | 1 | DAYS | 30 | 0 | 0 | 0 | ADVANCED_PAYMENT_ALLOCATION | + And Admin successfully approves the loan on "1 January 2024" with "100" amount and expected disbursement date on "1 January 2024" + And Admin successfully disburse the loan on "1 January 2024" with "100" EUR transaction amount + Then Loan status will be "ACTIVE" + And Admin runs inline COB job for Loan + And Admin adds buy down fee with "AUTOPAY" payment type to the loan on "1 January 2024" with "1" EUR transaction amount + When Admin sets the business date to "15 January 2024" + And Admin runs inline COB job for Loan + And Loan Amortization Allocation Mapping for "BUY_DOWN_FEE" transaction created on "01 January 2024" contains the following data: + | Date | Type | Amount | + | 01 January 2024 | AM | 0.03 | + | 02 January 2024 | AM | 0.04 | + | 03 January 2024 | AM | 0.03 | + | 04 January 2024 | AM | 0.03 | + | 05 January 2024 | AM | 0.04 | + | 06 January 2024 | AM | 0.03 | + | 07 January 2024 | AM | 0.03 | + | 08 January 2024 | AM | 0.04 | + | 09 January 2024 | AM | 0.03 | + | 10 January 2024 | AM | 0.03 | + | 11 January 2024 | AM | 0.04 | + | 12 January 2024 | AM | 0.03 | + | 13 January 2024 | AM | 0.03 | + | 14 January 2024 | AM | 0.04 | + And Buy down fee by external-id contains the following data: + | Date | Fee Amount | Amortized Amount | Not Yet Amortized Amount | Adjusted Amount | Charged Off Amount | + | 01 January 2024 | 1.0 | 0.47 | 0.53 | 0.0 | 0.0 | + And Admin adds buy down fee adjustment with "AUTOPAY" payment type to the loan on "15 January 2024" with "0.7" EUR transaction amount + When Admin sets the business date to "16 January 2024" + And Admin runs inline COB job for Loan + And Loan Amortization Allocation Mapping for "BUY_DOWN_FEE" transaction created on "01 January 2024" contains the following data: + | Date | Type | Amount | + | 01 January 2024 | AM | 0.03 | + | 02 January 2024 | AM | 0.04 | + | 03 January 2024 | AM | 0.03 | + | 04 January 2024 | AM | 0.03 | + | 05 January 2024 | AM | 0.04 | + | 06 January 2024 | AM | 0.03 | + | 07 January 2024 | AM | 0.03 | + | 08 January 2024 | AM | 0.04 | + | 09 January 2024 | AM | 0.03 | + | 10 January 2024 | AM | 0.03 | + | 11 January 2024 | AM | 0.04 | + | 12 January 2024 | AM | 0.03 | + | 13 January 2024 | AM | 0.03 | + | 14 January 2024 | AM | 0.04 | + | 15 January 2024 | AM_ADJ | 0.17 | + And Buy down fee by external-id contains the following data: + | Date | Fee Amount | Amortized Amount | Not Yet Amortized Amount | Adjusted Amount | Charged Off Amount | + | 01 January 2024 | 1.0 | 0.3 | 0.0 | 0.7 | 0.0 | + When Admin sets the business date to "25 January 2024" + And Admin runs inline COB job for Loan + And Loan Amortization Allocation Mapping for "BUY_DOWN_FEE" transaction created on "01 January 2024" contains the following data: + | Date | Type | Amount | + | 01 January 2024 | AM | 0.03 | + | 02 January 2024 | AM | 0.04 | + | 03 January 2024 | AM | 0.03 | + | 04 January 2024 | AM | 0.03 | + | 05 January 2024 | AM | 0.04 | + | 06 January 2024 | AM | 0.03 | + | 07 January 2024 | AM | 0.03 | + | 08 January 2024 | AM | 0.04 | + | 09 January 2024 | AM | 0.03 | + | 10 January 2024 | AM | 0.03 | + | 11 January 2024 | AM | 0.04 | + | 12 January 2024 | AM | 0.03 | + | 13 January 2024 | AM | 0.03 | + | 14 January 2024 | AM | 0.04 | + | 15 January 2024 | AM_ADJ | 0.17 | + And Buy down fee by external-id contains the following data: + | Date | Fee Amount | Amortized Amount | Not Yet Amortized Amount | Adjusted Amount | Charged Off Amount | + | 01 January 2024 | 1.0 | 0.3 | 0.0 | 0.7 | 0.0 | + + @TestRailId:C4043 + Scenario: Verify Buy Down Fee amortization allocation mapping when after buy down fee adjustment and charge-off + When Admin sets the business date to "1 January 2024" + And Admin creates a client with random data + When Admin creates a fully customized loan with the following data: + | LoanProduct | submitted on date | with Principal | ANNUAL interest rate % | interest type | interest calculation period | amortization type | loanTermFrequency | loanTermFrequencyType | repaymentEvery | repaymentFrequencyType | numberOfRepayments | graceOnPrincipalPayment | graceOnInterestPayment | interest free period | Payment strategy | + | LP2_PROGRESSIVE_ADVANCED_PAYMENT_ALLOCATION_BUYDOWN_FEES | 01 January 2024 | 100 | 7 | DECLINING_BALANCE | DAILY | EQUAL_INSTALLMENTS | 30 | DAYS | 1 | DAYS | 30 | 0 | 0 | 0 | ADVANCED_PAYMENT_ALLOCATION | + And Admin successfully approves the loan on "1 January 2024" with "100" amount and expected disbursement date on "1 January 2024" + And Admin successfully disburse the loan on "1 January 2024" with "100" EUR transaction amount + Then Loan status will be "ACTIVE" + And Admin runs inline COB job for Loan + And Admin adds buy down fee with "AUTOPAY" payment type to the loan on "1 January 2024" with "1" EUR transaction amount + Then Loan Transactions tab has the following data: + | Transaction date | Transaction Type | Amount | Principal | Interest | Fees | Penalties | Loan Balance | Reverted | + | 01 January 2024 | Disbursement | 100.0 | 0.0 | 0.0 | 0.0 | 0.0 | 100.0 | false | + | 01 January 2024 | Buy Down Fee | 1.0 | 0.0 | 0.0 | 0.0 | 0.0 | 0.0 | false | + When Admin sets the business date to "15 January 2024" + And Admin runs inline COB job for Loan + And Admin adds buy down fee adjustment with "AUTOPAY" payment type to the loan on "15 January 2024" with "0.3" EUR transaction amount + When Admin sets the business date to "16 January 2024" + And Admin runs inline COB job for Loan + Then Loan Transactions tab has the following data: + | Transaction date | Transaction Type | Amount | Principal | Interest | Fees | Penalties | Loan Balance | Reverted | + | 01 January 2024 | Disbursement | 100.0 | 0.0 | 0.0 | 0.0 | 0.0 | 100.0 | false | + | 01 January 2024 | Buy Down Fee | 1.0 | 0.0 | 0.0 | 0.0 | 0.0 | 0.0 | false | + | 01 January 2024 | Buy Down Fee Amortization | 0.03 | 0.0 | 0.03 | 0.0 | 0.0 | 0.0 | false | + | 02 January 2024 | Accrual | 0.02 | 0.0 | 0.02 | 0.0 | 0.0 | 0.0 | false | + | 02 January 2024 | Buy Down Fee Amortization | 0.04 | 0.0 | 0.04 | 0.0 | 0.0 | 0.0 | false | + | 03 January 2024 | Accrual | 0.02 | 0.0 | 0.02 | 0.0 | 0.0 | 0.0 | false | + | 03 January 2024 | Buy Down Fee Amortization | 0.03 | 0.0 | 0.03 | 0.0 | 0.0 | 0.0 | false | + | 04 January 2024 | Accrual | 0.02 | 0.0 | 0.02 | 0.0 | 0.0 | 0.0 | false | + | 04 January 2024 | Buy Down Fee Amortization | 0.03 | 0.0 | 0.03 | 0.0 | 0.0 | 0.0 | false | + | 05 January 2024 | Accrual | 0.02 | 0.0 | 0.02 | 0.0 | 0.0 | 0.0 | false | + | 05 January 2024 | Buy Down Fee Amortization | 0.04 | 0.0 | 0.04 | 0.0 | 0.0 | 0.0 | false | + | 06 January 2024 | Accrual | 0.02 | 0.0 | 0.02 | 0.0 | 0.0 | 0.0 | false | + | 06 January 2024 | Buy Down Fee Amortization | 0.03 | 0.0 | 0.03 | 0.0 | 0.0 | 0.0 | false | + | 07 January 2024 | Accrual | 0.02 | 0.0 | 0.02 | 0.0 | 0.0 | 0.0 | false | + | 07 January 2024 | Buy Down Fee Amortization | 0.03 | 0.0 | 0.03 | 0.0 | 0.0 | 0.0 | false | + | 08 January 2024 | Accrual | 0.02 | 0.0 | 0.02 | 0.0 | 0.0 | 0.0 | false | + | 08 January 2024 | Buy Down Fee Amortization | 0.04 | 0.0 | 0.04 | 0.0 | 0.0 | 0.0 | false | + | 09 January 2024 | Accrual | 0.02 | 0.0 | 0.02 | 0.0 | 0.0 | 0.0 | false | + | 09 January 2024 | Buy Down Fee Amortization | 0.03 | 0.0 | 0.03 | 0.0 | 0.0 | 0.0 | false | + | 10 January 2024 | Accrual | 0.02 | 0.0 | 0.02 | 0.0 | 0.0 | 0.0 | false | + | 10 January 2024 | Buy Down Fee Amortization | 0.03 | 0.0 | 0.03 | 0.0 | 0.0 | 0.0 | false | + | 11 January 2024 | Accrual | 0.02 | 0.0 | 0.02 | 0.0 | 0.0 | 0.0 | false | + | 11 January 2024 | Buy Down Fee Amortization | 0.04 | 0.0 | 0.04 | 0.0 | 0.0 | 0.0 | false | + | 12 January 2024 | Accrual | 0.02 | 0.0 | 0.02 | 0.0 | 0.0 | 0.0 | false | + | 12 January 2024 | Buy Down Fee Amortization | 0.03 | 0.0 | 0.03 | 0.0 | 0.0 | 0.0 | false | + | 13 January 2024 | Accrual | 0.02 | 0.0 | 0.02 | 0.0 | 0.0 | 0.0 | false | + | 13 January 2024 | Buy Down Fee Amortization | 0.03 | 0.0 | 0.03 | 0.0 | 0.0 | 0.0 | false | + | 14 January 2024 | Accrual | 0.02 | 0.0 | 0.02 | 0.0 | 0.0 | 0.0 | false | + | 14 January 2024 | Buy Down Fee Amortization | 0.04 | 0.0 | 0.04 | 0.0 | 0.0 | 0.0 | false | + | 15 January 2024 | Buy Down Fee Adjustment | 0.3 | 0.0 | 0.0 | 0.0 | 0.0 | 0.0 | false | + | 15 January 2024 | Accrual | 0.02 | 0.0 | 0.02 | 0.0 | 0.0 | 0.0 | false | + | 15 January 2024 | Buy Down Fee Amortization | 0.01 | 0.0 | 0.01 | 0.0 | 0.0 | 0.0 | false | + And Loan Amortization Allocation Mapping for "BUY_DOWN_FEE" transaction created on "01 January 2024" contains the following data: + | Date | Type | Amount | + | 01 January 2024 | AM | 0.03 | + | 02 January 2024 | AM | 0.04 | + | 03 January 2024 | AM | 0.03 | + | 04 January 2024 | AM | 0.03 | + | 05 January 2024 | AM | 0.04 | + | 06 January 2024 | AM | 0.03 | + | 07 January 2024 | AM | 0.03 | + | 08 January 2024 | AM | 0.04 | + | 09 January 2024 | AM | 0.03 | + | 10 January 2024 | AM | 0.03 | + | 11 January 2024 | AM | 0.04 | + | 12 January 2024 | AM | 0.03 | + | 13 January 2024 | AM | 0.03 | + | 14 January 2024 | AM | 0.04 | + | 15 January 2024 | AM | 0.01 | + And Buy down fee by external-id contains the following data: + | Date | Fee Amount | Amortized Amount | Not Yet Amortized Amount | Adjusted Amount | Charged Off Amount | + | 01 January 2024 | 1.0 | 0.48 | 0.22 | 0.3 | 0.0 | + And Admin does charge-off the loan on "16 January 2024" + Then Loan status will be "ACTIVE" + And Loan marked as charged-off on "16 January 2024" + Then Loan Transactions tab has the following data: + | Transaction date | Transaction Type | Amount | Principal | Interest | Fees | Penalties | Loan Balance | Reverted | + | 01 January 2024 | Disbursement | 100.0 | 0.0 | 0.0 | 0.0 | 0.0 | 100.0 | false | + | 01 January 2024 | Buy Down Fee | 1.0 | 0.0 | 0.0 | 0.0 | 0.0 | 0.0 | false | + | 01 January 2024 | Buy Down Fee Amortization | 0.03 | 0.0 | 0.03 | 0.0 | 0.0 | 0.0 | false | + | 02 January 2024 | Accrual | 0.02 | 0.0 | 0.02 | 0.0 | 0.0 | 0.0 | false | + | 02 January 2024 | Buy Down Fee Amortization | 0.04 | 0.0 | 0.04 | 0.0 | 0.0 | 0.0 | false | + | 03 January 2024 | Accrual | 0.02 | 0.0 | 0.02 | 0.0 | 0.0 | 0.0 | false | + | 03 January 2024 | Buy Down Fee Amortization | 0.03 | 0.0 | 0.03 | 0.0 | 0.0 | 0.0 | false | + | 04 January 2024 | Accrual | 0.02 | 0.0 | 0.02 | 0.0 | 0.0 | 0.0 | false | + | 04 January 2024 | Buy Down Fee Amortization | 0.03 | 0.0 | 0.03 | 0.0 | 0.0 | 0.0 | false | + | 05 January 2024 | Accrual | 0.02 | 0.0 | 0.02 | 0.0 | 0.0 | 0.0 | false | + | 05 January 2024 | Buy Down Fee Amortization | 0.04 | 0.0 | 0.04 | 0.0 | 0.0 | 0.0 | false | + | 06 January 2024 | Accrual | 0.02 | 0.0 | 0.02 | 0.0 | 0.0 | 0.0 | false | + | 06 January 2024 | Buy Down Fee Amortization | 0.03 | 0.0 | 0.03 | 0.0 | 0.0 | 0.0 | false | + | 07 January 2024 | Accrual | 0.02 | 0.0 | 0.02 | 0.0 | 0.0 | 0.0 | false | + | 07 January 2024 | Buy Down Fee Amortization | 0.03 | 0.0 | 0.03 | 0.0 | 0.0 | 0.0 | false | + | 08 January 2024 | Accrual | 0.02 | 0.0 | 0.02 | 0.0 | 0.0 | 0.0 | false | + | 08 January 2024 | Buy Down Fee Amortization | 0.04 | 0.0 | 0.04 | 0.0 | 0.0 | 0.0 | false | + | 09 January 2024 | Accrual | 0.02 | 0.0 | 0.02 | 0.0 | 0.0 | 0.0 | false | + | 09 January 2024 | Buy Down Fee Amortization | 0.03 | 0.0 | 0.03 | 0.0 | 0.0 | 0.0 | false | + | 10 January 2024 | Accrual | 0.02 | 0.0 | 0.02 | 0.0 | 0.0 | 0.0 | false | + | 10 January 2024 | Buy Down Fee Amortization | 0.03 | 0.0 | 0.03 | 0.0 | 0.0 | 0.0 | false | + | 11 January 2024 | Accrual | 0.02 | 0.0 | 0.02 | 0.0 | 0.0 | 0.0 | false | + | 11 January 2024 | Buy Down Fee Amortization | 0.04 | 0.0 | 0.04 | 0.0 | 0.0 | 0.0 | false | + | 12 January 2024 | Accrual | 0.02 | 0.0 | 0.02 | 0.0 | 0.0 | 0.0 | false | + | 12 January 2024 | Buy Down Fee Amortization | 0.03 | 0.0 | 0.03 | 0.0 | 0.0 | 0.0 | false | + | 13 January 2024 | Accrual | 0.02 | 0.0 | 0.02 | 0.0 | 0.0 | 0.0 | false | + | 13 January 2024 | Buy Down Fee Amortization | 0.03 | 0.0 | 0.03 | 0.0 | 0.0 | 0.0 | false | + | 14 January 2024 | Accrual | 0.02 | 0.0 | 0.02 | 0.0 | 0.0 | 0.0 | false | + | 14 January 2024 | Buy Down Fee Amortization | 0.04 | 0.0 | 0.04 | 0.0 | 0.0 | 0.0 | false | + | 15 January 2024 | Buy Down Fee Adjustment | 0.3 | 0.0 | 0.0 | 0.0 | 0.0 | 0.0 | false | + | 15 January 2024 | Accrual | 0.02 | 0.0 | 0.02 | 0.0 | 0.0 | 0.0 | false | + | 15 January 2024 | Buy Down Fee Amortization | 0.01 | 0.0 | 0.01 | 0.0 | 0.0 | 0.0 | false | + | 16 January 2024 | Accrual | 0.02 | 0.0 | 0.02 | 0.0 | 0.0 | 0.0 | false | + | 16 January 2024 | Buy Down Fee Amortization | 0.02 | 0.0 | 0.02 | 0.0 | 0.0 | 0.0 | false | + | 16 January 2024 | Charge-off | 100.38 | 100.0 | 0.38 | 0.0 | 0.0 | 0.0 | false | + | 16 January 2024 | Buy Down Fee Amortization | 0.2 | 0.0 | 0.2 | 0.0 | 0.0 | 0.0 | false | + And Loan Amortization Allocation Mapping for "BUY_DOWN_FEE" transaction created on "01 January 2024" contains the following data: + | Date | Type | Amount | + | 01 January 2024 | AM | 0.03 | + | 02 January 2024 | AM | 0.04 | + | 03 January 2024 | AM | 0.03 | + | 04 January 2024 | AM | 0.03 | + | 05 January 2024 | AM | 0.04 | + | 06 January 2024 | AM | 0.03 | + | 07 January 2024 | AM | 0.03 | + | 08 January 2024 | AM | 0.04 | + | 09 January 2024 | AM | 0.03 | + | 10 January 2024 | AM | 0.03 | + | 11 January 2024 | AM | 0.04 | + | 12 January 2024 | AM | 0.03 | + | 13 January 2024 | AM | 0.03 | + | 14 January 2024 | AM | 0.04 | + | 15 January 2024 | AM | 0.01 | + | 16 January 2024 | AM | 0.02 | + | 16 January 2024 | AM | 0.2 | + And Buy down fee by external-id contains the following data: + | Date | Fee Amount | Amortized Amount | Not Yet Amortized Amount | Adjusted Amount | Charged Off Amount | + | 01 January 2024 | 1.0 | 0.5 | 0.0 | 0.3 | 0.2 | \ No newline at end of file diff --git a/fineract-e2e-tests-runner/src/test/resources/features/LoanCapitalizedIncome.feature b/fineract-e2e-tests-runner/src/test/resources/features/LoanCapitalizedIncome.feature index b539eef60..814605733 100644 --- a/fineract-e2e-tests-runner/src/test/resources/features/LoanCapitalizedIncome.feature +++ b/fineract-e2e-tests-runner/src/test/resources/features/LoanCapitalizedIncome.feature @@ -7883,3 +7883,221 @@ Feature: Capitalized Income | 04 January 2024 | AM | 1.11 | | 05 January 2024 | AM_ADJ | 0.25 | | 06 January 2024 | AM | 0.43 | + + @TestRailId:C4041 + Scenario: Verify Capitalized Income amortization allocation mapping when already amortized amount is greater than should be after capitalized income adjustment + When Admin sets the business date to "1 January 2024" + And Admin creates a client with random data + When Admin creates a fully customized loan with the following data: + | LoanProduct | submitted on date | with Principal | ANNUAL interest rate % | interest type | interest calculation period | amortization type | loanTermFrequency | loanTermFrequencyType | repaymentEvery | repaymentFrequencyType | numberOfRepayments | graceOnPrincipalPayment | graceOnInterestPayment | interest free period | Payment strategy | + | LP2_ADV_PYMNT_INTEREST_DAILY_EMI_360_30_INTEREST_RECALC_DAILY_CAPITALIZED_INCOME_ADJ_CUSTOM_ALLOC | 01 January 2024 | 200 | 7 | DECLINING_BALANCE | DAILY | EQUAL_INSTALLMENTS | 30 | DAYS | 1 | DAYS | 30 | 0 | 0 | 0 | ADVANCED_PAYMENT_ALLOCATION | + And Admin successfully approves the loan on "1 January 2024" with "200" amount and expected disbursement date on "1 January 2024" + And Admin successfully disburse the loan on "1 January 2024" with "100" EUR transaction amount + Then Loan status will be "ACTIVE" + And Admin runs inline COB job for Loan + And Admin adds capitalized income with "AUTOPAY" payment type to the loan on "1 January 2024" with "1" EUR transaction amount + When Admin sets the business date to "15 January 2024" + And Admin runs inline COB job for Loan + And Loan Amortization Allocation Mapping for "CAPITALIZED_INCOME" transaction created on "01 January 2024" contains the following data: + | Date | Type | Amount | + | 01 January 2024 | AM | 0.03 | + | 02 January 2024 | AM | 0.04 | + | 03 January 2024 | AM | 0.03 | + | 04 January 2024 | AM | 0.03 | + | 05 January 2024 | AM | 0.04 | + | 06 January 2024 | AM | 0.03 | + | 07 January 2024 | AM | 0.03 | + | 08 January 2024 | AM | 0.04 | + | 09 January 2024 | AM | 0.03 | + | 10 January 2024 | AM | 0.03 | + | 11 January 2024 | AM | 0.04 | + | 12 January 2024 | AM | 0.03 | + | 13 January 2024 | AM | 0.03 | + | 14 January 2024 | AM | 0.04 | + And Deferred Capitalized Income by external-id contains the following data: + | Amount | Amortized Amount | Unrecognized Amount | Adjusted Amount | Charged Off Amount | + | 1.0 | 0.47 | 0.53 | 0.0 | 0.0 | + And Admin adds capitalized income adjustment with "AUTOPAY" payment type to the loan on "15 January 2024" with "0.7" EUR transaction amount + When Admin sets the business date to "16 January 2024" + And Admin runs inline COB job for Loan + And Loan Amortization Allocation Mapping for "CAPITALIZED_INCOME" transaction created on "01 January 2024" contains the following data: + | Date | Type | Amount | + | 01 January 2024 | AM | 0.03 | + | 02 January 2024 | AM | 0.04 | + | 03 January 2024 | AM | 0.03 | + | 04 January 2024 | AM | 0.03 | + | 05 January 2024 | AM | 0.04 | + | 06 January 2024 | AM | 0.03 | + | 07 January 2024 | AM | 0.03 | + | 08 January 2024 | AM | 0.04 | + | 09 January 2024 | AM | 0.03 | + | 10 January 2024 | AM | 0.03 | + | 11 January 2024 | AM | 0.04 | + | 12 January 2024 | AM | 0.03 | + | 13 January 2024 | AM | 0.03 | + | 14 January 2024 | AM | 0.04 | + | 15 January 2024 | AM_ADJ | 0.17 | + And Deferred Capitalized Income by external-id contains the following data: + | Amount | Amortized Amount | Unrecognized Amount | Adjusted Amount | Charged Off Amount | + | 1.0 | 0.3 | 0.0 | 0.7 | 0.0 | + When Admin sets the business date to "25 January 2024" + And Admin runs inline COB job for Loan + And Loan Amortization Allocation Mapping for "CAPITALIZED_INCOME" transaction created on "01 January 2024" contains the following data: + | Date | Type | Amount | + | 01 January 2024 | AM | 0.03 | + | 02 January 2024 | AM | 0.04 | + | 03 January 2024 | AM | 0.03 | + | 04 January 2024 | AM | 0.03 | + | 05 January 2024 | AM | 0.04 | + | 06 January 2024 | AM | 0.03 | + | 07 January 2024 | AM | 0.03 | + | 08 January 2024 | AM | 0.04 | + | 09 January 2024 | AM | 0.03 | + | 10 January 2024 | AM | 0.03 | + | 11 January 2024 | AM | 0.04 | + | 12 January 2024 | AM | 0.03 | + | 13 January 2024 | AM | 0.03 | + | 14 January 2024 | AM | 0.04 | + | 15 January 2024 | AM_ADJ | 0.17 | + And Deferred Capitalized Income by external-id contains the following data: + | Amount | Amortized Amount | Unrecognized Amount | Adjusted Amount | Charged Off Amount | + | 1.0 | 0.3 | 0.0 | 0.7 | 0.0 | + + @TestRailId:C4042 + Scenario: Verify Capitalized Income amortization allocation mapping when after capitalized income adjustment and charge-off + When Admin sets the business date to "1 January 2024" + And Admin creates a client with random data + When Admin creates a fully customized loan with the following data: + | LoanProduct | submitted on date | with Principal | ANNUAL interest rate % | interest type | interest calculation period | amortization type | loanTermFrequency | loanTermFrequencyType | repaymentEvery | repaymentFrequencyType | numberOfRepayments | graceOnPrincipalPayment | graceOnInterestPayment | interest free period | Payment strategy | + | LP2_ADV_PYMNT_INTEREST_DAILY_EMI_360_30_INTEREST_RECALC_DAILY_CAPITALIZED_INCOME_ADJ_CUSTOM_ALLOC | 01 January 2024 | 200 | 7 | DECLINING_BALANCE | DAILY | EQUAL_INSTALLMENTS | 30 | DAYS | 1 | DAYS | 30 | 0 | 0 | 0 | ADVANCED_PAYMENT_ALLOCATION | + And Admin successfully approves the loan on "1 January 2024" with "200" amount and expected disbursement date on "1 January 2024" + And Admin successfully disburse the loan on "1 January 2024" with "100" EUR transaction amount + Then Loan status will be "ACTIVE" + And Admin runs inline COB job for Loan + And Admin adds capitalized income with "AUTOPAY" payment type to the loan on "1 January 2024" with "1" EUR transaction amount + Then Loan Transactions tab has the following data: + | Transaction date | Transaction Type | Amount | Principal | Interest | Fees | Penalties | Loan Balance | Reverted | + | 01 January 2024 | Disbursement | 100.0 | 0.0 | 0.0 | 0.0 | 0.0 | 100.0 | false | + | 01 January 2024 | Capitalized Income | 1.0 | 1.0 | 0.0 | 0.0 | 0.0 | 101.0 | false | + When Admin sets the business date to "15 January 2024" + And Admin runs inline COB job for Loan + And Admin adds capitalized income adjustment with "AUTOPAY" payment type to the loan on "15 January 2024" with "0.3" EUR transaction amount + When Admin sets the business date to "16 January 2024" + And Admin runs inline COB job for Loan + Then Loan Transactions tab has the following data: + | Transaction date | Transaction Type | Amount | Principal | Interest | Fees | Penalties | Loan Balance | Reverted | + | 01 January 2024 | Disbursement | 100.0 | 0.0 | 0.0 | 0.0 | 0.0 | 100.0 | false | + | 01 January 2024 | Capitalized Income | 1.0 | 1.0 | 0.0 | 0.0 | 0.0 | 101.0 | false | + | 01 January 2024 | Capitalized Income Amortization | 0.03 | 0.0 | 0.03 | 0.0 | 0.0 | 0.0 | false | + | 02 January 2024 | Accrual | 0.02 | 0.0 | 0.02 | 0.0 | 0.0 | 0.0 | false | + | 02 January 2024 | Capitalized Income Amortization | 0.04 | 0.0 | 0.04 | 0.0 | 0.0 | 0.0 | false | + | 03 January 2024 | Accrual | 0.02 | 0.0 | 0.02 | 0.0 | 0.0 | 0.0 | false | + | 03 January 2024 | Capitalized Income Amortization | 0.03 | 0.0 | 0.03 | 0.0 | 0.0 | 0.0 | false | + | 04 January 2024 | Accrual | 0.02 | 0.0 | 0.02 | 0.0 | 0.0 | 0.0 | false | + | 04 January 2024 | Capitalized Income Amortization | 0.03 | 0.0 | 0.03 | 0.0 | 0.0 | 0.0 | false | + | 05 January 2024 | Accrual | 0.02 | 0.0 | 0.02 | 0.0 | 0.0 | 0.0 | false | + | 05 January 2024 | Capitalized Income Amortization | 0.04 | 0.0 | 0.04 | 0.0 | 0.0 | 0.0 | false | + | 06 January 2024 | Accrual | 0.02 | 0.0 | 0.02 | 0.0 | 0.0 | 0.0 | false | + | 06 January 2024 | Capitalized Income Amortization | 0.03 | 0.0 | 0.03 | 0.0 | 0.0 | 0.0 | false | + | 07 January 2024 | Accrual | 0.02 | 0.0 | 0.02 | 0.0 | 0.0 | 0.0 | false | + | 07 January 2024 | Capitalized Income Amortization | 0.03 | 0.0 | 0.03 | 0.0 | 0.0 | 0.0 | false | + | 08 January 2024 | Accrual | 0.02 | 0.0 | 0.02 | 0.0 | 0.0 | 0.0 | false | + | 08 January 2024 | Capitalized Income Amortization | 0.04 | 0.0 | 0.04 | 0.0 | 0.0 | 0.0 | false | + | 09 January 2024 | Accrual | 0.02 | 0.0 | 0.02 | 0.0 | 0.0 | 0.0 | false | + | 09 January 2024 | Capitalized Income Amortization | 0.03 | 0.0 | 0.03 | 0.0 | 0.0 | 0.0 | false | + | 10 January 2024 | Accrual | 0.02 | 0.0 | 0.02 | 0.0 | 0.0 | 0.0 | false | + | 10 January 2024 | Capitalized Income Amortization | 0.03 | 0.0 | 0.03 | 0.0 | 0.0 | 0.0 | false | + | 11 January 2024 | Accrual | 0.02 | 0.0 | 0.02 | 0.0 | 0.0 | 0.0 | false | + | 11 January 2024 | Capitalized Income Amortization | 0.04 | 0.0 | 0.04 | 0.0 | 0.0 | 0.0 | false | + | 12 January 2024 | Accrual | 0.02 | 0.0 | 0.02 | 0.0 | 0.0 | 0.0 | false | + | 12 January 2024 | Capitalized Income Amortization | 0.03 | 0.0 | 0.03 | 0.0 | 0.0 | 0.0 | false | + | 13 January 2024 | Accrual | 0.02 | 0.0 | 0.02 | 0.0 | 0.0 | 0.0 | false | + | 13 January 2024 | Capitalized Income Amortization | 0.03 | 0.0 | 0.03 | 0.0 | 0.0 | 0.0 | false | + | 14 January 2024 | Accrual | 0.02 | 0.0 | 0.02 | 0.0 | 0.0 | 0.0 | false | + | 14 January 2024 | Capitalized Income Amortization | 0.04 | 0.0 | 0.04 | 0.0 | 0.0 | 0.0 | false | + | 15 January 2024 | Capitalized Income Adjustment | 0.3 | 0.3 | 0.0 | 0.0 | 0.0 | 100.7 | false | + | 15 January 2024 | Accrual | 0.02 | 0.0 | 0.02 | 0.0 | 0.0 | 0.0 | false | + | 15 January 2024 | Capitalized Income Amortization | 0.01 | 0.0 | 0.01 | 0.0 | 0.0 | 0.0 | false | + And Loan Amortization Allocation Mapping for "CAPITALIZED_INCOME" transaction created on "01 January 2024" contains the following data: + | Date | Type | Amount | + | 01 January 2024 | AM | 0.03 | + | 02 January 2024 | AM | 0.04 | + | 03 January 2024 | AM | 0.03 | + | 04 January 2024 | AM | 0.03 | + | 05 January 2024 | AM | 0.04 | + | 06 January 2024 | AM | 0.03 | + | 07 January 2024 | AM | 0.03 | + | 08 January 2024 | AM | 0.04 | + | 09 January 2024 | AM | 0.03 | + | 10 January 2024 | AM | 0.03 | + | 11 January 2024 | AM | 0.04 | + | 12 January 2024 | AM | 0.03 | + | 13 January 2024 | AM | 0.03 | + | 14 January 2024 | AM | 0.04 | + | 15 January 2024 | AM | 0.01 | + And Deferred Capitalized Income by external-id contains the following data: + | Amount | Amortized Amount | Unrecognized Amount | Adjusted Amount | Charged Off Amount | + | 1.0 | 0.48 | 0.22 | 0.3 | 0.0 | + And Admin does charge-off the loan on "16 January 2024" + Then Loan status will be "ACTIVE" + And Loan marked as charged-off on "16 January 2024" + Then Loan Transactions tab has the following data: + | Transaction date | Transaction Type | Amount | Principal | Interest | Fees | Penalties | Loan Balance | Reverted | + | 01 January 2024 | Disbursement | 100.0 | 0.0 | 0.0 | 0.0 | 0.0 | 100.0 | false | + | 01 January 2024 | Capitalized Income | 1.0 | 1.0 | 0.0 | 0.0 | 0.0 | 101.0 | false | + | 01 January 2024 | Capitalized Income Amortization | 0.03 | 0.0 | 0.03 | 0.0 | 0.0 | 0.0 | false | + | 02 January 2024 | Accrual | 0.02 | 0.0 | 0.02 | 0.0 | 0.0 | 0.0 | false | + | 02 January 2024 | Capitalized Income Amortization | 0.04 | 0.0 | 0.04 | 0.0 | 0.0 | 0.0 | false | + | 03 January 2024 | Accrual | 0.02 | 0.0 | 0.02 | 0.0 | 0.0 | 0.0 | false | + | 03 January 2024 | Capitalized Income Amortization | 0.03 | 0.0 | 0.03 | 0.0 | 0.0 | 0.0 | false | + | 04 January 2024 | Accrual | 0.02 | 0.0 | 0.02 | 0.0 | 0.0 | 0.0 | false | + | 04 January 2024 | Capitalized Income Amortization | 0.03 | 0.0 | 0.03 | 0.0 | 0.0 | 0.0 | false | + | 05 January 2024 | Accrual | 0.02 | 0.0 | 0.02 | 0.0 | 0.0 | 0.0 | false | + | 05 January 2024 | Capitalized Income Amortization | 0.04 | 0.0 | 0.04 | 0.0 | 0.0 | 0.0 | false | + | 06 January 2024 | Accrual | 0.02 | 0.0 | 0.02 | 0.0 | 0.0 | 0.0 | false | + | 06 January 2024 | Capitalized Income Amortization | 0.03 | 0.0 | 0.03 | 0.0 | 0.0 | 0.0 | false | + | 07 January 2024 | Accrual | 0.02 | 0.0 | 0.02 | 0.0 | 0.0 | 0.0 | false | + | 07 January 2024 | Capitalized Income Amortization | 0.03 | 0.0 | 0.03 | 0.0 | 0.0 | 0.0 | false | + | 08 January 2024 | Accrual | 0.02 | 0.0 | 0.02 | 0.0 | 0.0 | 0.0 | false | + | 08 January 2024 | Capitalized Income Amortization | 0.04 | 0.0 | 0.04 | 0.0 | 0.0 | 0.0 | false | + | 09 January 2024 | Accrual | 0.02 | 0.0 | 0.02 | 0.0 | 0.0 | 0.0 | false | + | 09 January 2024 | Capitalized Income Amortization | 0.03 | 0.0 | 0.03 | 0.0 | 0.0 | 0.0 | false | + | 10 January 2024 | Accrual | 0.02 | 0.0 | 0.02 | 0.0 | 0.0 | 0.0 | false | + | 10 January 2024 | Capitalized Income Amortization | 0.03 | 0.0 | 0.03 | 0.0 | 0.0 | 0.0 | false | + | 11 January 2024 | Accrual | 0.02 | 0.0 | 0.02 | 0.0 | 0.0 | 0.0 | false | + | 11 January 2024 | Capitalized Income Amortization | 0.04 | 0.0 | 0.04 | 0.0 | 0.0 | 0.0 | false | + | 12 January 2024 | Accrual | 0.02 | 0.0 | 0.02 | 0.0 | 0.0 | 0.0 | false | + | 12 January 2024 | Capitalized Income Amortization | 0.03 | 0.0 | 0.03 | 0.0 | 0.0 | 0.0 | false | + | 13 January 2024 | Accrual | 0.02 | 0.0 | 0.02 | 0.0 | 0.0 | 0.0 | false | + | 13 January 2024 | Capitalized Income Amortization | 0.03 | 0.0 | 0.03 | 0.0 | 0.0 | 0.0 | false | + | 14 January 2024 | Accrual | 0.02 | 0.0 | 0.02 | 0.0 | 0.0 | 0.0 | false | + | 14 January 2024 | Capitalized Income Amortization | 0.04 | 0.0 | 0.04 | 0.0 | 0.0 | 0.0 | false | + | 15 January 2024 | Capitalized Income Adjustment | 0.3 | 0.3 | 0.0 | 0.0 | 0.0 | 100.7 | false | + | 15 January 2024 | Accrual | 0.02 | 0.0 | 0.02 | 0.0 | 0.0 | 0.0 | false | + | 15 January 2024 | Capitalized Income Amortization | 0.01 | 0.0 | 0.01 | 0.0 | 0.0 | 0.0 | false | + | 16 January 2024 | Accrual | 0.02 | 0.0 | 0.02 | 0.0 | 0.0 | 0.0 | false | + | 16 January 2024 | Capitalized Income Amortization | 0.02 | 0.0 | 0.02 | 0.0 | 0.0 | 0.0 | false | + | 16 January 2024 | Charge-off | 101.08 | 100.7 | 0.38 | 0.0 | 0.0 | 0.0 | false | + | 16 January 2024 | Capitalized Income Amortization | 0.2 | 0.0 | 0.2 | 0.0 | 0.0 | 0.0 | false | + And Loan Amortization Allocation Mapping for "CAPITALIZED_INCOME" transaction created on "01 January 2024" contains the following data: + | Date | Type | Amount | + | 01 January 2024 | AM | 0.03 | + | 02 January 2024 | AM | 0.04 | + | 03 January 2024 | AM | 0.03 | + | 04 January 2024 | AM | 0.03 | + | 05 January 2024 | AM | 0.04 | + | 06 January 2024 | AM | 0.03 | + | 07 January 2024 | AM | 0.03 | + | 08 January 2024 | AM | 0.04 | + | 09 January 2024 | AM | 0.03 | + | 10 January 2024 | AM | 0.03 | + | 11 January 2024 | AM | 0.04 | + | 12 January 2024 | AM | 0.03 | + | 13 January 2024 | AM | 0.03 | + | 14 January 2024 | AM | 0.04 | + | 15 January 2024 | AM | 0.01 | + | 16 January 2024 | AM | 0.02 | + | 16 January 2024 | AM | 0.2 | + And Deferred Capitalized Income by external-id contains the following data: + | Amount | Amortized Amount | Unrecognized Amount | Adjusted Amount | Charged Off Amount | + | 1.0 | 0.5 | 0.0 | 0.3 | 0.2 | diff --git a/fineract-loan/src/main/java/org/apache/fineract/portfolio/loanaccount/domain/LoanAmortizationAllocationMappingRepository.java b/fineract-loan/src/main/java/org/apache/fineract/portfolio/loanaccount/domain/LoanAmortizationAllocationMappingRepository.java index 7507a75ea..22ad707ba 100644 --- a/fineract-loan/src/main/java/org/apache/fineract/portfolio/loanaccount/domain/LoanAmortizationAllocationMappingRepository.java +++ b/fineract-loan/src/main/java/org/apache/fineract/portfolio/loanaccount/domain/LoanAmortizationAllocationMappingRepository.java @@ -18,6 +18,7 @@ */ package org.apache.fineract.portfolio.loanaccount.domain; +import java.math.BigDecimal; import java.util.List; import org.apache.fineract.portfolio.loanaccount.data.AmortizationAllocationMappingDTO; import org.springframework.data.jpa.repository.JpaRepository; @@ -33,11 +34,31 @@ import org.springframework.stereotype.Repository; public interface LoanAmortizationAllocationMappingRepository extends JpaRepository, JpaSpecificationExecutor { - @Query(value = "SELECT new org.apache.fineract.portfolio.loanaccount.data.AmortizationAllocationMappingDTO(" - + "laam.amortizationLoanTransactionId, at.externalId, laam.date, laam.amortizationType, laam.amount) " - + "FROM LoanAmortizationAllocationMapping laam " + "JOIN LoanTransaction at ON laam.amortizationLoanTransactionId = at.id " - + "WHERE laam.baseLoanTransactionId = :baseLoanTransactionId AND laam.loanId = :loanId " - + "ORDER BY laam.date, laam.amortizationLoanTransactionId") + @Query(""" + SELECT new org.apache.fineract.portfolio.loanaccount.data.AmortizationAllocationMappingDTO( + laam.amortizationLoanTransactionId, + at.externalId, + laam.date, + laam.amortizationType, + laam.amount + ) FROM LoanAmortizationAllocationMapping laam + JOIN LoanTransaction at ON laam.amortizationLoanTransactionId = at.id + WHERE laam.baseLoanTransactionId = :baseLoanTransactionId AND laam.loanId = :loanId + ORDER BY laam.date, laam.amortizationLoanTransactionId + """) List findAmortizationMappingsByBaseTransactionAndLoan( @Param("baseLoanTransactionId") Long baseLoanTransactionId, @Param("loanId") Long loanId); + + @Query(""" + SELECT COALESCE(SUM( + CASE + WHEN laam.amortizationType = org.apache.fineract.portfolio.loanaccount.domain.AmortizationType.AM THEN laam.amount + WHEN laam.amortizationType = org.apache.fineract.portfolio.loanaccount.domain.AmortizationType.AM_ADJ THEN -laam.amount + ELSE 0 + END + ), 0) + FROM LoanAmortizationAllocationMapping laam + WHERE laam.baseLoanTransactionId = :baseLoanTransactionId AND laam.loanId = :loanId + """) + BigDecimal calculateAlreadyAmortizedAmount(@Param("baseLoanTransactionId") Long baseLoanTransactionId, @Param("loanId") Long loanId); } diff --git a/fineract-loan/src/main/java/org/apache/fineract/portfolio/loanaccount/service/LoanAmortizationAllocationService.java b/fineract-loan/src/main/java/org/apache/fineract/portfolio/loanaccount/service/LoanAmortizationAllocationService.java index 70b2b62a8..56ea46820 100644 --- a/fineract-loan/src/main/java/org/apache/fineract/portfolio/loanaccount/service/LoanAmortizationAllocationService.java +++ b/fineract-loan/src/main/java/org/apache/fineract/portfolio/loanaccount/service/LoanAmortizationAllocationService.java @@ -36,6 +36,8 @@ public interface LoanAmortizationAllocationService { */ LoanAmortizationAllocationData retrieveLoanAmortizationAllocationsForCapitalizedIncomeTransaction(Long loanTransactionId, Long loanId); + BigDecimal calculateAlreadyAmortizedAmount(Long loanTransactionId, Long loanId); + LoanAmortizationAllocationMapping createAmortizationAllocationMappingWithBaseLoanTransaction(LoanTransaction loanTransaction, BigDecimal amount, AmortizationType amortizationType); diff --git a/fineract-provider/src/main/java/org/apache/fineract/portfolio/loanaccount/service/LoanAmortizationAllocationServiceImpl.java b/fineract-provider/src/main/java/org/apache/fineract/portfolio/loanaccount/service/LoanAmortizationAllocationServiceImpl.java index 6932d26cb..739bf224a 100644 --- a/fineract-provider/src/main/java/org/apache/fineract/portfolio/loanaccount/service/LoanAmortizationAllocationServiceImpl.java +++ b/fineract-provider/src/main/java/org/apache/fineract/portfolio/loanaccount/service/LoanAmortizationAllocationServiceImpl.java @@ -69,6 +69,11 @@ public class LoanAmortizationAllocationServiceImpl implements LoanAmortizationAl return retrieveLoanAmortizationAllocationData(loanTransaction, loanId); } + @Override + public BigDecimal calculateAlreadyAmortizedAmount(final Long loanTransactionId, final Long loanId) { + return loanAmortizationAllocationMappingRepository.calculateAlreadyAmortizedAmount(loanTransactionId, loanId); + } + private LoanAmortizationAllocationData retrieveLoanAmortizationAllocationData(final LoanTransaction loanTransaction, final Long loanId) { try { diff --git a/fineract-provider/src/main/java/org/apache/fineract/portfolio/loanaccount/service/LoanBuyDownFeeAmortizationProcessingServiceImpl.java b/fineract-provider/src/main/java/org/apache/fineract/portfolio/loanaccount/service/LoanBuyDownFeeAmortizationProcessingServiceImpl.java index 7bf31ef0b..5fc4a098e 100644 --- a/fineract-provider/src/main/java/org/apache/fineract/portfolio/loanaccount/service/LoanBuyDownFeeAmortizationProcessingServiceImpl.java +++ b/fineract-provider/src/main/java/org/apache/fineract/portfolio/loanaccount/service/LoanBuyDownFeeAmortizationProcessingServiceImpl.java @@ -34,7 +34,6 @@ import org.apache.fineract.infrastructure.event.business.domain.loan.transaction import org.apache.fineract.infrastructure.event.business.domain.loan.transaction.LoanBuyDownFeeAmortizationTransactionCreatedBusinessEvent; import org.apache.fineract.infrastructure.event.business.service.BusinessEventNotifierService; import org.apache.fineract.organisation.monetary.domain.Money; -import org.apache.fineract.portfolio.loanaccount.data.LoanAmortizationAllocationData; import org.apache.fineract.portfolio.loanaccount.domain.AmortizationType; import org.apache.fineract.portfolio.loanaccount.domain.Loan; import org.apache.fineract.portfolio.loanaccount.domain.LoanAmortizationAllocationMapping; @@ -75,7 +74,6 @@ public class LoanBuyDownFeeAmortizationProcessingServiceImpl implements LoanBuyD final List loanAmortizationAllocationMappings = new ArrayList<>(); Money totalAmortization = Money.zero(loan.getCurrency()); final BigDecimal totalAmortized = loanTransactionRepository.getAmortizedAmountBuyDownFee(loan); - BigDecimal totalAmortizedAccumulator = totalAmortized; for (LoanBuyDownFeeBalance balance : balances) { BigDecimal amortizationAmount; AmortizationType amortizationType; @@ -84,46 +82,26 @@ public class LoanBuyDownFeeAmortizationProcessingServiceImpl implements LoanBuyD final Money amortizationTillDate = BuyDownFeeAmortizationUtil.calculateTotalAmortizationTillDate(balance, adjustments, maturityDate, loan.getLoanProductRelatedDetail().getBuyDownFeeStrategy(), tillDatePlusOne, loan.getCurrency()); totalAmortization = totalAmortization.add(amortizationTillDate); + final BigDecimal alreadyAmortizedAmount = loanAmortizationAllocationService + .calculateAlreadyAmortizedAmount(balance.getLoanTransaction().getId(), loan.getId()); if (!adjustments.isEmpty()) { - BigDecimal alreadyAmortizedAmount = balance.getAmount().subtract(MathUtil.nullToZero(balance.getAmountAdjustment())) - .subtract(MathUtil.nullToZero(balance.getChargedOffAmount())).subtract(balance.getUnrecognizedAmount()); - if (alreadyAmortizedAmount.compareTo(BigDecimal.ZERO) == 0) { - final LoanAmortizationAllocationData loanAmortizationAllocationData = loanAmortizationAllocationService - .retrieveLoanAmortizationAllocationsForBuyDownFeeTransaction(balance.getLoanTransaction().getId(), - loan.getId()); - BigDecimal amortizedAmount = BigDecimal.ZERO; - for (LoanAmortizationAllocationData.AmortizationMappingData loanAmortizationMapping : loanAmortizationAllocationData - .getAmortizationMappings()) { - if (AmortizationType.AM.equals(loanAmortizationMapping.getType())) { - amortizedAmount = amortizedAmount.add(loanAmortizationMapping.getAmount()); - } else if (AmortizationType.AM_ADJ.equals(loanAmortizationMapping.getType())) { - amortizedAmount = amortizedAmount.subtract(loanAmortizationMapping.getAmount()); - } - } - amortizationAmount = amortizedAmount; - amortizationType = AmortizationType.AM_ADJ; - totalAmortizedAccumulator = totalAmortizedAccumulator.subtract(amortizationAmount); - } else if (alreadyAmortizedAmount.compareTo(amortizationTillDate.getAmount()) > 0) { + if (alreadyAmortizedAmount.compareTo(amortizationTillDate.getAmount()) > 0) { amortizationAmount = alreadyAmortizedAmount.subtract(amortizationTillDate.getAmount()); amortizationType = AmortizationType.AM_ADJ; - totalAmortizedAccumulator = totalAmortizedAccumulator.subtract(amortizationAmount); } else { amortizationAmount = amortizationTillDate.getAmount().subtract(alreadyAmortizedAmount); amortizationType = AmortizationType.AM; - totalAmortizedAccumulator = totalAmortizedAccumulator.add(amortizationAmount); } } else { - amortizationAmount = totalAmortization.getAmount().subtract(totalAmortizedAccumulator); + amortizationAmount = amortizationTillDate.getAmount().subtract(alreadyAmortizedAmount); amortizationType = AmortizationType.AM; - totalAmortizedAccumulator = totalAmortizedAccumulator.add(amortizationAmount); } - balance.setUnrecognizedAmount(balance.getAmount().subtract(MathUtil.nullToZero(balance.getAmountAdjustment())) - .subtract(amortizationTillDate.getAmount())); + balance.setUnrecognizedAmount( + MathUtil.subtract(balance.getAmount(), balance.getAmountAdjustment(), amortizationTillDate.getAmount())); } else { amortizationAmount = balance.getAmount().subtract(balance.getUnrecognizedAmount()); amortizationType = AmortizationType.AM_ADJ; balance.setClosed(true); - totalAmortizedAccumulator = totalAmortizedAccumulator.subtract(amortizationAmount); } if (amortizationAmount.compareTo(BigDecimal.ZERO) > 0) { final LoanAmortizationAllocationMapping loanAmortizationAllocationMapping = loanAmortizationAllocationService @@ -236,7 +214,6 @@ public class LoanBuyDownFeeAmortizationProcessingServiceImpl implements LoanBuyD BigDecimal totalAmortization = BigDecimal.ZERO; final BigDecimal totalAmortized = loanTransactionRepository.getAmortizedAmountBuyDownFee(loan); - BigDecimal totalAmortizedAccumulator = totalAmortized; for (LoanBuyDownFeeBalance balance : balances) { BigDecimal amortizationAmount; AmortizationType amortizationType; @@ -246,38 +223,19 @@ public class LoanBuyDownFeeAmortizationProcessingServiceImpl implements LoanBuyD final Money amortizationTillDate = BuyDownFeeAmortizationUtil.calculateTotalAmortizationTillDate(balance, adjustments, maturityDate, loan.getLoanProductRelatedDetail().getBuyDownFeeStrategy(), maturityDate, loan.getCurrency()); totalAmortization = totalAmortization.add(amortizationTillDate.getAmount()); + final BigDecimal alreadyAmortizedAmount = loanAmortizationAllocationService + .calculateAlreadyAmortizedAmount(balance.getLoanTransaction().getId(), loan.getId()); if (!adjustments.isEmpty()) { - BigDecimal alreadyAmortizedAmount = balance.getAmount().subtract(MathUtil.nullToZero(balance.getAmountAdjustment())) - .subtract(MathUtil.nullToZero(balance.getChargedOffAmount())).subtract(balance.getUnrecognizedAmount()); - if (alreadyAmortizedAmount.compareTo(BigDecimal.ZERO) == 0) { - final LoanAmortizationAllocationData loanAmortizationAllocationData = loanAmortizationAllocationService - .retrieveLoanAmortizationAllocationsForBuyDownFeeTransaction(balance.getLoanTransaction().getId(), - loan.getId()); - BigDecimal amortizedAmount = BigDecimal.ZERO; - for (LoanAmortizationAllocationData.AmortizationMappingData loanAmortizationMapping : loanAmortizationAllocationData - .getAmortizationMappings()) { - if (AmortizationType.AM.equals(loanAmortizationMapping.getType())) { - amortizedAmount = amortizedAmount.add(loanAmortizationMapping.getAmount()); - } else if (AmortizationType.AM_ADJ.equals(loanAmortizationMapping.getType())) { - amortizedAmount = amortizedAmount.subtract(loanAmortizationMapping.getAmount()); - } - } - amortizationAmount = amortizedAmount; - amortizationType = AmortizationType.AM_ADJ; - totalAmortizedAccumulator = totalAmortizedAccumulator.subtract(amortizationAmount); - } else if (alreadyAmortizedAmount.compareTo(amortizationTillDate.getAmount()) > 0) { + if (alreadyAmortizedAmount.compareTo(amortizationTillDate.getAmount()) > 0) { amortizationAmount = alreadyAmortizedAmount.subtract(amortizationTillDate.getAmount()); amortizationType = AmortizationType.AM_ADJ; - totalAmortizedAccumulator = totalAmortizedAccumulator.subtract(amortizationAmount); } else { amortizationAmount = amortizationTillDate.getAmount().subtract(alreadyAmortizedAmount); amortizationType = AmortizationType.AM; - totalAmortizedAccumulator = totalAmortizedAccumulator.add(amortizationAmount); } } else { - amortizationAmount = totalAmortization.subtract(totalAmortizedAccumulator); + amortizationAmount = amortizationTillDate.getAmount().subtract(alreadyAmortizedAmount); amortizationType = AmortizationType.AM; - totalAmortizedAccumulator = totalAmortizedAccumulator.add(amortizationAmount); } if (isChargeOff) { balance.setChargedOffAmount(balance.getUnrecognizedAmount()); @@ -287,7 +245,6 @@ public class LoanBuyDownFeeAmortizationProcessingServiceImpl implements LoanBuyD amortizationAmount = balance.getAmount().subtract(balance.getUnrecognizedAmount()); amortizationType = AmortizationType.AM_ADJ; balance.setClosed(true); - totalAmortizedAccumulator = totalAmortizedAccumulator.subtract(amortizationAmount); } if (amortizationAmount.compareTo(BigDecimal.ZERO) > 0) { final LoanAmortizationAllocationMapping loanAmortizationAllocationMapping = loanAmortizationAllocationService diff --git a/fineract-provider/src/main/java/org/apache/fineract/portfolio/loanaccount/service/LoanCapitalizedIncomeAmortizationProcessingServiceImpl.java b/fineract-provider/src/main/java/org/apache/fineract/portfolio/loanaccount/service/LoanCapitalizedIncomeAmortizationProcessingServiceImpl.java index 045227e1a..a7377d97b 100644 --- a/fineract-provider/src/main/java/org/apache/fineract/portfolio/loanaccount/service/LoanCapitalizedIncomeAmortizationProcessingServiceImpl.java +++ b/fineract-provider/src/main/java/org/apache/fineract/portfolio/loanaccount/service/LoanCapitalizedIncomeAmortizationProcessingServiceImpl.java @@ -35,7 +35,6 @@ import org.apache.fineract.infrastructure.event.business.domain.loan.transaction import org.apache.fineract.infrastructure.event.business.domain.loan.transaction.LoanCapitalizedIncomeAmortizationTransactionCreatedBusinessEvent; import org.apache.fineract.infrastructure.event.business.service.BusinessEventNotifierService; import org.apache.fineract.organisation.monetary.domain.Money; -import org.apache.fineract.portfolio.loanaccount.data.LoanAmortizationAllocationData; import org.apache.fineract.portfolio.loanaccount.domain.AmortizationType; import org.apache.fineract.portfolio.loanaccount.domain.Loan; import org.apache.fineract.portfolio.loanaccount.domain.LoanAmortizationAllocationMapping; @@ -119,7 +118,6 @@ public class LoanCapitalizedIncomeAmortizationProcessingServiceImpl implements L BigDecimal totalAmortization = BigDecimal.ZERO; final BigDecimal totalAmortized = loanTransactionRepository.getAmortizedAmountCapitalizedIncome(loan); - BigDecimal totalAmortizedAccumulator = totalAmortized; for (LoanCapitalizedIncomeBalance balance : balances) { BigDecimal amortizationAmount; AmortizationType amortizationType; @@ -130,38 +128,19 @@ public class LoanCapitalizedIncomeAmortizationProcessingServiceImpl implements L adjustments, maturityDate, loan.getLoanProductRelatedDetail().getCapitalizedIncomeStrategy(), maturityDate, loan.getCurrency()); totalAmortization = totalAmortization.add(amortizationTillDate.getAmount()); + final BigDecimal alreadyAmortizedAmount = loanAmortizationAllocationService + .calculateAlreadyAmortizedAmount(balance.getLoanTransaction().getId(), loan.getId()); if (!adjustments.isEmpty()) { - BigDecimal alreadyAmortizedAmount = balance.getAmount().subtract(MathUtil.nullToZero(balance.getAmountAdjustment())) - .subtract(MathUtil.nullToZero(balance.getChargedOffAmount())).subtract(balance.getUnrecognizedAmount()); - if (alreadyAmortizedAmount.compareTo(BigDecimal.ZERO) == 0) { - final LoanAmortizationAllocationData loanAmortizationAllocationData = loanAmortizationAllocationService - .retrieveLoanAmortizationAllocationsForCapitalizedIncomeTransaction(balance.getLoanTransaction().getId(), - loan.getId()); - BigDecimal amortizedAmount = BigDecimal.ZERO; - for (LoanAmortizationAllocationData.AmortizationMappingData loanAmortizationMapping : loanAmortizationAllocationData - .getAmortizationMappings()) { - if (AmortizationType.AM.equals(loanAmortizationMapping.getType())) { - amortizedAmount = amortizedAmount.add(loanAmortizationMapping.getAmount()); - } else if (AmortizationType.AM_ADJ.equals(loanAmortizationMapping.getType())) { - amortizedAmount = amortizedAmount.subtract(loanAmortizationMapping.getAmount()); - } - } - amortizationAmount = amortizedAmount; - amortizationType = AmortizationType.AM_ADJ; - totalAmortizedAccumulator = totalAmortizedAccumulator.subtract(amortizationAmount); - } else if (alreadyAmortizedAmount.compareTo(amortizationTillDate.getAmount()) > 0) { + if (alreadyAmortizedAmount.compareTo(amortizationTillDate.getAmount()) > 0) { amortizationAmount = alreadyAmortizedAmount.subtract(amortizationTillDate.getAmount()); amortizationType = AmortizationType.AM_ADJ; - totalAmortizedAccumulator = totalAmortizedAccumulator.subtract(amortizationAmount); } else { amortizationAmount = amortizationTillDate.getAmount().subtract(alreadyAmortizedAmount); amortizationType = AmortizationType.AM; - totalAmortizedAccumulator = totalAmortizedAccumulator.add(amortizationAmount); } } else { - amortizationAmount = totalAmortization.subtract(totalAmortizedAccumulator); + amortizationAmount = amortizationTillDate.getAmount().subtract(alreadyAmortizedAmount); amortizationType = AmortizationType.AM; - totalAmortizedAccumulator = totalAmortizedAccumulator.add(amortizationAmount); } if (isChargeOff) { balance.setChargedOffAmount(balance.getUnrecognizedAmount()); @@ -171,7 +150,6 @@ public class LoanCapitalizedIncomeAmortizationProcessingServiceImpl implements L amortizationAmount = balance.getAmount().subtract(balance.getUnrecognizedAmount()); amortizationType = AmortizationType.AM_ADJ; balance.setClosed(true); - totalAmortizedAccumulator = totalAmortizedAccumulator.subtract(amortizationAmount); } if (amortizationAmount.compareTo(BigDecimal.ZERO) > 0) { final LoanAmortizationAllocationMapping loanAmortizationAllocationMapping = loanAmortizationAllocationService @@ -246,7 +224,6 @@ public class LoanCapitalizedIncomeAmortizationProcessingServiceImpl implements L final List loanAmortizationAllocationMappings = new ArrayList<>(); Money totalAmortization = Money.zero(loan.getCurrency()); final BigDecimal totalAmortized = loanTransactionRepository.getAmortizedAmountCapitalizedIncome(loan); - BigDecimal totalAmortizedAccumulator = totalAmortized; for (LoanCapitalizedIncomeBalance balance : balances) { BigDecimal amortizationAmount; AmortizationType amortizationType; @@ -256,46 +233,26 @@ public class LoanCapitalizedIncomeAmortizationProcessingServiceImpl implements L adjustments, maturityDate, loan.getLoanProductRelatedDetail().getCapitalizedIncomeStrategy(), tillDatePlusOne, loan.getCurrency()); totalAmortization = totalAmortization.add(amortizationTillDate); + final BigDecimal alreadyAmortizedAmount = loanAmortizationAllocationService + .calculateAlreadyAmortizedAmount(balance.getLoanTransaction().getId(), loan.getId()); if (!adjustments.isEmpty()) { - BigDecimal alreadyAmortizedAmount = balance.getAmount().subtract(MathUtil.nullToZero(balance.getAmountAdjustment())) - .subtract(MathUtil.nullToZero(balance.getChargedOffAmount())).subtract(balance.getUnrecognizedAmount()); - if (alreadyAmortizedAmount.compareTo(BigDecimal.ZERO) == 0) { - final LoanAmortizationAllocationData loanAmortizationAllocationData = loanAmortizationAllocationService - .retrieveLoanAmortizationAllocationsForCapitalizedIncomeTransaction(balance.getLoanTransaction().getId(), - loan.getId()); - BigDecimal amortizedAmount = BigDecimal.ZERO; - for (LoanAmortizationAllocationData.AmortizationMappingData loanAmortizationMapping : loanAmortizationAllocationData - .getAmortizationMappings()) { - if (AmortizationType.AM.equals(loanAmortizationMapping.getType())) { - amortizedAmount = amortizedAmount.add(loanAmortizationMapping.getAmount()); - } else if (AmortizationType.AM_ADJ.equals(loanAmortizationMapping.getType())) { - amortizedAmount = amortizedAmount.subtract(loanAmortizationMapping.getAmount()); - } - } - amortizationAmount = amortizedAmount; - amortizationType = AmortizationType.AM_ADJ; - totalAmortizedAccumulator = totalAmortizedAccumulator.subtract(amortizationAmount); - } else if (alreadyAmortizedAmount.compareTo(amortizationTillDate.getAmount()) > 0) { + if (alreadyAmortizedAmount.compareTo(amortizationTillDate.getAmount()) > 0) { amortizationAmount = alreadyAmortizedAmount.subtract(amortizationTillDate.getAmount()); amortizationType = AmortizationType.AM_ADJ; - totalAmortizedAccumulator = totalAmortizedAccumulator.subtract(amortizationAmount); } else { amortizationAmount = amortizationTillDate.getAmount().subtract(alreadyAmortizedAmount); amortizationType = AmortizationType.AM; - totalAmortizedAccumulator = totalAmortizedAccumulator.add(amortizationAmount); } } else { - amortizationAmount = totalAmortization.getAmount().subtract(totalAmortizedAccumulator); + amortizationAmount = amortizationTillDate.getAmount().subtract(alreadyAmortizedAmount); amortizationType = AmortizationType.AM; - totalAmortizedAccumulator = totalAmortizedAccumulator.add(amortizationAmount); } - balance.setUnrecognizedAmount(balance.getAmount().subtract(MathUtil.nullToZero(balance.getAmountAdjustment())) - .subtract(amortizationTillDate.getAmount())); + balance.setUnrecognizedAmount( + MathUtil.subtract(balance.getAmount(), balance.getAmountAdjustment(), amortizationTillDate.getAmount())); } else { amortizationAmount = balance.getAmount().subtract(balance.getUnrecognizedAmount()); amortizationType = AmortizationType.AM_ADJ; balance.setClosed(true); - totalAmortizedAccumulator = totalAmortizedAccumulator.subtract(amortizationAmount); } if (amortizationAmount.compareTo(BigDecimal.ZERO) > 0) { final LoanAmortizationAllocationMapping loanAmortizationAllocationMapping = loanAmortizationAllocationService