This is an automated email from the ASF dual-hosted git repository.
adamsaghy pushed a commit to branch develop
in repository https://gitbox.apache.org/repos/asf/fineract.git
The following commit(s) were added to refs/heads/develop by this push:
new 18a55874ba FINERACT-2286: Make configurable the outstanding interest
strategy during asset owner transfer
18a55874ba is described below
commit 18a55874ba769f34b3942a8b8f40728b237d9211
Author: Adam Saghy <[email protected]>
AuthorDate: Wed May 21 15:12:37 2025 +0200
FINERACT-2286: Make configurable the outstanding interest strategy during
asset owner transfer
---
.../api/GlobalConfigurationConstants.java | 1 +
.../domain/ConfigurationDomainService.java | 1 +
.../test/helper/GlobalConfigurationHelper.java | 6 ++
.../test/messaging/event/EventCheckHelper.java | 21 +++--
.../AssetExternalizationStepDef.java | 35 ++++++--
.../features/AssetExternalization.feature | 97 ++++++++++++++++++++++
.../loan/LoanAccountOwnerTransferBusinessStep.java | 18 ++--
.../fineract/investor/domain/AttributeKey.java | 17 ++--
.../ExternalAssetOwnerLoanProductAttribute.java | 38 +++++++++
.../domain/ExternalAssetOwnerTransferDetails.java | 33 +++++++-
.../investor/service/AccountingServiceImpl.java | 4 +-
...wnerTransferOutstandingInterestCalculation.java | 69 +++++++++++++++
.../LoanAccountOwnerTransferServiceImpl.java | 17 ++--
.../module/investor/module-changelog-master.xml | 1 +
...wner_transfer_outstanding_interest_strategy.xml | 43 ++++++++++
.../LoanAccountOwnerTransferBusinessStepTest.java | 25 +++++-
.../service/AccountingServiceImplTest.java | 24 +++++-
.../LoanAccountOwnerTransferServiceTest.java | 27 +++++-
.../loanaccount/data/LoanAccountData.java | 22 +++--
.../loanaccount/guarantor/data/IGuarantor.java | 18 +---
.../service/LoanReadPlatformService.java | 0
.../service/LoanSummaryDataProvider.java | 0
.../service/LoanSummaryProviderDelegate.java | 0
...argeRepaymentScheduleProcessingWrapperTest.java | 6 ++
.../domain/ConfigurationDomainServiceJpa.java | 6 ++
.../ConvertChargeDataToSpecificChargeData.java | 15 ----
.../loanaccount/guarantor/data/GuarantorData.java | 3 +-
.../common/GlobalConfigurationHelper.java | 13 ++-
28 files changed, 474 insertions(+), 86 deletions(-)
diff --git
a/fineract-core/src/main/java/org/apache/fineract/infrastructure/configuration/api/GlobalConfigurationConstants.java
b/fineract-core/src/main/java/org/apache/fineract/infrastructure/configuration/api/GlobalConfigurationConstants.java
index 82d91b4989..3e6426a1d3 100644
---
a/fineract-core/src/main/java/org/apache/fineract/infrastructure/configuration/api/GlobalConfigurationConstants.java
+++
b/fineract-core/src/main/java/org/apache/fineract/infrastructure/configuration/api/GlobalConfigurationConstants.java
@@ -76,6 +76,7 @@ public final class GlobalConfigurationConstants {
public static final String NEXT_PAYMENT_DUE_DATE = "next-payment-due-date";
public static final String ENABLE_PAYMENT_HUB_INTEGRATION =
"enable-payment-hub-integration";
public static final String ENABLE_IMMEDIATE_CHARGE_ACCRUAL_POST_MATURITY =
"enable-immediate-charge-accrual-post-maturity";
+ public static final String
ASSET_OWNER_TRANSFER_OUTSTANDING_INTEREST_CALCULATION_STRATEGY =
"outstanding-interest-calculation-strategy-for-external-asset-transfer";
private GlobalConfigurationConstants() {}
}
diff --git
a/fineract-core/src/main/java/org/apache/fineract/infrastructure/configuration/domain/ConfigurationDomainService.java
b/fineract-core/src/main/java/org/apache/fineract/infrastructure/configuration/domain/ConfigurationDomainService.java
index e7482d16a1..7a138fb25f 100644
---
a/fineract-core/src/main/java/org/apache/fineract/infrastructure/configuration/domain/ConfigurationDomainService.java
+++
b/fineract-core/src/main/java/org/apache/fineract/infrastructure/configuration/domain/ConfigurationDomainService.java
@@ -145,4 +145,5 @@ public interface ConfigurationDomainService {
boolean isImmediateChargeAccrualPostMaturityEnabled();
+ String getAssetOwnerTransferOustandingInterestStrategy();
}
diff --git
a/fineract-e2e-tests-core/src/test/java/org/apache/fineract/test/helper/GlobalConfigurationHelper.java
b/fineract-e2e-tests-core/src/test/java/org/apache/fineract/test/helper/GlobalConfigurationHelper.java
index 224b6d76e9..fefacea9e6 100644
---
a/fineract-e2e-tests-core/src/test/java/org/apache/fineract/test/helper/GlobalConfigurationHelper.java
+++
b/fineract-e2e-tests-core/src/test/java/org/apache/fineract/test/helper/GlobalConfigurationHelper.java
@@ -74,4 +74,10 @@ public class GlobalConfigurationHelper {
boolean isEnabled =
BooleanUtils.toBoolean(updatedConfiguration.body().getEnabled());
assertThat(isEnabled).isEqualTo(true);
}
+
+ public GlobalConfigurationPropertyData getGlobalConfiguration(String
configKey) throws IOException {
+ Response<GlobalConfigurationPropertyData> configuration =
globalConfigurationApi.retrieveOneByName(configKey).execute();
+ ErrorHelper.checkSuccessfulApiCall(configuration);
+ return configuration.body();
+ }
}
diff --git
a/fineract-e2e-tests-core/src/test/java/org/apache/fineract/test/messaging/event/EventCheckHelper.java
b/fineract-e2e-tests-core/src/test/java/org/apache/fineract/test/messaging/event/EventCheckHelper.java
index abf0c196e6..6f7f7397f2 100644
---
a/fineract-e2e-tests-core/src/test/java/org/apache/fineract/test/messaging/event/EventCheckHelper.java
+++
b/fineract-e2e-tests-core/src/test/java/org/apache/fineract/test/messaging/event/EventCheckHelper.java
@@ -41,6 +41,7 @@ import
org.apache.fineract.client.models.GetClientsClientIdResponse;
import org.apache.fineract.client.models.GetLoansLoanIdDelinquencyPausePeriod;
import org.apache.fineract.client.models.GetLoansLoanIdResponse;
import org.apache.fineract.client.models.GetLoansLoanIdTransactions;
+import org.apache.fineract.client.models.GlobalConfigurationPropertyData;
import org.apache.fineract.client.models.PageExternalTransferData;
import org.apache.fineract.client.models.PostClientsResponse;
import org.apache.fineract.client.models.PostLoansLoanIdResponse;
@@ -53,6 +54,7 @@ import
org.apache.fineract.test.data.AssetExternalizationTransferStatus;
import org.apache.fineract.test.data.AssetExternalizationTransferStatusReason;
import org.apache.fineract.test.data.TransactionType;
import org.apache.fineract.test.helper.ErrorMessageHelper;
+import org.apache.fineract.test.helper.GlobalConfigurationHelper;
import org.apache.fineract.test.messaging.EventAssertion;
import
org.apache.fineract.test.messaging.event.assetexternalization.LoanAccountSnapshotEvent;
import
org.apache.fineract.test.messaging.event.assetexternalization.LoanOwnershipTransferEvent;
@@ -90,15 +92,14 @@ public class EventCheckHelper {
@Autowired
private ClientApi clientApi;
-
@Autowired
private LoansApi loansApi;
-
@Autowired
private EventAssertion eventAssertion;
-
@Autowired
private ExternalAssetOwnersApi externalAssetOwnersApi;
+ @Autowired
+ private GlobalConfigurationHelper configurationHelper;
public void clientEventCheck(Response<PostClientsResponse>
clientCreationResponse) throws IOException {
Response<GetClientsClientIdResponse> clientDetails =
clientApi.retrieveOne11(clientCreationResponse.body().getClientId(), false)
@@ -412,14 +413,24 @@ public class EventCheckHelper {
ExternalTransferData filtered = content.stream().filter(t ->
transferId.equals(t.getTransferId())).reduce((first, second) -> second)
.orElseThrow(() -> new IllegalStateException("No element
found"));
+ BigDecimal totalOutstandingBalanceAmountExpected =
zeroConversion(filtered.getDetails().getTotalOutstanding());
+ BigDecimal outstandingInterestPortionExpected =
zeroConversion(filtered.getDetails().getTotalInterestOutstanding());
+
+ GlobalConfigurationPropertyData outstandingInterestStrategy =
configurationHelper
+
.getGlobalConfiguration("outstanding-interest-calculation-strategy-for-external-asset-transfer");
+ if
("PAYABLE_OUTSTANDING_INTEREST".equals(outstandingInterestStrategy.getStringValue()))
{
+ Response<GetLoansLoanIdResponse> loanDetails =
loansApi.retrieveLoan(loanId, false, "all", null, null).execute();
+ totalOutstandingBalanceAmountExpected =
BigDecimal.valueOf(loanDetails.body().getSummary().getTotalOutstanding());
+ outstandingInterestPortionExpected =
BigDecimal.valueOf(loanDetails.body().getSummary().getInterestOutstanding());
+ }
+
String ownerExternalIdExpected =
filtered.getStatus().getValue().equals("BUYBACK") ? null :
filtered.getOwner().getExternalId();
String settlementDateExpected =
filtered.getStatus().getValue().equals("BUYBACK") ? null
: FORMATTER_EVENTS.format(filtered.getSettlementDate());
- BigDecimal totalOutstandingBalanceAmountExpected =
zeroConversion(filtered.getDetails().getTotalOutstanding());
BigDecimal outstandingPrincipalPortionExpected =
zeroConversion(filtered.getDetails().getTotalPrincipalOutstanding());
BigDecimal outstandingFeePortionExpected =
zeroConversion(filtered.getDetails().getTotalFeeChargesOutstanding());
BigDecimal outstandingPenaltyPortionExpected =
zeroConversion(filtered.getDetails().getTotalPenaltyChargesOutstanding());
- BigDecimal outstandingInterestPortionExpected =
zeroConversion(filtered.getDetails().getTotalInterestOutstanding());
+
BigDecimal overPaymentPortionExpected =
zeroConversion(filtered.getDetails().getTotalOverpaid());
eventAssertion.assertEvent(LoanAccountSnapshotEvent.class,
loanId).extractingData(LoanAccountDataV1::getId).isEqualTo(loanId)
diff --git
a/fineract-e2e-tests-core/src/test/java/org/apache/fineract/test/stepdef/assetexternalization/AssetExternalizationStepDef.java
b/fineract-e2e-tests-core/src/test/java/org/apache/fineract/test/stepdef/assetexternalization/AssetExternalizationStepDef.java
index 82d597abcb..b9f9fea0d2 100644
---
a/fineract-e2e-tests-core/src/test/java/org/apache/fineract/test/stepdef/assetexternalization/AssetExternalizationStepDef.java
+++
b/fineract-e2e-tests-core/src/test/java/org/apache/fineract/test/stepdef/assetexternalization/AssetExternalizationStepDef.java
@@ -341,11 +341,6 @@ public class AssetExternalizationStepDef extends
AbstractStepDef {
transferExternalId =
testContext().get(TestContextKey.ASSET_EXTERNALIZATION_SALES_TRANSFER_EXTERNAL_ID_FROM_RESPONSE);
}
- expectedValues.add(ownerExternalIdStored);
- expectedValues.add(loanId == null ? null : String.valueOf(loanId));
- expectedValues.add(loanExternalId);
- expectedValues.add(transferExternalId);
-
List<List<String>> actualValuesList = content.stream().map(t -> {
List<String> actualValues = new ArrayList<>();
actualValues.add(t.getSettlementDate() == null ? null :
FORMATTER.format(t.getSettlementDate()));
@@ -354,6 +349,31 @@ public class AssetExternalizationStepDef extends
AbstractStepDef {
actualValues.add(t.getEffectiveFrom() == null ? null :
FORMATTER.format(t.getEffectiveFrom()));
actualValues.add(t.getEffectiveTo() == null ? null :
FORMATTER.format(t.getEffectiveTo()));
actualValues.add(transactionType);
+ if (expectedValues.size() > 6) {
+ actualValues.add(
+ t.getDetails() != null ?
t.getDetails().getTotalOutstanding().setScale(2,
RoundingMode.HALF_DOWN).toString()
+ : null);
+ }
+ if (expectedValues.size() > 7) {
+ actualValues.add(t.getDetails() != null
+ ?
t.getDetails().getTotalPrincipalOutstanding().setScale(2,
RoundingMode.HALF_DOWN).toString()
+ : null);
+ }
+ if (expectedValues.size() > 8) {
+ actualValues.add(t.getDetails() != null
+ ?
t.getDetails().getTotalInterestOutstanding().setScale(2,
RoundingMode.HALF_DOWN).toString()
+ : null);
+ }
+ if (expectedValues.size() > 9) {
+ actualValues.add(t.getDetails() != null
+ ?
t.getDetails().getTotalFeeChargesOutstanding().setScale(2,
RoundingMode.HALF_DOWN).toString()
+ : null);
+ }
+ if (expectedValues.size() > 10) {
+ actualValues.add(t.getDetails() != null
+ ?
t.getDetails().getTotalPenaltyChargesOutstanding().setScale(2,
RoundingMode.HALF_DOWN).toString()
+ : null);
+ }
actualValues.add(t.getOwner().getExternalId() == null ? null :
t.getOwner().getExternalId());
actualValues.add(loanId == null ? null :
String.valueOf(t.getLoan().getLoanId()));
actualValues.add(loanExternalId == null ? null :
t.getLoan().getExternalId());
@@ -361,6 +381,11 @@ public class AssetExternalizationStepDef extends
AbstractStepDef {
return actualValues;
}).collect(Collectors.toList());
+ expectedValues.add(ownerExternalIdStored);
+ expectedValues.add(loanId == null ? null : String.valueOf(loanId));
+ expectedValues.add(loanExternalId);
+ expectedValues.add(transferExternalId);
+
boolean containsExpectedValues =
actualValuesList.stream().anyMatch(actualValues ->
actualValues.equals(expectedValues));
assertThat(numberOfElementsActual)
diff --git
a/fineract-e2e-tests-runner/src/test/resources/features/AssetExternalization.feature
b/fineract-e2e-tests-runner/src/test/resources/features/AssetExternalization.feature
index 327c9333aa..c205844b61 100644
---
a/fineract-e2e-tests-runner/src/test/resources/features/AssetExternalization.feature
+++
b/fineract-e2e-tests-runner/src/test/resources/features/AssetExternalization.feature
@@ -1679,3 +1679,100 @@ Feature: Asset Externalization
| INCOME | 404000 | Interest Income | CREDIT |
0.33 |
| ASSET | 112603 | Interest/Fee Receivable | DEBIT |
0.33 |
| INCOME | 404000 | Interest Income | CREDIT |
0.33 |
+
+ @TestRailId:C3690 @AssetExternalizationJournalEntry
+ Scenario: Verify that Asset externalization SALES and BUYBACK has the
correct Journal entries with PAYABLE_OUTSTANDING_INTEREST strategy
+ When Global config
"outstanding-interest-calculation-strategy-for-external-asset-transfer" value
set to "PAYABLE_OUTSTANDING_INTEREST"
+ When Admin sets the business date to "1 May 2023"
+ When 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_ACTUAL_ACTUAL | 01 May 2023 |
1000 | 12 | DECLINING_BALANCE | DAILY
| EQUAL_INSTALLMENTS | 6 | MONTHS | 1
| MONTHS | 6 | 0
| 0 | 0 |
ADVANCED_PAYMENT_ALLOCATION |
+ And Admin successfully approves the loan on "1 May 2023" with "1000"
amount and expected disbursement date on "1 May 2023"
+ When Admin successfully disburse the loan on "1 May 2023" with "1000" EUR
transaction amount
+ Then Loan status will be "ACTIVE"
+ When Admin makes asset externalization request by Loan ID with unique
ownerExternalId, system-generated transferExternalId and the following data:
+ | Transaction type | settlementDate | purchasePriceRatio |
+ | sale | 2023-05-21 | 1 |
+ Then Asset externalization response has the correct Loan ID,
transferExternalId
+ Then Fetching Asset externalization details by loan id gives
numberOfElements: 1 with correct ownerExternalId and the following data:
+ | settlementDate | purchasePriceRatio | status | effectiveFrom |
effectiveTo | Transaction type | totalOutstanding | totalPrincipalOutstanding |
totalInterestOutstanding | totalFeeChargesOutstanding |
totalPenaltyChargesOutstanding |
+ | 2023-05-21 | 1 | PENDING | 2023-05-01 |
9999-12-31 | SALE | | |
| |
|
+ When Admin adds "LOAN_SNOOZE_FEE" due date charge with "10 May 2023" due
date and 10 EUR transaction amount
+ When Admin sets the business date to "10 May 2023"
+ When Admin runs inline COB job for Loan
+ When Admin sets the business date to "22 May 2023"
+ When Admin runs inline COB job for Loan
+ Then LoanOwnershipTransferBusinessEvent is created
+ Then LoanAccountSnapshotBusinessEvent is created
+ Then Fetching Asset externalization details by loan id gives
numberOfElements: 2 with correct ownerExternalId and the following data:
+ | settlementDate | purchasePriceRatio | status | effectiveFrom |
effectiveTo | Transaction type | totalOutstanding | totalPrincipalOutstanding |
totalInterestOutstanding | totalFeeChargesOutstanding |
totalPenaltyChargesOutstanding |
+ | 2023-05-21 | 1 | PENDING | 2023-05-01 |
2023-05-21 | SALE | | |
| |
|
+ | 2023-05-21 | 1 | ACTIVE | 2023-05-22 |
9999-12-31 | SALE | 1016.58 | 1000.00 |
6.58 | 10.00 | 0.00
|
+ Then The latest asset externalization transaction with "ACTIVE" status has
the following TRANSFER Journal entries:
+ | glAccountType | glAccountCode | glAccountName | entryType |
amount |
+ | ASSET | 112601 | Loans Receivable | CREDIT |
1000.00 |
+ | ASSET | 112603 | Interest/Fee Receivable | CREDIT |
16.58 |
+ | ASSET | 146000 | Asset transfer | DEBIT |
1016.58 |
+ | ASSET | 112601 | Loans Receivable | DEBIT |
1000.00 |
+ | ASSET | 112603 | Interest/Fee Receivable | DEBIT |
16.58 |
+ | ASSET | 146000 | Asset transfer | CREDIT |
1016.58 |
+ Then The asset external owner has the following OWNER Journal entries:
+ | glAccountType | glAccountCode | glAccountName | entryType |
amount |
+ | ASSET | 112601 | Loans Receivable | DEBIT |
1000.00 |
+ | ASSET | 112603 | Interest/Fee Receivable | DEBIT |
16.58 |
+ When Admin makes asset externalization request by Loan ID with unique
ownerExternalId, system-generated transferExternalId and the following data:
+ | Transaction type | settlementDate | purchasePriceRatio |
+ | buyback | 2023-05-30 | |
+ Then Fetching Asset externalization details by loan id gives
numberOfElements: 3 with correct ownerExternalId and the following data:
+ | settlementDate | purchasePriceRatio | status | effectiveFrom |
effectiveTo | Transaction type | totalOutstanding | totalPrincipalOutstanding |
totalInterestOutstanding | totalFeeChargesOutstanding |
totalPenaltyChargesOutstanding |
+ | 2023-05-21 | 1 | PENDING | 2023-05-01 |
2023-05-21 | SALE | | |
| |
|
+ | 2023-05-21 | 1 | ACTIVE | 2023-05-22 |
9999-12-31 | SALE | 1016.58 | 1000.00 |
6.58 | 10.00 | 0.00
|
+ | 2023-05-30 | 1 | BUYBACK | 2023-05-22 |
9999-12-31 | BUYBACK | | |
| |
|
+ When Admin adds "LOAN_NSF_FEE" due date charge with "25 May 2023" due date
and 20 EUR transaction amount
+ When Admin sets the business date to "26 May 2023"
+ When Admin runs inline COB job for Loan
+ When Admin sets the business date to "31 May 2023"
+ When Admin runs inline COB job for Loan
+ Then LoanOwnershipTransferBusinessEvent is created
+ Then LoanAccountSnapshotBusinessEvent is created
+ Then Fetching Asset externalization details by loan id gives
numberOfElements: 3 with correct ownerExternalId and the following data:
+ | settlementDate | purchasePriceRatio | status | effectiveFrom |
effectiveTo | Transaction type | totalOutstanding | totalPrincipalOutstanding |
totalInterestOutstanding | totalFeeChargesOutstanding |
totalPenaltyChargesOutstanding |
+ | 2023-05-21 | 1 | PENDING | 2023-05-01 |
2023-05-21 | SALE | | |
| |
|
+ | 2023-05-21 | 1 | ACTIVE | 2023-05-22 |
2023-05-30 | SALE | 1016.58 | 1000.00 |
6.58 | 10.00 | 0.00
|
+ | 2023-05-30 | 1 | BUYBACK | 2023-05-22 |
2023-05-30 | BUYBACK | 1039.53 | 1000.00 |
9.53 | 10.00 | 20.00
|
+ Then The latest asset externalization transaction with "BUYBACK" status
has the following TRANSFER Journal entries:
+ | glAccountType | glAccountCode | glAccountName | entryType |
amount |
+ | ASSET | 112601 | Loans Receivable | DEBIT |
1000.00 |
+ | ASSET | 112603 | Interest/Fee Receivable | DEBIT |
39.53 |
+ | ASSET | 146000 | Asset transfer | CREDIT |
1039.53 |
+ | ASSET | 112601 | Loans Receivable | CREDIT |
1000.00 |
+ | ASSET | 112603 | Interest/Fee Receivable | CREDIT |
39.53 |
+ | ASSET | 146000 | Asset transfer | DEBIT |
1039.53 |
+ Then The asset external owner has the following OWNER Journal entries:
+ | glAccountType | glAccountCode | glAccountName | entryType |
amount |
+ | ASSET | 112601 | Loans Receivable | DEBIT |
1000.00 |
+ | ASSET | 112603 | Interest/Fee Receivable | DEBIT |
16.58 |
+ | ASSET | 112603 | Interest/Fee Receivable | DEBIT |
0.33 |
+ | INCOME | 404000 | Interest Income | CREDIT |
0.33 |
+ | ASSET | 112603 | Interest/Fee Receivable | DEBIT |
0.33 |
+ | INCOME | 404000 | Interest Income | CREDIT |
0.33 |
+ | ASSET | 112603 | Interest/Fee Receivable | DEBIT |
0.33 |
+ | INCOME | 404000 | Interest Income | CREDIT |
0.33 |
+ | ASSET | 112603 | Interest/Fee Receivable | DEBIT |
0.33 |
+ | INCOME | 404000 | Interest Income | CREDIT |
0.33 |
+ | ASSET | 112603 | Interest/Fee Receivable | DEBIT |
0.33 |
+ | INCOME | 404000 | Interest Income | CREDIT |
0.33 |
+ | ASSET | 112603 | Interest/Fee Receivable | DEBIT |
0.33 |
+ | INCOME | 404000 | Interest Income | CREDIT |
0.33 |
+ | ASSET | 112603 | Interest/Fee Receivable | DEBIT |
0.33 |
+ | INCOME | 404000 | Interest Income | CREDIT |
0.33 |
+ | ASSET | 112603 | Interest/Fee Receivable | DEBIT |
0.33 |
+ | INCOME | 404000 | Interest Income | CREDIT |
0.33 |
+ | ASSET | 112603 | Interest/Fee Receivable | DEBIT |
0.33 |
+ | INCOME | 404000 | Interest Income | CREDIT |
0.33 |
+ | ASSET | 112603 | Interest/Fee Receivable | DEBIT |
0.33 |
+ | INCOME | 404000 | Interest Income | CREDIT |
0.33 |
+ | ASSET | 112603 | Interest/Fee Receivable | DEBIT |
0.33 |
+ | INCOME | 404000 | Interest Income | CREDIT |
0.33 |
+ When Global config
"outstanding-interest-calculation-strategy-for-external-asset-transfer" value
set to "TOTAL_OUTSTANDING_INTEREST"
diff --git
a/fineract-investor/src/main/java/org/apache/fineract/investor/cob/loan/LoanAccountOwnerTransferBusinessStep.java
b/fineract-investor/src/main/java/org/apache/fineract/investor/cob/loan/LoanAccountOwnerTransferBusinessStep.java
index 752501c9b6..3ba0963ee3 100644
---
a/fineract-investor/src/main/java/org/apache/fineract/investor/cob/loan/LoanAccountOwnerTransferBusinessStep.java
+++
b/fineract-investor/src/main/java/org/apache/fineract/investor/cob/loan/LoanAccountOwnerTransferBusinessStep.java
@@ -21,7 +21,6 @@ package org.apache.fineract.investor.cob.loan;
import java.math.BigDecimal;
import java.time.LocalDate;
import java.util.List;
-import java.util.Objects;
import java.util.Optional;
import java.util.stream.Stream;
import lombok.RequiredArgsConstructor;
@@ -42,6 +41,7 @@ import
org.apache.fineract.investor.domain.ExternalAssetOwnerTransferRepository;
import org.apache.fineract.investor.domain.LoanOwnershipTransferBusinessEvent;
import org.apache.fineract.investor.service.AccountingService;
import org.apache.fineract.investor.service.DelayedSettlementAttributeService;
+import
org.apache.fineract.investor.service.ExternalAssetOwnerTransferOutstandingInterestCalculation;
import org.apache.fineract.investor.service.LoanTransferabilityService;
import org.apache.fineract.portfolio.loanaccount.domain.Loan;
import org.springframework.context.annotation.Conditional;
@@ -65,6 +65,7 @@ public class LoanAccountOwnerTransferBusinessStep implements
LoanCOBBusinessStep
private final BusinessEventNotifierService businessEventNotifierService;
private final LoanTransferabilityService loanTransferabilityService;
private final DelayedSettlementAttributeService
delayedSettlementAttributeService;
+ private final ExternalAssetOwnerTransferOutstandingInterestCalculation
externalAssetOwnerTransferOutstandingInterestCalculation;
@Override
public Loan execute(Loan loan) {
@@ -220,14 +221,13 @@ public class LoanAccountOwnerTransferBusinessStep
implements LoanCOBBusinessStep
ExternalAssetOwnerTransfer externalAssetOwnerTransfer) {
ExternalAssetOwnerTransferDetails details = new
ExternalAssetOwnerTransferDetails();
details.setExternalAssetOwnerTransfer(externalAssetOwnerTransfer);
-
details.setTotalOutstanding(Objects.requireNonNullElse(loan.getSummary().getTotalOutstanding(),
BigDecimal.ZERO));
-
details.setTotalPrincipalOutstanding(Objects.requireNonNullElse(loan.getSummary().getTotalPrincipalOutstanding(),
BigDecimal.ZERO));
-
details.setTotalInterestOutstanding(Objects.requireNonNullElse(loan.getSummary().getTotalInterestOutstanding(),
BigDecimal.ZERO));
- details.setTotalFeeChargesOutstanding(
-
Objects.requireNonNullElse(loan.getSummary().getTotalFeeChargesOutstanding(),
BigDecimal.ZERO));
- details.setTotalPenaltyChargesOutstanding(
-
Objects.requireNonNullElse(loan.getSummary().getTotalPenaltyChargesOutstanding(),
BigDecimal.ZERO));
-
details.setTotalOverpaid(Objects.requireNonNullElse(loan.getTotalOverpaid(),
BigDecimal.ZERO));
+
details.setTotalPrincipalOutstanding(loan.getSummary().getTotalPrincipalOutstanding());
+ // We have different strategies to calculate oustanding interest
+ final BigDecimal interestAmount =
externalAssetOwnerTransferOutstandingInterestCalculation.calculateOutstandingInterest(loan);
+ details.setTotalInterestOutstanding(interestAmount);
+
details.setTotalFeeChargesOutstanding(loan.getSummary().getTotalFeeChargesOutstanding());
+
details.setTotalPenaltyChargesOutstanding(loan.getSummary().getTotalPenaltyChargesOutstanding());
+ details.setTotalOverpaid(loan.getTotalOverpaid());
return details;
}
diff --git
a/fineract-provider/src/main/java/org/apache/fineract/portfolio/loanaccount/service/LoanSummaryProviderDelegate.java
b/fineract-investor/src/main/java/org/apache/fineract/investor/domain/AttributeKey.java
similarity index 54%
copy from
fineract-provider/src/main/java/org/apache/fineract/portfolio/loanaccount/service/LoanSummaryProviderDelegate.java
copy to
fineract-investor/src/main/java/org/apache/fineract/investor/domain/AttributeKey.java
index 20f9663fce..f874eaf1f8 100644
---
a/fineract-provider/src/main/java/org/apache/fineract/portfolio/loanaccount/service/LoanSummaryProviderDelegate.java
+++
b/fineract-investor/src/main/java/org/apache/fineract/investor/domain/AttributeKey.java
@@ -16,20 +16,13 @@
* specific language governing permissions and limitations
* under the License.
*/
-package org.apache.fineract.portfolio.loanaccount.service;
+package org.apache.fineract.investor.domain;
-import java.util.List;
-import lombok.AllArgsConstructor;
-import org.springframework.stereotype.Component;
+public interface AttributeKey {
-@Component
-@AllArgsConstructor
-public class LoanSummaryProviderDelegate {
+ String getKey();
- private final List<LoanSummaryDataProvider> loanSummaryDataProviders;
+ String getValue();
- public LoanSummaryDataProvider resolveLoanSummaryDataProvider(String
loanProcessingStrategyCode) {
- return loanSummaryDataProviders.stream().filter(provider ->
provider.accept(loanProcessingStrategyCode)).findAny()
- .orElseThrow(() -> new IllegalArgumentException("No provider
found for :" + loanProcessingStrategyCode));
- }
+ String getDescription();
}
diff --git
a/fineract-investor/src/main/java/org/apache/fineract/investor/domain/ExternalAssetOwnerLoanProductAttribute.java
b/fineract-investor/src/main/java/org/apache/fineract/investor/domain/ExternalAssetOwnerLoanProductAttribute.java
new file mode 100644
index 0000000000..fb08c38209
--- /dev/null
+++
b/fineract-investor/src/main/java/org/apache/fineract/investor/domain/ExternalAssetOwnerLoanProductAttribute.java
@@ -0,0 +1,38 @@
+/**
+ * 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.investor.domain;
+
+import lombok.Getter;
+import lombok.RequiredArgsConstructor;
+
+@RequiredArgsConstructor
+@Getter
+public class ExternalAssetOwnerLoanProductAttribute implements AttributeKey {
+
+ public static final ExternalAssetOwnerLoanProductAttribute
TOTAL_OUTSTANDING_INTEREST_STRATEGY = new
ExternalAssetOwnerLoanProductAttribute(
+ "OUTSTANDING_INTEREST_STRATEGY", "TOTAL_OUTSTANDING",
+ "During external owner transfer the total (due + not yet due +
projected) interest participate");
+ public static final ExternalAssetOwnerLoanProductAttribute
PAYABLE_OUTSTANDING_INTEREST_STRATEGY = new
ExternalAssetOwnerLoanProductAttribute(
+ "OUTSTANDING_INTEREST_STRATEGY", "PAYABLE_OUTSTANDING",
+ "During external owner transfer the total (due + not yet due)
interest participate");
+
+ private final String key;
+ private final String value;
+ private final String description;
+}
diff --git
a/fineract-investor/src/main/java/org/apache/fineract/investor/domain/ExternalAssetOwnerTransferDetails.java
b/fineract-investor/src/main/java/org/apache/fineract/investor/domain/ExternalAssetOwnerTransferDetails.java
index da1d29727d..13ae8323fb 100644
---
a/fineract-investor/src/main/java/org/apache/fineract/investor/domain/ExternalAssetOwnerTransferDetails.java
+++
b/fineract-investor/src/main/java/org/apache/fineract/investor/domain/ExternalAssetOwnerTransferDetails.java
@@ -25,18 +25,20 @@ import jakarta.persistence.JoinColumn;
import jakarta.persistence.OneToOne;
import jakarta.persistence.Table;
import java.math.BigDecimal;
+import java.util.Objects;
import lombok.Getter;
import lombok.NoArgsConstructor;
import lombok.Setter;
import
org.apache.fineract.infrastructure.core.domain.AbstractAuditableWithUTCDateTimeCustom;
+import org.apache.fineract.infrastructure.core.service.MathUtil;
@Getter
-@Setter
@Table(name = "m_external_asset_owner_transfer_details")
@NoArgsConstructor
@Entity
public class ExternalAssetOwnerTransferDetails extends
AbstractAuditableWithUTCDateTimeCustom<Long> {
+ @Setter
@OneToOne(cascade = CascadeType.ALL)
@JoinColumn(name = "asset_owner_transfer_id", referencedColumnName = "id")
private ExternalAssetOwnerTransfer externalAssetOwnerTransfer;
@@ -58,4 +60,33 @@ public class ExternalAssetOwnerTransferDetails extends
AbstractAuditableWithUTCD
@Column(name = "total_overpaid_derived", scale = 6, precision = 19,
nullable = false)
private BigDecimal totalOverpaid;
+
+ public void setTotalPrincipalOutstanding(BigDecimal
totalPrincipalOutstanding) {
+ this.totalPrincipalOutstanding =
Objects.requireNonNullElse(totalPrincipalOutstanding, BigDecimal.ZERO);
+ updateTotalOutstanding();
+ }
+
+ public void setTotalInterestOutstanding(BigDecimal
totalInterestOutstanding) {
+ this.totalInterestOutstanding =
Objects.requireNonNullElse(totalInterestOutstanding, BigDecimal.ZERO);
+ updateTotalOutstanding();
+ }
+
+ public void setTotalFeeChargesOutstanding(BigDecimal
totalFeeChargesOutstanding) {
+ this.totalFeeChargesOutstanding =
Objects.requireNonNullElse(totalFeeChargesOutstanding, BigDecimal.ZERO);
+ updateTotalOutstanding();
+ }
+
+ public void setTotalPenaltyChargesOutstanding(BigDecimal
totalPenaltyChargesOutstanding) {
+ this.totalPenaltyChargesOutstanding =
Objects.requireNonNullElse(totalPenaltyChargesOutstanding, BigDecimal.ZERO);
+ updateTotalOutstanding();
+ }
+
+ private void updateTotalOutstanding() {
+ this.totalOutstanding = MathUtil.add(getTotalPrincipalOutstanding(),
getTotalInterestOutstanding(), getTotalFeeChargesOutstanding(),
+ getTotalPenaltyChargesOutstanding());
+ }
+
+ public void setTotalOverpaid(BigDecimal totalOverpaid) {
+ this.totalOverpaid = Objects.requireNonNullElse(totalOverpaid,
BigDecimal.ZERO);
+ }
}
diff --git
a/fineract-investor/src/main/java/org/apache/fineract/investor/service/AccountingServiceImpl.java
b/fineract-investor/src/main/java/org/apache/fineract/investor/service/AccountingServiceImpl.java
index fe72d6182a..d60487a135 100644
---
a/fineract-investor/src/main/java/org/apache/fineract/investor/service/AccountingServiceImpl.java
+++
b/fineract-investor/src/main/java/org/apache/fineract/investor/service/AccountingServiceImpl.java
@@ -55,6 +55,7 @@ public class AccountingServiceImpl implements
AccountingService {
private final ExternalAssetOwnerTransferJournalEntryMappingRepository
externalAssetOwnerTransferJournalEntryMappingRepository;
private final ExternalAssetOwnerJournalEntryMappingRepository
externalAssetOwnerJournalEntryMappingRepository;
private final FinancialActivityAccountRepositoryWrapper
financialActivityAccountRepository;
+ private final ExternalAssetOwnerTransferOutstandingInterestCalculation
externalAssetOwnerTransferOutstandingInterestCalculation;
@Override
public void createJournalEntriesForSaleAssetTransfer(final Loan loan,
final ExternalAssetOwnerTransfer transfer,
@@ -104,7 +105,8 @@ public class AccountingServiceImpl implements
AccountingService {
final Long transactionId = transfer.getId();
final LocalDate transactionDate = transfer.getSettlementDate();
final BigDecimal principalAmount =
loan.getSummary().getTotalPrincipalOutstanding();
- final BigDecimal interestAmount =
loan.getSummary().getTotalInterestOutstanding();
+ // We have different strategies to calculate oustanding interest
+ final BigDecimal interestAmount =
externalAssetOwnerTransferOutstandingInterestCalculation.calculateOutstandingInterest(loan);
final BigDecimal feesAmount =
loan.getSummary().getTotalFeeChargesOutstanding();
final BigDecimal penaltiesAmount =
loan.getSummary().getTotalPenaltyChargesOutstanding();
final BigDecimal overPaymentAmount = loan.getTotalOverpaid();
diff --git
a/fineract-investor/src/main/java/org/apache/fineract/investor/service/ExternalAssetOwnerTransferOutstandingInterestCalculation.java
b/fineract-investor/src/main/java/org/apache/fineract/investor/service/ExternalAssetOwnerTransferOutstandingInterestCalculation.java
new file mode 100644
index 0000000000..46422b88c8
--- /dev/null
+++
b/fineract-investor/src/main/java/org/apache/fineract/investor/service/ExternalAssetOwnerTransferOutstandingInterestCalculation.java
@@ -0,0 +1,69 @@
+/**
+ * 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.investor.service;
+
+import java.math.BigDecimal;
+import lombok.RequiredArgsConstructor;
+import
org.apache.fineract.infrastructure.configuration.domain.ConfigurationDomainService;
+import org.apache.fineract.infrastructure.core.service.DateUtils;
+import org.apache.fineract.infrastructure.core.service.MathUtil;
+import org.apache.fineract.investor.config.InvestorModuleIsEnabledCondition;
+import org.apache.fineract.organisation.monetary.domain.Money;
+import org.apache.fineract.portfolio.loanaccount.data.LoanAccountData;
+import org.apache.fineract.portfolio.loanaccount.domain.Loan;
+import
org.apache.fineract.portfolio.loanaccount.service.LoanReadPlatformService;
+import
org.apache.fineract.portfolio.loanaccount.service.LoanSummaryDataProvider;
+import
org.apache.fineract.portfolio.loanaccount.service.LoanSummaryProviderDelegate;
+import org.springframework.context.annotation.Conditional;
+import org.springframework.stereotype.Component;
+
+@Component
+@RequiredArgsConstructor
+@Conditional(InvestorModuleIsEnabledCondition.class)
+public class ExternalAssetOwnerTransferOutstandingInterestCalculation {
+
+ private final LoanSummaryProviderDelegate loanSummaryDataProvider;
+ private final ConfigurationDomainService configurationDomainService;
+ private final LoanReadPlatformService loanReadPlatformService;
+
+ private LoanSummaryDataProvider fetchLoanSummaryDataProvider(Loan loan) {
+ return
this.loanSummaryDataProvider.resolveLoanSummaryDataProvider(loan.getTransactionProcessingStrategyCode());
+ }
+
+ public BigDecimal calculateOutstandingInterest(Loan loan) {
+ String outstandingInterestCalculationStrategy =
configurationDomainService.getAssetOwnerTransferOustandingInterestStrategy();
+ return switch (outstandingInterestCalculationStrategy) {
+ case "TOTAL_OUTSTANDING_INTEREST" ->
loan.getSummary().getTotalInterestOutstanding();
+ case "PAYABLE_OUTSTANDING_INTEREST" -> {
+ LoanAccountData data =
loanReadPlatformService.retrieveOne(loan.getId());
+ data =
loanReadPlatformService.fetchRepaymentScheduleData(data);
+ Money duePayableAmount = loan
+ .getRepaymentScheduleInstallments(i ->
!i.getDueDate().isAfter(DateUtils.getBusinessLocalDate())).stream()
+ .map(i ->
i.getInterestOutstanding(loan.getCurrency())).reduce(Money.zero(loan.getCurrency()),
MathUtil::plus);
+ BigDecimal notDuePayableAmount =
fetchLoanSummaryDataProvider(loan)
+
.computeTotalUnpaidPayableNotDueInterestAmountOnActualPeriod(loan,
data.getRepaymentSchedule().getPeriods(),
+ DateUtils.getBusinessLocalDate(),
loan.getCurrency().toData(), duePayableAmount.getAmount());
+
+ yield MathUtil.add(duePayableAmount.getAmount(),
notDuePayableAmount);
+ }
+ default -> throw new UnsupportedOperationException(
+ "Unknown outstanding interest calculation: " +
outstandingInterestCalculationStrategy);
+ };
+ }
+}
diff --git
a/fineract-investor/src/main/java/org/apache/fineract/investor/service/LoanAccountOwnerTransferServiceImpl.java
b/fineract-investor/src/main/java/org/apache/fineract/investor/service/LoanAccountOwnerTransferServiceImpl.java
index c638a06d8f..28876ff79e 100644
---
a/fineract-investor/src/main/java/org/apache/fineract/investor/service/LoanAccountOwnerTransferServiceImpl.java
+++
b/fineract-investor/src/main/java/org/apache/fineract/investor/service/LoanAccountOwnerTransferServiceImpl.java
@@ -35,7 +35,6 @@ import static
org.apache.fineract.investor.data.ExternalTransferSubStatus.UNSOLD
import java.math.BigDecimal;
import java.time.LocalDate;
import java.util.List;
-import java.util.Objects;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.apache.fineract.infrastructure.core.service.MathUtil;
@@ -63,6 +62,7 @@ public class LoanAccountOwnerTransferServiceImpl implements
LoanAccountOwnerTran
private final ExternalAssetOwnerTransferLoanMappingRepository
externalAssetOwnerTransferLoanMappingRepository;
private final AccountingService accountingService;
private final BusinessEventNotifierService businessEventNotifierService;
+ private final ExternalAssetOwnerTransferOutstandingInterestCalculation
externalAssetOwnerTransferOutstandingInterestCalculation;
@Override
public void handleLoanClosedOrOverpaid(Loan loan) {
@@ -166,14 +166,13 @@ public class LoanAccountOwnerTransferServiceImpl
implements LoanAccountOwnerTran
ExternalAssetOwnerTransfer externalAssetOwnerTransfer) {
ExternalAssetOwnerTransferDetails details = new
ExternalAssetOwnerTransferDetails();
details.setExternalAssetOwnerTransfer(externalAssetOwnerTransfer);
-
details.setTotalOutstanding(Objects.requireNonNullElse(loan.getSummary().getTotalOutstanding(),
BigDecimal.ZERO));
-
details.setTotalPrincipalOutstanding(Objects.requireNonNullElse(loan.getSummary().getTotalPrincipalOutstanding(),
BigDecimal.ZERO));
-
details.setTotalInterestOutstanding(Objects.requireNonNullElse(loan.getSummary().getTotalInterestOutstanding(),
BigDecimal.ZERO));
- details.setTotalFeeChargesOutstanding(
-
Objects.requireNonNullElse(loan.getSummary().getTotalFeeChargesOutstanding(),
BigDecimal.ZERO));
- details.setTotalPenaltyChargesOutstanding(
-
Objects.requireNonNullElse(loan.getSummary().getTotalPenaltyChargesOutstanding(),
BigDecimal.ZERO));
-
details.setTotalOverpaid(Objects.requireNonNullElse(loan.getTotalOverpaid(),
BigDecimal.ZERO));
+
details.setTotalPrincipalOutstanding(loan.getSummary().getTotalPrincipalOutstanding());
+ // We have different strategies to calculate oustanding interest
+ final BigDecimal interestAmount =
externalAssetOwnerTransferOutstandingInterestCalculation.calculateOutstandingInterest(loan);
+ details.setTotalInterestOutstanding(interestAmount);
+
details.setTotalFeeChargesOutstanding(loan.getSummary().getTotalFeeChargesOutstanding());
+
details.setTotalPenaltyChargesOutstanding(loan.getSummary().getTotalPenaltyChargesOutstanding());
+ details.setTotalOverpaid(loan.getTotalOverpaid());
return details;
}
diff --git
a/fineract-investor/src/main/resources/db/changelog/tenant/module/investor/module-changelog-master.xml
b/fineract-investor/src/main/resources/db/changelog/tenant/module/investor/module-changelog-master.xml
index b3e6f32eec..e96557908c 100644
---
a/fineract-investor/src/main/resources/db/changelog/tenant/module/investor/module-changelog-master.xml
+++
b/fineract-investor/src/main/resources/db/changelog/tenant/module/investor/module-changelog-master.xml
@@ -39,4 +39,5 @@
<include relativeToChangelogFile="true"
file="parts/0015_add_intermediary_sale_command.xml"/>
<include relativeToChangelogFile="true"
file="parts/0016_add_external_reference_id.xml"/>
<include relativeToChangelogFile="true"
file="parts/0017_add_external_asset_owner_loan_product_attr_index.xml"/>
+ <include relativeToChangelogFile="true"
file="parts/0018_add_external_asset_owner_transfer_outstanding_interest_strategy.xml"/>
</databaseChangeLog>
diff --git
a/fineract-investor/src/main/resources/db/changelog/tenant/module/investor/parts/0018_add_external_asset_owner_transfer_outstanding_interest_strategy.xml
b/fineract-investor/src/main/resources/db/changelog/tenant/module/investor/parts/0018_add_external_asset_owner_transfer_outstanding_interest_strategy.xml
new file mode 100644
index 0000000000..7004b0636b
--- /dev/null
+++
b/fineract-investor/src/main/resources/db/changelog/tenant/module/investor/parts/0018_add_external_asset_owner_transfer_outstanding_interest_strategy.xml
@@ -0,0 +1,43 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!--
+
+ 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.
+
+-->
+<databaseChangeLog xmlns="http://www.liquibase.org/xml/ns/dbchangelog"
+ xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
+
xsi:schemaLocation="http://www.liquibase.org/xml/ns/dbchangelog
+
https://www.liquibase.org/xml/ns/dbchangelog/dbchangelog-latest.xsd">
+
+ <changeSet author="fineract" id="1" context="postgresql">
+ <sql>
+ SELECT SETVAL('c_configuration_id_seq', COALESCE(MAX(id), 0)+1,
false ) FROM c_configuration;
+ </sql>
+ </changeSet>
+ <changeSet author="fineract" id="2">
+ <insert tableName="c_configuration">
+ <column name="name"
value="outstanding-interest-calculation-strategy-for-external-asset-transfer"/>
+ <column name="value"/>
+ <column name="date_value"/>
+ <column name="string_value" value="TOTAL_OUTSTANDING_INTEREST"/>
+ <column name="enabled" valueBoolean="true"/>
+ <column name="is_trap_door" valueBoolean="false"/>
+ <column name="description" value=" Available options:
TOTAL_OUTSTANDING_INTEREST, PAYABLE_OUTSTANDING_INTEREST. Define whether total
outstanding interest (due + not yet due + projected) or payable till transfer
date ( due + not yet due) should be involved in the asset transfer."/>
+ </insert>
+ </changeSet>
+</databaseChangeLog>
diff --git
a/fineract-investor/src/test/java/org/apache/fineract/investor/cob/loan/LoanAccountOwnerTransferBusinessStepTest.java
b/fineract-investor/src/test/java/org/apache/fineract/investor/cob/loan/LoanAccountOwnerTransferBusinessStepTest.java
index ed5fa3934c..39c5db4462 100644
---
a/fineract-investor/src/test/java/org/apache/fineract/investor/cob/loan/LoanAccountOwnerTransferBusinessStepTest.java
+++
b/fineract-investor/src/test/java/org/apache/fineract/investor/cob/loan/LoanAccountOwnerTransferBusinessStepTest.java
@@ -24,6 +24,7 @@ import static org.junit.jupiter.api.Assertions.assertThrows;
import static org.junit.jupiter.api.Assertions.assertTrue;
import static org.mockito.ArgumentMatchers.any;
import static org.mockito.ArgumentMatchers.eq;
+import static org.mockito.Mockito.mockStatic;
import static org.mockito.Mockito.never;
import static org.mockito.Mockito.times;
import static org.mockito.Mockito.verify;
@@ -31,6 +32,8 @@ import static org.mockito.Mockito.verifyNoInteractions;
import static org.mockito.Mockito.verifyNoMoreInteractions;
import static org.mockito.Mockito.when;
+import java.math.MathContext;
+import java.math.RoundingMode;
import java.time.LocalDate;
import java.time.ZoneId;
import java.util.HashMap;
@@ -55,12 +58,16 @@ import
org.apache.fineract.investor.domain.ExternalAssetOwnerTransferRepository;
import org.apache.fineract.investor.domain.LoanOwnershipTransferBusinessEvent;
import org.apache.fineract.investor.service.AccountingService;
import org.apache.fineract.investor.service.DelayedSettlementAttributeService;
+import
org.apache.fineract.investor.service.ExternalAssetOwnerTransferOutstandingInterestCalculation;
import org.apache.fineract.investor.service.LoanTransferabilityService;
+import org.apache.fineract.organisation.monetary.domain.MoneyHelper;
import org.apache.fineract.portfolio.loanaccount.domain.Loan;
import org.apache.fineract.portfolio.loanaccount.domain.LoanSummary;
import org.apache.fineract.portfolio.loanproduct.domain.LoanProduct;
import org.jetbrains.annotations.NotNull;
+import org.junit.jupiter.api.AfterAll;
import org.junit.jupiter.api.AfterEach;
+import org.junit.jupiter.api.BeforeAll;
import org.junit.jupiter.api.BeforeEach;
import org.junit.jupiter.api.Test;
import org.junit.jupiter.api.extension.ExtendWith;
@@ -69,6 +76,7 @@ import org.junit.jupiter.params.provider.Arguments;
import org.junit.jupiter.params.provider.MethodSource;
import org.mockito.ArgumentCaptor;
import org.mockito.Mock;
+import org.mockito.MockedStatic;
import org.mockito.Mockito;
import org.mockito.junit.jupiter.MockitoExtension;
import org.springframework.data.domain.Sort;
@@ -80,6 +88,7 @@ public class LoanAccountOwnerTransferBusinessStepTest {
public static final LocalDate FUTURE_DATE_9999_12_31 = LocalDate.of(9999,
12, 31);
private static final Long LOAN_PRODUCT_ID = 2L;
private final LocalDate actualDate = LocalDate.now(ZoneId.systemDefault());
+ private static final MockedStatic<MoneyHelper> MONEY_HELPER =
mockStatic(MoneyHelper.class);
@Mock
private ExternalAssetOwnerTransferRepository
externalAssetOwnerTransferRepository;
@@ -99,8 +108,22 @@ public class LoanAccountOwnerTransferBusinessStepTest {
@Mock
private DelayedSettlementAttributeService
delayedSettlementAttributeService;
+ @Mock
+ private ExternalAssetOwnerTransferOutstandingInterestCalculation
externalAssetOwnerTransferOutstandingInterestCalculation;
+
private LoanAccountOwnerTransferBusinessStep underTest;
+ @BeforeAll
+ public static void init() {
+
MONEY_HELPER.when(MoneyHelper::getRoundingMode).thenReturn(RoundingMode.HALF_EVEN);
+ MONEY_HELPER.when(MoneyHelper::getMathContext).thenReturn(new
MathContext(12, RoundingMode.HALF_EVEN));
+ }
+
+ @AfterAll
+ public static void destruct() {
+ MONEY_HELPER.close();
+ }
+
@BeforeEach
public void setUp() {
ThreadLocalContextUtil.setTenant(new FineractPlatformTenant(1L,
"default", "Default", "Asia/Kolkata", null));
@@ -108,7 +131,7 @@ public class LoanAccountOwnerTransferBusinessStepTest {
ThreadLocalContextUtil.setBusinessDates(new
HashMap<>(Map.of(BusinessDateType.BUSINESS_DATE, actualDate)));
underTest = new
LoanAccountOwnerTransferBusinessStep(externalAssetOwnerTransferRepository,
externalAssetOwnerTransferLoanMappingRepository,
accountingService, businessEventNotifierService,
- loanTransferabilityService, delayedSettlementAttributeService);
+ loanTransferabilityService, delayedSettlementAttributeService,
externalAssetOwnerTransferOutstandingInterestCalculation);
}
@AfterEach
diff --git
a/fineract-investor/src/test/java/org/apache/fineract/investor/service/AccountingServiceImplTest.java
b/fineract-investor/src/test/java/org/apache/fineract/investor/service/AccountingServiceImplTest.java
index 9e20c1e4ed..ad2d1816a5 100644
---
a/fineract-investor/src/test/java/org/apache/fineract/investor/service/AccountingServiceImplTest.java
+++
b/fineract-investor/src/test/java/org/apache/fineract/investor/service/AccountingServiceImplTest.java
@@ -27,11 +27,14 @@ import static org.mockito.ArgumentMatchers.anyInt;
import static org.mockito.ArgumentMatchers.eq;
import static org.mockito.Mockito.lenient;
import static org.mockito.Mockito.mock;
+import static org.mockito.Mockito.mockStatic;
import static org.mockito.Mockito.times;
import static org.mockito.Mockito.verify;
import static org.mockito.Mockito.when;
import java.math.BigDecimal;
+import java.math.MathContext;
+import java.math.RoundingMode;
import java.time.LocalDate;
import java.util.HashMap;
import java.util.List;
@@ -51,16 +54,20 @@ import
org.apache.fineract.investor.domain.ExternalAssetOwnerJournalEntryMapping
import org.apache.fineract.investor.domain.ExternalAssetOwnerTransfer;
import
org.apache.fineract.investor.domain.ExternalAssetOwnerTransferJournalEntryMapping;
import
org.apache.fineract.investor.domain.ExternalAssetOwnerTransferJournalEntryMappingRepository;
+import org.apache.fineract.organisation.monetary.domain.MoneyHelper;
import org.apache.fineract.organisation.office.domain.Office;
import org.apache.fineract.portfolio.loanaccount.domain.Loan;
import org.apache.fineract.portfolio.loanaccount.domain.LoanStatus;
import org.apache.fineract.portfolio.loanaccount.domain.LoanSummary;
+import org.junit.jupiter.api.AfterAll;
+import org.junit.jupiter.api.BeforeAll;
import org.junit.jupiter.api.BeforeEach;
import org.junit.jupiter.api.Test;
import org.junit.jupiter.api.extension.ExtendWith;
import org.mockito.ArgumentCaptor;
import org.mockito.InjectMocks;
import org.mockito.Mock;
+import org.mockito.MockedStatic;
import org.mockito.Mockito;
import org.mockito.MockitoAnnotations;
import org.mockito.junit.jupiter.MockitoExtension;
@@ -68,6 +75,19 @@ import org.mockito.junit.jupiter.MockitoExtension;
@ExtendWith(MockitoExtension.class)
class AccountingServiceImplTest {
+ private static final MockedStatic<MoneyHelper> MONEY_HELPER =
mockStatic(MoneyHelper.class);
+
+ @BeforeAll
+ public static void init() {
+
MONEY_HELPER.when(MoneyHelper::getRoundingMode).thenReturn(RoundingMode.HALF_EVEN);
+ MONEY_HELPER.when(MoneyHelper::getMathContext).thenReturn(new
MathContext(12, RoundingMode.HALF_EVEN));
+ }
+
+ @AfterAll
+ public static void destruct() {
+ MONEY_HELPER.close();
+ }
+
@BeforeEach
public void setUp() {
ThreadLocalContextUtil.setBusinessDates(new
HashMap<>(Map.of(BUSINESS_DATE, LocalDate.of(2024, 9, 27))));
@@ -517,6 +537,9 @@ class AccountingServiceImplTest {
@Mock
private FinancialActivityAccountRepositoryWrapper
financialActivityAccountRepository;
+ @Mock
+ private ExternalAssetOwnerTransferOutstandingInterestCalculation
externalAssetOwnerTransferOutstandingInterestCalculation;
+
@InjectMocks
private AccountingServiceImpl testSubject;
@@ -540,7 +563,6 @@ class AccountingServiceImplTest {
LoanSummary loanSummary = Mockito.mock(LoanSummary.class);
when(loanSummary.getTotalPrincipalOutstanding()).thenReturn(BigDecimal.ONE);
-
when(loanSummary.getTotalInterestOutstanding()).thenReturn(BigDecimal.ONE);
when(loanSummary.getTotalFeeChargesOutstanding()).thenReturn(BigDecimal.ONE);
when(loanSummary.getTotalPenaltyChargesOutstanding()).thenReturn(BigDecimal.ONE);
when(loan.getSummary()).thenReturn(loanSummary);
diff --git
a/fineract-investor/src/test/java/org/apache/fineract/investor/service/LoanAccountOwnerTransferServiceTest.java
b/fineract-investor/src/test/java/org/apache/fineract/investor/service/LoanAccountOwnerTransferServiceTest.java
index 430ff33a9b..ac409b363e 100644
---
a/fineract-investor/src/test/java/org/apache/fineract/investor/service/LoanAccountOwnerTransferServiceTest.java
+++
b/fineract-investor/src/test/java/org/apache/fineract/investor/service/LoanAccountOwnerTransferServiceTest.java
@@ -23,11 +23,14 @@ import static org.junit.jupiter.api.Assertions.assertEquals;
import static org.junit.jupiter.api.Assertions.assertTrue;
import static org.mockito.ArgumentMatchers.any;
import static org.mockito.ArgumentMatchers.eq;
+import static org.mockito.Mockito.mockStatic;
import static org.mockito.Mockito.times;
import static org.mockito.Mockito.verify;
import static org.mockito.Mockito.when;
import static org.springframework.data.domain.Sort.Direction.ASC;
+import java.math.MathContext;
+import java.math.RoundingMode;
import java.time.LocalDate;
import java.time.ZoneId;
import java.util.HashMap;
@@ -44,9 +47,12 @@ import
org.apache.fineract.investor.domain.ExternalAssetOwnerTransfer;
import
org.apache.fineract.investor.domain.ExternalAssetOwnerTransferLoanMappingRepository;
import
org.apache.fineract.investor.domain.ExternalAssetOwnerTransferRepository;
import org.apache.fineract.investor.domain.LoanOwnershipTransferBusinessEvent;
+import org.apache.fineract.organisation.monetary.domain.MoneyHelper;
import org.apache.fineract.portfolio.loanaccount.domain.Loan;
import org.apache.fineract.portfolio.loanaccount.domain.LoanSummary;
import org.jetbrains.annotations.NotNull;
+import org.junit.jupiter.api.AfterAll;
+import org.junit.jupiter.api.BeforeAll;
import org.junit.jupiter.api.BeforeEach;
import org.junit.jupiter.api.Test;
import org.junit.jupiter.api.extension.ExtendWith;
@@ -54,7 +60,9 @@ import org.junit.jupiter.params.ParameterizedTest;
import org.junit.jupiter.params.provider.Arguments;
import org.junit.jupiter.params.provider.MethodSource;
import org.mockito.ArgumentCaptor;
+import org.mockito.InjectMocks;
import org.mockito.Mock;
+import org.mockito.MockedStatic;
import org.mockito.Mockito;
import org.mockito.junit.jupiter.MockitoExtension;
import org.springframework.data.domain.Sort;
@@ -63,6 +71,7 @@ import org.springframework.data.jpa.domain.Specification;
@ExtendWith(MockitoExtension.class)
public class LoanAccountOwnerTransferServiceTest {
+ private static final MockedStatic<MoneyHelper> MONEY_HELPER =
mockStatic(MoneyHelper.class);
@Mock
private ExternalAssetOwnerTransferRepository
externalAssetOwnerTransferRepository;
@Mock
@@ -71,15 +80,27 @@ public class LoanAccountOwnerTransferServiceTest {
private AccountingService accountingService;
@Mock
private BusinessEventNotifierService businessEventNotifierService;
+ @Mock
+ private ExternalAssetOwnerTransferOutstandingInterestCalculation
externalAssetOwnerTransferOutstandingInterestCalculation;
- private LoanAccountOwnerTransferService underTest;
+ @InjectMocks
+ private LoanAccountOwnerTransferServiceImpl underTest;
private final LocalDate actualDate = LocalDate.now(ZoneId.systemDefault());
+ @BeforeAll
+ public static void init() {
+
MONEY_HELPER.when(MoneyHelper::getRoundingMode).thenReturn(RoundingMode.HALF_EVEN);
+ MONEY_HELPER.when(MoneyHelper::getMathContext).thenReturn(new
MathContext(12, RoundingMode.HALF_EVEN));
+ }
+
+ @AfterAll
+ public static void destruct() {
+ MONEY_HELPER.close();
+ }
+
@BeforeEach
public void setUp() {
ThreadLocalContextUtil.setBusinessDates(new
HashMap<>(Map.of(BUSINESS_DATE, actualDate)));
- underTest = new
LoanAccountOwnerTransferServiceImpl(externalAssetOwnerTransferRepository,
- externalAssetOwnerTransferLoanMappingRepository,
accountingService, businessEventNotifierService);
}
@Test
diff --git
a/fineract-provider/src/main/java/org/apache/fineract/portfolio/loanaccount/data/LoanAccountData.java
b/fineract-loan/src/main/java/org/apache/fineract/portfolio/loanaccount/data/LoanAccountData.java
similarity index 98%
rename from
fineract-provider/src/main/java/org/apache/fineract/portfolio/loanaccount/data/LoanAccountData.java
rename to
fineract-loan/src/main/java/org/apache/fineract/portfolio/loanaccount/data/LoanAccountData.java
index f2e4b2f355..333da377db 100644
---
a/fineract-provider/src/main/java/org/apache/fineract/portfolio/loanaccount/data/LoanAccountData.java
+++
b/fineract-loan/src/main/java/org/apache/fineract/portfolio/loanaccount/data/LoanAccountData.java
@@ -42,14 +42,13 @@ import
org.apache.fineract.portfolio.account.data.PortfolioAccountData;
import
org.apache.fineract.portfolio.accountdetails.data.LoanAccountSummaryData;
import org.apache.fineract.portfolio.calendar.data.CalendarData;
import org.apache.fineract.portfolio.charge.data.ChargeData;
-import
org.apache.fineract.portfolio.charge.util.ConvertChargeDataToSpecificChargeData;
import org.apache.fineract.portfolio.client.data.ClientData;
import org.apache.fineract.portfolio.delinquency.data.DelinquencyRangeData;
import org.apache.fineract.portfolio.floatingrates.data.InterestRatePeriodData;
import org.apache.fineract.portfolio.fund.data.FundData;
import org.apache.fineract.portfolio.group.data.GroupGeneralData;
import org.apache.fineract.portfolio.loanaccount.domain.LoanStatus;
-import org.apache.fineract.portfolio.loanaccount.guarantor.data.GuarantorData;
+import org.apache.fineract.portfolio.loanaccount.guarantor.data.IGuarantor;
import
org.apache.fineract.portfolio.loanaccount.loanschedule.data.LoanScheduleData;
import
org.apache.fineract.portfolio.loanproduct.data.LoanProductBorrowerCycleVariationData;
import org.apache.fineract.portfolio.loanproduct.data.LoanProductData;
@@ -146,7 +145,7 @@ public class LoanAccountData {
private Collection<LoanTransactionData> transactions;
private Collection<LoanChargeData> charges;
private Collection<LoanCollateralManagementData> collateral;
- private Collection<GuarantorData> guarantors;
+ private Collection<? extends IGuarantor> guarantors;
private CalendarData meeting;
private Collection<NoteData> notes;
private Collection<DisbursementData> disbursementDetails;
@@ -356,7 +355,7 @@ public class LoanAccountData {
final Collection<LoanChargeData> charges = new
ArrayList<LoanChargeData>();
for (final ChargeData charge : product.charges()) {
if (!charge.isOverdueInstallmentCharge()) {
-
charges.add(ConvertChargeDataToSpecificChargeData.toLoanChargeData(charge));
+ charges.add(toLoanChargeData(charge));
}
}
@@ -530,7 +529,7 @@ public class LoanAccountData {
*/
public LoanAccountData associationsAndTemplate(final LoanScheduleData
repaymentSchedule,
final Collection<LoanTransactionData> transactions, final
Collection<LoanChargeData> charges,
- final Collection<LoanCollateralManagementData> collateral, final
Collection<GuarantorData> guarantors,
+ final Collection<LoanCollateralManagementData> collateral, final
Collection<? extends IGuarantor> guarantors,
final CalendarData calendarData, final Collection<LoanProductData>
productOptions,
final Collection<EnumOptionData> termFrequencyTypeOptions, final
Collection<EnumOptionData> repaymentFrequencyTypeOptions,
final Collection<EnumOptionData>
repaymentFrequencyNthDayTypeOptions,
@@ -680,4 +679,17 @@ public class LoanAccountData {
public boolean isActive() {
return LoanStatus.fromInt(getStatus().getId().intValue()).isActive();
}
+
+ public static LoanChargeData toLoanChargeData(final ChargeData chargeData)
{
+
+ BigDecimal percentage = null;
+ if (chargeData.getChargeCalculationType().getId() == 2) {
+ percentage = chargeData.getAmount();
+ }
+
+ return LoanChargeData.newLoanChargeDetails(chargeData.getId(),
chargeData.getName(), chargeData.getCurrency(),
+ chargeData.getAmount(), percentage,
chargeData.getChargeTimeType(), chargeData.getChargeCalculationType(),
+ chargeData.isPenalty(), chargeData.getChargePaymentMode(),
chargeData.getMinCap(), chargeData.getMaxCap(),
+ ExternalId.empty());
+ }
}
diff --git
a/fineract-provider/src/main/java/org/apache/fineract/portfolio/loanaccount/service/LoanSummaryProviderDelegate.java
b/fineract-loan/src/main/java/org/apache/fineract/portfolio/loanaccount/guarantor/data/IGuarantor.java
similarity index 54%
copy from
fineract-provider/src/main/java/org/apache/fineract/portfolio/loanaccount/service/LoanSummaryProviderDelegate.java
copy to
fineract-loan/src/main/java/org/apache/fineract/portfolio/loanaccount/guarantor/data/IGuarantor.java
index 20f9663fce..cb1d911883 100644
---
a/fineract-provider/src/main/java/org/apache/fineract/portfolio/loanaccount/service/LoanSummaryProviderDelegate.java
+++
b/fineract-loan/src/main/java/org/apache/fineract/portfolio/loanaccount/guarantor/data/IGuarantor.java
@@ -16,20 +16,8 @@
* specific language governing permissions and limitations
* under the License.
*/
-package org.apache.fineract.portfolio.loanaccount.service;
+package org.apache.fineract.portfolio.loanaccount.guarantor.data;
-import java.util.List;
-import lombok.AllArgsConstructor;
-import org.springframework.stereotype.Component;
+import java.io.Serializable;
-@Component
-@AllArgsConstructor
-public class LoanSummaryProviderDelegate {
-
- private final List<LoanSummaryDataProvider> loanSummaryDataProviders;
-
- public LoanSummaryDataProvider resolveLoanSummaryDataProvider(String
loanProcessingStrategyCode) {
- return loanSummaryDataProviders.stream().filter(provider ->
provider.accept(loanProcessingStrategyCode)).findAny()
- .orElseThrow(() -> new IllegalArgumentException("No provider
found for :" + loanProcessingStrategyCode));
- }
-}
+public interface IGuarantor extends Serializable {}
diff --git
a/fineract-provider/src/main/java/org/apache/fineract/portfolio/loanaccount/service/LoanReadPlatformService.java
b/fineract-loan/src/main/java/org/apache/fineract/portfolio/loanaccount/service/LoanReadPlatformService.java
similarity index 100%
rename from
fineract-provider/src/main/java/org/apache/fineract/portfolio/loanaccount/service/LoanReadPlatformService.java
rename to
fineract-loan/src/main/java/org/apache/fineract/portfolio/loanaccount/service/LoanReadPlatformService.java
diff --git
a/fineract-provider/src/main/java/org/apache/fineract/portfolio/loanaccount/service/LoanSummaryDataProvider.java
b/fineract-loan/src/main/java/org/apache/fineract/portfolio/loanaccount/service/LoanSummaryDataProvider.java
similarity index 100%
rename from
fineract-provider/src/main/java/org/apache/fineract/portfolio/loanaccount/service/LoanSummaryDataProvider.java
rename to
fineract-loan/src/main/java/org/apache/fineract/portfolio/loanaccount/service/LoanSummaryDataProvider.java
diff --git
a/fineract-provider/src/main/java/org/apache/fineract/portfolio/loanaccount/service/LoanSummaryProviderDelegate.java
b/fineract-loan/src/main/java/org/apache/fineract/portfolio/loanaccount/service/LoanSummaryProviderDelegate.java
similarity index 100%
rename from
fineract-provider/src/main/java/org/apache/fineract/portfolio/loanaccount/service/LoanSummaryProviderDelegate.java
rename to
fineract-loan/src/main/java/org/apache/fineract/portfolio/loanaccount/service/LoanSummaryProviderDelegate.java
diff --git
a/fineract-loan/src/test/java/org/apache/fineract/portfolio/loanaccount/domain/SingleLoanChargeRepaymentScheduleProcessingWrapperTest.java
b/fineract-loan/src/test/java/org/apache/fineract/portfolio/loanaccount/domain/SingleLoanChargeRepaymentScheduleProcessingWrapperTest.java
index b8e124e090..2e82031343 100644
---
a/fineract-loan/src/test/java/org/apache/fineract/portfolio/loanaccount/domain/SingleLoanChargeRepaymentScheduleProcessingWrapperTest.java
+++
b/fineract-loan/src/test/java/org/apache/fineract/portfolio/loanaccount/domain/SingleLoanChargeRepaymentScheduleProcessingWrapperTest.java
@@ -44,6 +44,7 @@ import
org.apache.fineract.portfolio.charge.domain.ChargeCalculationType;
import org.apache.fineract.portfolio.charge.domain.ChargePaymentMode;
import org.apache.fineract.portfolio.charge.domain.ChargeTimeType;
import org.jetbrains.annotations.NotNull;
+import org.junit.jupiter.api.AfterAll;
import org.junit.jupiter.api.BeforeAll;
import org.junit.jupiter.api.Test;
import org.mockito.ArgumentCaptor;
@@ -69,6 +70,11 @@ public class
SingleLoanChargeRepaymentScheduleProcessingWrapperTest {
MONEY_HELPER.when(MoneyHelper::getMathContext).thenReturn(new
MathContext(12, RoundingMode.HALF_EVEN));
}
+ @AfterAll
+ public static void destruct() {
+ MONEY_HELPER.close();
+ }
+
@Test
public void testOnePeriodWithFeeCharge() {
LocalDate disbursementDate = LocalDate.of(2023, 1, 1);
diff --git
a/fineract-provider/src/main/java/org/apache/fineract/infrastructure/configuration/domain/ConfigurationDomainServiceJpa.java
b/fineract-provider/src/main/java/org/apache/fineract/infrastructure/configuration/domain/ConfigurationDomainServiceJpa.java
index 2e8558184a..cc17cad248 100644
---
a/fineract-provider/src/main/java/org/apache/fineract/infrastructure/configuration/domain/ConfigurationDomainServiceJpa.java
+++
b/fineract-provider/src/main/java/org/apache/fineract/infrastructure/configuration/domain/ConfigurationDomainServiceJpa.java
@@ -527,4 +527,10 @@ public class ConfigurationDomainServiceJpa implements
ConfigurationDomainService
public boolean isImmediateChargeAccrualPostMaturityEnabled() {
return
getGlobalConfigurationPropertyData(GlobalConfigurationConstants.ENABLE_IMMEDIATE_CHARGE_ACCRUAL_POST_MATURITY).isEnabled();
}
+
+ @Override
+ public String getAssetOwnerTransferOustandingInterestStrategy() {
+ return getGlobalConfigurationPropertyData(
+
GlobalConfigurationConstants.ASSET_OWNER_TRANSFER_OUTSTANDING_INTEREST_CALCULATION_STRATEGY).getStringValue();
+ }
}
diff --git
a/fineract-provider/src/main/java/org/apache/fineract/portfolio/charge/util/ConvertChargeDataToSpecificChargeData.java
b/fineract-provider/src/main/java/org/apache/fineract/portfolio/charge/util/ConvertChargeDataToSpecificChargeData.java
index 8f50d46c1f..ac2a6c2aa8 100644
---
a/fineract-provider/src/main/java/org/apache/fineract/portfolio/charge/util/ConvertChargeDataToSpecificChargeData.java
+++
b/fineract-provider/src/main/java/org/apache/fineract/portfolio/charge/util/ConvertChargeDataToSpecificChargeData.java
@@ -21,9 +21,7 @@ package org.apache.fineract.portfolio.charge.util;
import java.math.BigDecimal;
import java.time.LocalDate;
import java.util.Collection;
-import org.apache.fineract.infrastructure.core.domain.ExternalId;
import org.apache.fineract.portfolio.charge.data.ChargeData;
-import org.apache.fineract.portfolio.loanaccount.data.LoanChargeData;
import org.apache.fineract.portfolio.savings.data.SavingsAccountChargeData;
import org.apache.fineract.portfolio.shareaccounts.data.ShareAccountChargeData;
@@ -31,19 +29,6 @@ public final class ConvertChargeDataToSpecificChargeData {
private ConvertChargeDataToSpecificChargeData() {}
- public static LoanChargeData toLoanChargeData(final ChargeData chargeData)
{
-
- BigDecimal percentage = null;
- if (chargeData.getChargeCalculationType().getId() == 2) {
- percentage = chargeData.getAmount();
- }
-
- return LoanChargeData.newLoanChargeDetails(chargeData.getId(),
chargeData.getName(), chargeData.getCurrency(),
- chargeData.getAmount(), percentage,
chargeData.getChargeTimeType(), chargeData.getChargeCalculationType(),
- chargeData.isPenalty(), chargeData.getChargePaymentMode(),
chargeData.getMinCap(), chargeData.getMaxCap(),
- ExternalId.empty());
- }
-
public static SavingsAccountChargeData toSavingsAccountChargeData(final
ChargeData chargeData) {
final Long savingsChargeId = null;
diff --git
a/fineract-provider/src/main/java/org/apache/fineract/portfolio/loanaccount/guarantor/data/GuarantorData.java
b/fineract-provider/src/main/java/org/apache/fineract/portfolio/loanaccount/guarantor/data/GuarantorData.java
index ea293c89f4..4bdd36bea3 100644
---
a/fineract-provider/src/main/java/org/apache/fineract/portfolio/loanaccount/guarantor/data/GuarantorData.java
+++
b/fineract-provider/src/main/java/org/apache/fineract/portfolio/loanaccount/guarantor/data/GuarantorData.java
@@ -19,7 +19,6 @@
package org.apache.fineract.portfolio.loanaccount.guarantor.data;
import java.io.Serial;
-import java.io.Serializable;
import java.math.BigDecimal;
import java.time.LocalDate;
import java.util.Collection;
@@ -34,7 +33,7 @@ import
org.apache.fineract.portfolio.loanaccount.guarantor.domain.GuarantorType;
import
org.apache.fineract.portfolio.loanaccount.guarantor.service.GuarantorEnumerations;
@Getter
-public class GuarantorData implements Serializable {
+public class GuarantorData implements IGuarantor {
@Serial
private static final long serialVersionUID = 1L;
diff --git
a/integration-tests/src/test/java/org/apache/fineract/integrationtests/common/GlobalConfigurationHelper.java
b/integration-tests/src/test/java/org/apache/fineract/integrationtests/common/GlobalConfigurationHelper.java
index bc0e0f2970..e636d63460 100644
---
a/integration-tests/src/test/java/org/apache/fineract/integrationtests/common/GlobalConfigurationHelper.java
+++
b/integration-tests/src/test/java/org/apache/fineract/integrationtests/common/GlobalConfigurationHelper.java
@@ -105,8 +105,8 @@ public class GlobalConfigurationHelper {
ArrayList<HashMap> expectedGlobalConfigurations =
getAllDefaultGlobalConfigurations();
GetGlobalConfigurationsResponse actualGlobalConfigurations =
getAllGlobalConfigurations();
- Assertions.assertEquals(56, expectedGlobalConfigurations.size());
- Assertions.assertEquals(56,
actualGlobalConfigurations.getGlobalConfiguration().size());
+ Assertions.assertEquals(57, expectedGlobalConfigurations.size());
+ Assertions.assertEquals(57,
actualGlobalConfigurations.getGlobalConfiguration().size());
for (int i = 0; i < expectedGlobalConfigurations.size(); i++) {
@@ -540,6 +540,15 @@ public class GlobalConfigurationHelper {
enableImmediateChargeAccrualPostMaturity.put("trapDoor", false);
defaults.add(enableImmediateChargeAccrualPostMaturity);
+ HashMap<String, Object> assetOwnerTransferInterestOutstandingStrategy
= new HashMap<>();
+ assetOwnerTransferInterestOutstandingStrategy.put("name",
+
GlobalConfigurationConstants.ASSET_OWNER_TRANSFER_OUTSTANDING_INTEREST_CALCULATION_STRATEGY);
+ assetOwnerTransferInterestOutstandingStrategy.put("value", 0L);
+ assetOwnerTransferInterestOutstandingStrategy.put("enabled", false);
+ assetOwnerTransferInterestOutstandingStrategy.put("trapDoor", false);
+ assetOwnerTransferInterestOutstandingStrategy.put("string_value",
"TOTAL_OUTSTANDING_INTEREST");
+ defaults.add(assetOwnerTransferInterestOutstandingStrategy);
+
return defaults;
}