Skip to content

Commit c79c076

Browse files
committed
FINERACT-2354: In case full transaction reprocessing, we need to recalculate the schedule as well
1 parent 0515710 commit c79c076

File tree

39 files changed

+357
-475
lines changed

39 files changed

+357
-475
lines changed

fineract-core/src/main/java/org/apache/fineract/organisation/monetary/domain/MonetaryCurrency.java

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -20,6 +20,7 @@
2020

2121
import jakarta.persistence.Column;
2222
import jakarta.persistence.Embeddable;
23+
import lombok.AccessLevel;
2324
import lombok.Getter;
2425
import org.apache.fineract.organisation.monetary.data.CurrencyData;
2526

@@ -36,6 +37,7 @@ public class MonetaryCurrency {
3637
@Column(name = "currency_multiplesof")
3738
private Integer inMultiplesOf;
3839

40+
@Getter(AccessLevel.PRIVATE)
3941
private transient CurrencyData currencyData;
4042

4143
protected MonetaryCurrency() {

fineract-core/src/main/java/org/apache/fineract/organisation/monetary/domain/Money.java

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -21,6 +21,7 @@
2121
import java.math.BigDecimal;
2222
import java.math.MathContext;
2323
import java.util.Iterator;
24+
import org.apache.fineract.infrastructure.core.service.MathUtil;
2425
import org.apache.fineract.organisation.monetary.data.CurrencyData;
2526

2627
public class Money implements Comparable<Money> {
@@ -45,9 +46,8 @@ private Money(final CurrencyData currency, final BigDecimal amount, final MathCo
4546

4647
// round monetary amounts into multiples of say 20/50.
4748
if (currency.getInMultiplesOf() != null && currency.getDecimalPlaces() == 0 && currency.getInMultiplesOf() > 0
48-
&& amountScaled.doubleValue() > 0) {
49-
final double existingVal = amountScaled.doubleValue();
50-
amountScaled = BigDecimal.valueOf(roundToMultiplesOf(existingVal, currency.getInMultiplesOf()));
49+
&& MathUtil.isGreaterThanZero(amountScaled)) {
50+
amountScaled = roundToMultiplesOf(amountScaled, currency.getInMultiplesOf());
5151
}
5252
this.amount = amountScaled.setScale(currency.getDecimalPlaces(), getMc().getRoundingMode());
5353
}

fineract-e2e-tests-runner/src/test/resources/features/Loan.feature

Lines changed: 7 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -8394,13 +8394,13 @@ Feature: Loan
83948394
| 2 | 15 | 31 January 2025 | | 200.59 | 49.78 | 0.73 | 0.0 | 0.0 | 50.51 | 0.0 | 0.0 | 0.0 | 50.51 |
83958395
| | | 01 February 2025 | | 500.0 | | | 0.0 | | 0.0 | | | | 0.0 |
83968396
| | | 01 February 2025 | | 200.0 | | | 0.0 | | 0.0 | | | | 0.0 |
8397-
| 3 | 15 | 15 February 2025 | | 850.67 | 49.92 | 0.59 | 0.0 | 0.0 | 50.51 | 0.0 | 0.0 | 0.0 | 50.51 |
8398-
| 4 | 15 | 02 March 2025 | | 800.6 | 50.07 | 0.44 | 0.0 | 0.0 | 50.51 | 0.0 | 0.0 | 0.0 | 50.51 |
8399-
| 5 | 15 | 17 March 2025 | | 750.38 | 50.22 | 0.29 | 0.0 | 0.0 | 50.51 | 0.0 | 0.0 | 0.0 | 50.51 |
8400-
| 6 | 15 | 01 April 2025 | | 700.0 | 50.38 | 0.15 | 0.0 | 0.0 | 50.53 | 0.0 | 0.0 | 0.0 | 50.53 |
8397+
| 3 | 15 | 15 February 2025 | | 676.32 | 224.27 | 2.49 | 0.0 | 0.0 | 226.76 | 0.0 | 0.0 | 0.0 | 226.76 |
8398+
| 4 | 15 | 02 March 2025 | | 451.53 | 224.79 | 1.97 | 0.0 | 0.0 | 226.76 | 0.0 | 0.0 | 0.0 | 226.76 |
8399+
| 5 | 15 | 17 March 2025 | | 226.09 | 225.44 | 1.32 | 0.0 | 0.0 | 226.76 | 0.0 | 0.0 | 0.0 | 226.76 |
8400+
| 6 | 15 | 01 April 2025 | | 0.0 | 226.09 | 0.66 | 0.0 | 0.0 | 226.75 | 0.0 | 0.0 | 0.0 | 226.75 |
84018401
Then Loan Repayment schedule has the following data in Total row:
8402-
| Principal due | Interest | Fees | Penalties | Due | Paid | In advance | Late | Outstanding |
8403-
| 300.0 | 3.08 | 0.0 | 0.0 | 303.08 | 0.0 | 0.0 | 0.0 | 303.08 |
8402+
| Principal due | Interest | Fees | Penalties | Due | Paid | In advance | Late | Outstanding |
8403+
| 1000.00 | 8.05 | 0.0 | 0.0 | 1008.05 | 0.0 | 0.0 | 0.0 | 1008.05 |
84048404
Then Loan Tranche Details tab has the following data:
84058405
| Expected Disbursement On | Disbursed On | Principal | Net Disbursal Amount |
84068406
| 01 January 2025 | | 300.0 | |
@@ -8860,4 +8860,4 @@ Feature: Loan
88608860
| 21 October 2025 | Accrual Activity | 3.32 | 0.0 | 0.52 | 0.0 | 2.8 | 0.0 | false | true |
88618861
| 06 November 2025 | Accrual | 1.21 | 0.0 | 1.21 | 0.0 | 0.0 | 0.0 | false | false |
88628862
And Customer makes "AUTOPAY" repayment on "06 November 2025" with 35.28 EUR transaction amount
8863-
Then Loan status will be "CLOSED_OBLIGATIONS_MET"
8863+
Then Loan status will be "CLOSED_OBLIGATIONS_MET"

fineract-e2e-tests-runner/src/test/resources/features/LoanReAging.feature

Lines changed: 20 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -4634,10 +4634,10 @@ Feature: LoanReAging
46344634
| 01 February 2024 | Repayment | 17.01 | 16.43 | 0.58 | 0.0 | 0.0 | 83.57 | false | false |
46354635
| 01 March 2024 | Accrual | 1.07 | 0.0 | 1.07 | 0.0 | 0.0 | 0.0 | false | false |
46364636
| 01 March 2024 | Contract Termination | 84.06 | 83.57 | 0.49 | 0.0 | 0.0 | 0.0 | false | false |
4637-
When Admin sets the business date to "15 April 2024"
4638-
Then Admin fails to create a Loan re-aging transaction with the following data because loan was contract terminated:
4639-
| frequencyNumber | frequencyType | startDate | numberOfInstallments |
4640-
| 1 | MONTHS | 01 May 2024 | 6 |
4637+
# When Admin sets the business date to "15 April 2024"
4638+
# Then Admin fails to create a Loan re-aging transaction with the following data because loan was contract terminated:
4639+
# | frequencyNumber | frequencyType | startDate | numberOfInstallments |
4640+
# | 1 | MONTHS | 01 May 2024 | 6 |
46414641

46424642
@TestRailId:C4090 @AdvancedPaymentAllocation
46434643
Scenario: Verify that Re-aging is forbidden on charged-off loan, interest bearing loan, Interest calculation: Default Behavior, Charge-off scenario (accelerate maturity) - UC11
@@ -5014,6 +5014,8 @@ Feature: LoanReAging
50145014
| 01 February 2024 | Repayment | 17.01 | 16.43 | 0.58 | 0.0 | 0.0 | 83.57 | false |
50155015
| 15 March 2024 | Re-age | 84.28 | 83.57 | 0.71 | 0.0 | 0.0 | 0.0 | true |
50165016
| 15 March 2024 | Interest waive | 0.71 | 0.0 | 0.71 | 0.0 | 0.0 | 0.0 | true |
5017+
When Loan Pay-off is made on "01 April 2024"
5018+
Then Loan is closed with zero outstanding balance and it's all installments have obligations met
50175019

50185020
@Skip @TestRailId:C4198 @AdvancedPaymentAllocation
50195021
Scenario: Verify Re-aging reversal on interest bearing loan - UC3: Interest handling: EQUAL_AMORTIZATION_PAYABLE_INTEREST
@@ -5120,6 +5122,8 @@ Feature: LoanReAging
51205122
| 01 January 2024 | Disbursement | 100.0 | 0.0 | 0.0 | 0.0 | 0.0 | 100.0 | false |
51215123
| 01 February 2024 | Repayment | 17.01 | 16.43 | 0.58 | 0.0 | 0.0 | 83.57 | false |
51225124
| 15 March 2024 | Re-age | 84.28 | 83.57 | 0.71 | 0.0 | 0.0 | 0.0 | true |
5125+
When Loan Pay-off is made on "01 April 2024"
5126+
Then Loan is closed with zero outstanding balance and it's all installments have obligations met
51235127

51245128
@Skip @TestRailId:C4199 @AdvancedPaymentAllocation
51255129
Scenario: Verify Re-aging reversal on interest bearing loan - UC4: Interest handling: EQUAL_AMORTIZATION_FULL_INTEREST
@@ -5226,6 +5230,8 @@ Feature: LoanReAging
52265230
| 01 January 2024 | Disbursement | 100.0 | 0.0 | 0.0 | 0.0 | 0.0 | 100.0 | false |
52275231
| 01 February 2024 | Repayment | 17.01 | 16.43 | 0.58 | 0.0 | 0.0 | 83.57 | false |
52285232
| 15 March 2024 | Re-age | 85.08 | 83.57 | 1.51 | 0.0 | 0.0 | 0.0 | true |
5233+
When Loan Pay-off is made on "01 April 2024"
5234+
Then Loan is closed with zero outstanding balance and it's all installments have obligations met
52295235

52305236
@TestRailId:C4202 @AdvancedPaymentAllocation
52315237
Scenario: Verify Re-aging reversal on interest bearing loan - UC5: Interest handling: DEFAULT, re-aging is NOT the latest transaction on loan
@@ -5331,7 +5337,7 @@ Feature: LoanReAging
53315337
| Transaction date | Transaction Type | Amount | Principal | Interest | Fees | Penalties | Loan Balance | Reverted | Replayed |
53325338
| 01 January 2024 | Disbursement | 100.0 | 0.0 | 0.0 | 0.0 | 0.0 | 100.0 | false | false |
53335339
| 01 February 2024 | Repayment | 17.01 | 16.43 | 0.58 | 0.0 | 0.0 | 83.57 | false | false |
5334-
| 15 March 2024 | Re-age | 84.28 | 83.57 | 0.71 | 0.0 | 0.0 | 0.0 | false | true |
5340+
| 15 March 2024 | Re-age | 84.28 | 83.57 | 0.71 | 0.0 | 0.0 | 0.0 | false | false |
53355341
| 16 March 2024 | Repayment | 14.3 | 13.57 | 0.73 | 0.0 | 0.0 | 70.0 | false | false |
53365342
# --- Reversal of re-age transaction ---
53375343
When Admin sets the business date to "01 April 2024"
@@ -5352,7 +5358,7 @@ Feature: LoanReAging
53525358
| Transaction date | Transaction Type | Amount | Principal | Interest | Fees | Penalties | Loan Balance | Reverted | Replayed |
53535359
| 01 January 2024 | Disbursement | 100.0 | 0.0 | 0.0 | 0.0 | 0.0 | 100.0 | false | false |
53545360
| 01 February 2024 | Repayment | 17.01 | 16.43 | 0.58 | 0.0 | 0.0 | 83.57 | false | false |
5355-
| 15 March 2024 | Re-age | 84.28 | 83.57 | 0.71 | 0.0 | 0.0 | 0.0 | true | true |
5361+
| 15 March 2024 | Re-age | 84.28 | 83.57 | 0.71 | 0.0 | 0.0 | 0.0 | true | false |
53565362
| 16 March 2024 | Repayment | 14.3 | 13.81 | 0.49 | 0.0 | 0.0 | 69.76 | false | true |
53575363
When Loan Pay-off is made on "01 April 2024"
53585364
Then Loan is closed with zero outstanding balance and it's all installments have obligations met
@@ -5416,12 +5422,12 @@ Feature: LoanReAging
54165422
| | | 01 January 2024 | | 100.0 | | | 0.0 | | 0.0 | 0.0 | | | |
54175423
| 1 | 31 | 01 February 2024 | 01 February 2024 | 83.57 | 16.43 | 0.58 | 0.0 | 0.0 | 17.01 | 17.01 | 0.0 | 0.0 | 0.0 |
54185424
| 2 | 29 | 01 March 2024 | 01 March 2024 | 67.05 | 16.52 | 0.49 | 0.0 | 0.0 | 17.01 | 17.01 | 0.0 | 0.0 | 0.0 |
5419-
| 3 | 31 | 01 April 2024 | | 56.0 | 11.05 | 0.39 | 0.0 | 0.0 | 11.44 | 0.0 | 0.0 | 0.0 | 11.44 |
5420-
| 4 | 30 | 01 May 2024 | | 44.95 | 11.05 | 0.39 | 0.0 | 0.0 | 11.44 | 0.0 | 0.0 | 0.0 | 11.44 |
5421-
| 5 | 31 | 01 June 2024 | | 33.9 | 11.05 | 0.39 | 0.0 | 0.0 | 11.44 | 0.0 | 0.0 | 0.0 | 11.44 |
5422-
| 6 | 30 | 01 July 2024 | | 22.66 | 11.24 | 0.2 | 0.0 | 0.0 | 11.44 | 0.0 | 0.0 | 0.0 | 11.44 |
5423-
| 7 | 31 | 01 August 2024 | | 11.35 | 11.31 | 0.13 | 0.0 | 0.0 | 11.44 | 0.0 | 0.0 | 0.0 | 11.44 |
5424-
| 8 | 31 | 01 September 2024| | 0.0 | 11.35 | 0.07 | 0.0 | 0.0 | 11.42 | 0.0 | 0.0 | 0.0 | 11.42 |
5425+
| 3 | 31 | 01 April 2024 | | 56.04 | 11.01 | 0.39 | 0.0 | 0.0 | 11.4 | 0.0 | 0.0 | 0.0 | 11.4 |
5426+
| 4 | 30 | 01 May 2024 | | 45.03 | 11.01 | 0.39 | 0.0 | 0.0 | 11.4 | 0.0 | 0.0 | 0.0 | 11.4 |
5427+
| 5 | 31 | 01 June 2024 | | 34.02 | 11.01 | 0.39 | 0.0 | 0.0 | 11.4 | 0.0 | 0.0 | 0.0 | 11.4 |
5428+
| 6 | 30 | 01 July 2024 | | 22.82 | 11.2 | 0.2 | 0.0 | 0.0 | 11.4 | 0.0 | 0.0 | 0.0 | 11.4 |
5429+
| 7 | 31 | 01 August 2024 | | 11.55 | 11.27 | 0.13 | 0.0 | 0.0 | 11.4 | 0.0 | 0.0 | 0.0 | 11.4 |
5430+
| 8 | 31 | 01 September 2024| | 0.0 | 11.55 | 0.07 | 0.0 | 0.0 | 11.62 | 0.0 | 0.0 | 0.0 | 11.62 |
54255431
Then Loan Repayment schedule has the following data in Total row:
54265432
| Principal due | Interest | Fees | Penalties | Due | Paid | In advance | Late | Outstanding |
54275433
| 100.0 | 2.64 | 0.0 | 0.0 | 102.64 | 34.02 | 0.0 | 0.0 | 68.62 |
@@ -5430,7 +5436,7 @@ Feature: LoanReAging
54305436
| 01 January 2024 | Disbursement | 100.0 | 0.0 | 0.0 | 0.0 | 0.0 | 100.0 | false | false |
54315437
| 01 February 2024 | Repayment | 17.01 | 16.43 | 0.58 | 0.0 | 0.0 | 83.57 | false | false |
54325438
| 01 March 2024 | Repayment | 17.01 | 16.52 | 0.49 | 0.0 | 0.0 | 67.05 | false | false |
5433-
| 01 April 2024 | Re-age | 67.44 | 67.05 | 0.39 | 0.0 | 0.0 | 0.0 | false | true |
5439+
| 01 April 2024 | Re-age | 67.44 | 67.05 | 0.39 | 0.0 | 0.0 | 0.0 | false | false |
54345440

54355441
@Skip
54365442
@TestRailId:C4154 @AdvancedPaymentAllocation
@@ -5508,7 +5514,7 @@ Feature: LoanReAging
55085514
| frequencyNumber | frequencyType | startDate | numberOfInstallments |
55095515
| 1 | MONTHS | 31 December 2023 | 6 |
55105516

5511-
@TestRailId:C4156 @AdvancedPaymentAllocation
5517+
@Skip @TestRailId:C4156 @AdvancedPaymentAllocation
55125518
Scenario: Verify allowing Re-aging on interest bearing loan - Interest calculation: Default Behavior - Verify backdated re-aging on the day of repayment with interest recalculation enabled - UC16.3
55135519
When Admin sets the business date to "01 January 2024"
55145520
When Admin creates a client with random data

fineract-e2e-tests-runner/src/test/resources/features/LoanReschedule.feature

Lines changed: 0 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1132,5 +1132,3 @@ Feature: LoanReschedule
11321132
| Transaction date | Transaction Type | Amount | Principal | Interest | Fees | Penalties | Loan Balance | Reverted | Replayed |
11331133
| 24 July 2025 | Disbursement | 500.0 | 0.0 | 0.0 | 0.0 | 0.0 | 500.0 | false | false |
11341134
Then LoanRescheduledDueAdjustScheduleBusinessEvent is raised on "24 July 2025"
1135-
1136-

fineract-loan/src/main/java/org/apache/fineract/portfolio/interestpauses/service/InterestPauseWritePlatformServiceImpl.java

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -46,7 +46,7 @@
4646
import org.apache.fineract.portfolio.loanaccount.domain.LoanTermVariations;
4747
import org.apache.fineract.portfolio.loanaccount.rescheduleloan.domain.LoanTermVariationsRepository;
4848
import org.apache.fineract.portfolio.loanaccount.service.LoanAssembler;
49-
import org.apache.fineract.portfolio.loanaccount.service.ReprocessLoanTransactionsService;
49+
import org.apache.fineract.portfolio.loanaccount.service.LoanScheduleService;
5050
import org.springframework.transaction.annotation.Transactional;
5151

5252
@AllArgsConstructor
@@ -56,8 +56,8 @@ public class InterestPauseWritePlatformServiceImpl implements InterestPauseWrite
5656
private final LoanTermVariationsRepository loanTermVariationsRepository;
5757
private final LoanRepositoryWrapper loanRepositoryWrapper;
5858
private final LoanAssembler loanAssembler;
59-
private final ReprocessLoanTransactionsService reprocessLoanTransactionsService;
6059
private final BusinessEventNotifierService businessEventNotifierService;
60+
private final LoanScheduleService loanScheduleService;
6161

6262
@Override
6363
public CommandProcessingResult createInterestPause(final ExternalId loanExternalId, final String startDateString,
@@ -114,7 +114,7 @@ private CommandProcessingResult processDeleteInterestPause(Loan loan, Long varia
114114
loanTermVariationsRepository.delete(variation);
115115
loan.getLoanTermVariations().remove(variation);
116116

117-
reprocessLoanTransactionsService.reprocessTransactions(loan);
117+
loanScheduleService.regenerateScheduleWithReprocessingTransactions(loan);
118118

119119
businessEventNotifierService.notifyPostBusinessEvent(new LoanScheduleVariationsDeletedBusinessEvent(loan));
120120
businessEventNotifierService.notifyPostBusinessEvent(new LoanBalanceChangedBusinessEvent(loan));
@@ -141,7 +141,7 @@ private CommandProcessingResult processUpdateInterestPause(Loan loan, Long varia
141141

142142
LoanTermVariations updatedVariation = loanTermVariationsRepository.save(variation);
143143

144-
reprocessLoanTransactionsService.reprocessTransactions(loan);
144+
loanScheduleService.regenerateScheduleWithReprocessingTransactions(loan);
145145

146146
businessEventNotifierService.notifyPostBusinessEvent(new LoanScheduleVariationsAddedBusinessEvent(loan));
147147
businessEventNotifierService.notifyPostBusinessEvent(new LoanBalanceChangedBusinessEvent(loan));
@@ -161,7 +161,7 @@ private CommandProcessingResult processInterestPause(final Loan loan, final Loca
161161
final LoanTermVariations savedVariation = loanTermVariationsRepository.saveAndFlush(variation);
162162
loan.getLoanTermVariations().add(savedVariation);
163163

164-
reprocessLoanTransactionsService.reprocessTransactions(loan);
164+
loanScheduleService.regenerateScheduleWithReprocessingTransactions(loan);
165165

166166
businessEventNotifierService.notifyPostBusinessEvent(new LoanScheduleVariationsAddedBusinessEvent(loan));
167167
businessEventNotifierService.notifyPostBusinessEvent(new LoanBalanceChangedBusinessEvent(loan));
Lines changed: 47 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,47 @@
1+
/**
2+
* Licensed to the Apache Software Foundation (ASF) under one
3+
* or more contributor license agreements. See the NOTICE file
4+
* distributed with this work for additional information
5+
* regarding copyright ownership. The ASF licenses this file
6+
* to you under the Apache License, Version 2.0 (the
7+
* "License"); you may not use this file except in compliance
8+
* with the License. You may obtain a copy of the License at
9+
*
10+
* http://www.apache.org/licenses/LICENSE-2.0
11+
*
12+
* Unless required by applicable law or agreed to in writing,
13+
* software distributed under the License is distributed on an
14+
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
15+
* KIND, either express or implied. See the License for the
16+
* specific language governing permissions and limitations
17+
* under the License.
18+
*/
19+
package org.apache.fineract.portfolio.loanaccount.service;
20+
21+
import java.time.LocalDate;
22+
import org.apache.fineract.portfolio.calendar.domain.Calendar;
23+
import org.apache.fineract.portfolio.group.domain.Group;
24+
import org.apache.fineract.portfolio.loanaccount.data.HolidayDetailDTO;
25+
import org.apache.fineract.portfolio.loanaccount.data.ScheduleGeneratorDTO;
26+
import org.apache.fineract.portfolio.loanaccount.domain.Loan;
27+
import org.apache.fineract.portfolio.loanaccount.domain.LoanTransactionType;
28+
29+
public interface ILoanUtilService {
30+
31+
ScheduleGeneratorDTO buildScheduleGeneratorDTO(Loan loan, LocalDate recalculateFrom);
32+
33+
ScheduleGeneratorDTO buildScheduleGeneratorDTO(Loan loan, LocalDate recalculateFrom, LocalDate rescheduleTill);
34+
35+
ScheduleGeneratorDTO buildScheduleGeneratorDTO(Loan loan, LocalDate recalculateFrom, LocalDate recalculateTill,
36+
HolidayDetailDTO holidayDetailDTO);
37+
38+
Boolean isLoanRepaymentsSyncWithMeeting(Group group, Calendar calendar);
39+
40+
LocalDate getCalculatedRepaymentsStartingFromDate(Loan loan);
41+
42+
HolidayDetailDTO constructHolidayDTO(Long officeId, LocalDate localDate);
43+
44+
void validateRepaymentTransactionType(LoanTransactionType repaymentTransactionType);
45+
46+
void checkClientOrGroupActive(Loan loan);
47+
}

0 commit comments

Comments
 (0)