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 544607a05a FINERACT-2232: Capitalized Incomce Adjustment template
544607a05a is described below
commit 544607a05a5898182e798bf5f4cde9aef6a3d94e
Author: Jose Alberto Hernandez <[email protected]>
AuthorDate: Fri May 9 12:05:37 2025 -0500
FINERACT-2232: Capitalized Incomce Adjustment template
---
.../apache/fineract/test/data/TransactionType.java | 4 +-
.../test/stepdef/loan/LoanRepaymentStepDef.java | 2 +-
.../loanaccount/api/LoanApiConstants.java | 1 +
.../api/LoanTransactionApiConstants.java | 1 +
.../loanaccount/data/LoanTransactionData.java | 30 ++++++++
.../loanaccount/domain/LoanTransaction.java | 4 ++
.../loanaccount/domain/LoanTransactionType.java | 6 ++
.../service/LoanReadPlatformService.java | 2 +-
.../loanproduct/service/LoanEnumerations.java | 3 +
.../CapitalizedIncomeWritePlatformServiceImpl.java | 5 +-
.../api/LoanTransactionsApiResource.java | 20 ++++--
.../service/LoanReadPlatformServiceImpl.java | 79 +++++++++++++++++++++-
.../starter/LoanAccountConfiguration.java | 7 +-
.../integrationtests/BaseLoanIntegrationTest.java | 2 +-
.../integrationtests/LoanTransactionTest.java | 62 +++++++++++++++--
.../common/loans/LoanTransactionHelper.java | 17 ++++-
16 files changed, 221 insertions(+), 24 deletions(-)
diff --git
a/fineract-e2e-tests-core/src/test/java/org/apache/fineract/test/data/TransactionType.java
b/fineract-e2e-tests-core/src/test/java/org/apache/fineract/test/data/TransactionType.java
index cd73614f3d..ebb16e6577 100644
---
a/fineract-e2e-tests-core/src/test/java/org/apache/fineract/test/data/TransactionType.java
+++
b/fineract-e2e-tests-core/src/test/java/org/apache/fineract/test/data/TransactionType.java
@@ -35,7 +35,9 @@ public enum TransactionType {
INTEREST_PAYMENT_WAIVER("interestPaymentWaiver"), //
REPAYMENT_AT_DISBURSEMENT("repaymentAtDisbursement"), //
CAPITALIZED_INCOME("capitalizedIncome"), //
- CAPITALIZED_INCOME_AMORTIZATION("capitalizedIncomeAmortization"); //
+ CAPITALIZED_INCOME_AMORTIZATION("capitalizedIncomeAmortization"), //
+ CAPITALIZED_INCOME_ADJUSTMENT("capitalizedIncomeAdjustment"), //
+ ;
public final String value;
diff --git
a/fineract-e2e-tests-core/src/test/java/org/apache/fineract/test/stepdef/loan/LoanRepaymentStepDef.java
b/fineract-e2e-tests-core/src/test/java/org/apache/fineract/test/stepdef/loan/LoanRepaymentStepDef.java
index e0e0e93705..6530aede29 100644
---
a/fineract-e2e-tests-core/src/test/java/org/apache/fineract/test/stepdef/loan/LoanRepaymentStepDef.java
+++
b/fineract-e2e-tests-core/src/test/java/org/apache/fineract/test/stepdef/loan/LoanRepaymentStepDef.java
@@ -579,7 +579,7 @@ public class LoanRepaymentStepDef extends AbstractStepDef {
Response<PostLoansResponse> loanResponse =
testContext().get(TestContextKey.LOAN_CREATE_RESPONSE);
long loanId1 = loanResponse.body().getLoanId();
Response<GetLoansLoanIdTransactionsTemplateResponse> response =
loanTransactionsApi
- .retrieveTransactionTemplate(loanId1, "prepayLoan",
DATE_FORMAT, transactionDate, DEFAULT_LOCALE).execute();
+ .retrieveTransactionTemplate(loanId1, "prepayLoan",
DATE_FORMAT, transactionDate, DEFAULT_LOCALE, null).execute();
Double transactionAmount = response.body().getAmount();
log.debug("%n--- Loan Pay-off with amount: {} ---", transactionAmount);
diff --git
a/fineract-loan/src/main/java/org/apache/fineract/portfolio/loanaccount/api/LoanApiConstants.java
b/fineract-loan/src/main/java/org/apache/fineract/portfolio/loanaccount/api/LoanApiConstants.java
index 62dfbd146e..e6db7ed52b 100644
---
a/fineract-loan/src/main/java/org/apache/fineract/portfolio/loanaccount/api/LoanApiConstants.java
+++
b/fineract-loan/src/main/java/org/apache/fineract/portfolio/loanaccount/api/LoanApiConstants.java
@@ -175,6 +175,7 @@ public interface LoanApiConstants {
String CHARGEBACK_TRANSACTION_COMMAND = "chargeback";
String MARK_AS_FRAUD_COMMAND = "markAsFraud";
String CAPITALIZED_INCOME_TRANSACTION_COMMAND = "capitalizedIncome";
+ String CAPITALIZED_INCOME_ADJUSTMENT_TRANSACTION_COMMAND =
"capitalizedIncomeAdjustment";
// Data Validator names
String LOAN_FRAUD_DATAVALIDATOR_PREFIX = "loans.fraud";
diff --git
a/fineract-loan/src/main/java/org/apache/fineract/portfolio/loanaccount/api/LoanTransactionApiConstants.java
b/fineract-loan/src/main/java/org/apache/fineract/portfolio/loanaccount/api/LoanTransactionApiConstants.java
index 70de654919..23a426ec77 100644
---
a/fineract-loan/src/main/java/org/apache/fineract/portfolio/loanaccount/api/LoanTransactionApiConstants.java
+++
b/fineract-loan/src/main/java/org/apache/fineract/portfolio/loanaccount/api/LoanTransactionApiConstants.java
@@ -54,5 +54,6 @@ public interface LoanTransactionApiConstants {
accrualAdjustment, //
capitalizedIncome, //
capitalizedIncomeAmortization, //
+ capitalizedIncomeAdjustment, //
}
}
diff --git
a/fineract-loan/src/main/java/org/apache/fineract/portfolio/loanaccount/data/LoanTransactionData.java
b/fineract-loan/src/main/java/org/apache/fineract/portfolio/loanaccount/data/LoanTransactionData.java
index c9a9ced865..abcf285169 100644
---
a/fineract-loan/src/main/java/org/apache/fineract/portfolio/loanaccount/data/LoanTransactionData.java
+++
b/fineract-loan/src/main/java/org/apache/fineract/portfolio/loanaccount/data/LoanTransactionData.java
@@ -313,6 +313,36 @@ public class LoanTransactionData implements Serializable {
null, null, outstandingLoanBalance, null, manuallyReversed,
ExternalId.empty(), null, loanId);
}
+ public static LoanTransactionData
loanTransactionDataForCreditTemplate(final LoanTransactionEnumData
transactionType,
+ final LocalDate transactionDate, final BigDecimal
transactionAmount, final Collection<PaymentTypeData> paymentOptions,
+ final CurrencyData currency) {
+ final Long id = null;
+ final Long loanId = null;
+ final ExternalId externalLoanId = ExternalId.empty();
+ final ExternalId externalId = ExternalId.empty();
+ final Long officeId = null;
+ final String officeName = null;
+ final PaymentDetailData paymentDetailData = null;
+ final BigDecimal unrecognizedIncomePortion = null;
+ final BigDecimal principalPortion = null;
+ final BigDecimal interestPortion = null;
+ final BigDecimal feeChargesPortion = null;
+ final BigDecimal penaltyChargesPortion = null;
+ final BigDecimal overpaymentPortion = null;
+ final BigDecimal netDisbursalAmount = null;
+ final BigDecimal fixedEmiAmount = null;
+ final BigDecimal outstandingLoanBalance = null;
+ final AccountTransferData transfer = null;
+ final LocalDate submittedOnDate = null;
+ final LocalDate possibleNextRepaymentDate = null;
+ final boolean manuallyReversed = false;
+ return new LoanTransactionData(id, officeId, officeName,
transactionType, paymentDetailData, currency, transactionDate,
+ transactionAmount, netDisbursalAmount, principalPortion,
interestPortion, feeChargesPortion, penaltyChargesPortion,
+ overpaymentPortion, unrecognizedIncomePortion, paymentOptions,
transfer, externalId, fixedEmiAmount, outstandingLoanBalance,
+ submittedOnDate, manuallyReversed, possibleNextRepaymentDate,
loanId, externalLoanId);
+
+ }
+
public static LoanTransactionData
loanTransactionDataForDisbursalTemplate(final LoanTransactionEnumData
transactionType,
final LocalDate expectedDisbursedOnLocalDateForTemplate, final
BigDecimal disburseAmountForTemplate,
final BigDecimal netDisbursalAmount, final
Collection<PaymentTypeData> paymentOptions, final BigDecimal
retriveLastEmiAmount,
diff --git
a/fineract-loan/src/main/java/org/apache/fineract/portfolio/loanaccount/domain/LoanTransaction.java
b/fineract-loan/src/main/java/org/apache/fineract/portfolio/loanaccount/domain/LoanTransaction.java
index 55a29f5e73..47f4ef5303 100644
---
a/fineract-loan/src/main/java/org/apache/fineract/portfolio/loanaccount/domain/LoanTransaction.java
+++
b/fineract-loan/src/main/java/org/apache/fineract/portfolio/loanaccount/domain/LoanTransaction.java
@@ -650,6 +650,10 @@ public class LoanTransaction extends
AbstractAuditableWithUTCDateTimeCustom<Long
return
LoanTransactionType.CAPITALIZED_INCOME_AMORTIZATION.equals(getTypeOf()) &&
isNotReversed();
}
+ public boolean isCapitalizedIncomeAdjustment() {
+ return
LoanTransactionType.CAPITALIZED_INCOME_ADJUSTMENT.equals(getTypeOf()) &&
isNotReversed();
+ }
+
public boolean isWaiver() {
return isInterestWaiver() || isChargesWaiver();
}
diff --git
a/fineract-loan/src/main/java/org/apache/fineract/portfolio/loanaccount/domain/LoanTransactionType.java
b/fineract-loan/src/main/java/org/apache/fineract/portfolio/loanaccount/domain/LoanTransactionType.java
index 195b4e4363..2eb37e7a27 100644
---
a/fineract-loan/src/main/java/org/apache/fineract/portfolio/loanaccount/domain/LoanTransactionType.java
+++
b/fineract-loan/src/main/java/org/apache/fineract/portfolio/loanaccount/domain/LoanTransactionType.java
@@ -69,6 +69,7 @@ public enum LoanTransactionType {
ACCRUAL_ADJUSTMENT(34, "loanTransactionType.accrualAdjustment"), //
CAPITALIZED_INCOME(35, "loanTransactionType.capitalizedIncome"), //
CAPITALIZED_INCOME_AMORTIZATION(36,
"loanTransactionType.capitalizedIncomeAmortization"), //
+ CAPITALIZED_INCOME_ADJUSTMENT(37,
"loanTransactionType.capitalizedIncomeAdjustment"), //
;
private final Integer value;
@@ -121,6 +122,7 @@ public enum LoanTransactionType {
case 34 -> LoanTransactionType.ACCRUAL_ADJUSTMENT;
case 35 -> LoanTransactionType.CAPITALIZED_INCOME;
case 36 -> LoanTransactionType.CAPITALIZED_INCOME_AMORTIZATION;
+ case 37 -> LoanTransactionType.CAPITALIZED_INCOME_ADJUSTMENT;
default -> LoanTransactionType.INVALID;
};
}
@@ -241,4 +243,8 @@ public enum LoanTransactionType {
public boolean isCapitalizedIncome() {
return this == LoanTransactionType.CAPITALIZED_INCOME;
}
+
+ public boolean isCapitalizedIncomeAdjustment() {
+ return this == LoanTransactionType.CAPITALIZED_INCOME_ADJUSTMENT;
+ }
}
diff --git
a/fineract-loan/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
index c81a5d73f0..cdff9421ba 100644
---
a/fineract-loan/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
@@ -63,7 +63,7 @@ public interface LoanReadPlatformService {
LoanTransactionData retrieveLoanTransactionTemplate(Long loanId);
- LoanTransactionData retrieveLoanTransactionTemplate(Long loanId,
LoanTransactionType transactionType);
+ LoanTransactionData retrieveLoanTransactionTemplate(Long loanId,
LoanTransactionType transactionType, Long transactionId);
LoanTransactionData retrieveWaiveInterestDetails(Long loanId);
diff --git
a/fineract-loan/src/main/java/org/apache/fineract/portfolio/loanproduct/service/LoanEnumerations.java
b/fineract-loan/src/main/java/org/apache/fineract/portfolio/loanproduct/service/LoanEnumerations.java
index f3c77f5725..807def9364 100644
---
a/fineract-loan/src/main/java/org/apache/fineract/portfolio/loanproduct/service/LoanEnumerations.java
+++
b/fineract-loan/src/main/java/org/apache/fineract/portfolio/loanproduct/service/LoanEnumerations.java
@@ -330,6 +330,9 @@ public final class LoanEnumerations {
case CAPITALIZED_INCOME_AMORTIZATION ->
new
LoanTransactionEnumData(LoanTransactionType.CAPITALIZED_INCOME_AMORTIZATION.getValue().longValue(),
LoanTransactionType.CAPITALIZED_INCOME_AMORTIZATION.getCode(), "Capitalized
Income Amortization");
+ case CAPITALIZED_INCOME_ADJUSTMENT ->
+ new
LoanTransactionEnumData(LoanTransactionType.CAPITALIZED_INCOME_ADJUSTMENT.getValue().longValue(),
+
LoanTransactionType.CAPITALIZED_INCOME_ADJUSTMENT.getCode(), "Capitalized
Income Adjustment");
};
}
diff --git
a/fineract-progressive-loan/src/main/java/org/apache/fineract/portfolio/loanaccount/service/CapitalizedIncomeWritePlatformServiceImpl.java
b/fineract-progressive-loan/src/main/java/org/apache/fineract/portfolio/loanaccount/service/CapitalizedIncomeWritePlatformServiceImpl.java
index af4d6d344f..6c22ce20ab 100644
---
a/fineract-progressive-loan/src/main/java/org/apache/fineract/portfolio/loanaccount/service/CapitalizedIncomeWritePlatformServiceImpl.java
+++
b/fineract-progressive-loan/src/main/java/org/apache/fineract/portfolio/loanaccount/service/CapitalizedIncomeWritePlatformServiceImpl.java
@@ -93,7 +93,10 @@ public class CapitalizedIncomeWritePlatformServiceImpl
implements CapitalizedInc
// Post journal entries
journalEntryPoster.postJournalEntries(loan, existingTransactionIds,
existingReversedTransactionIds);
- return new
CommandProcessingResultBuilder().withEntityId(loan.getId()).withEntityExternalId(loan.getExternalId()).build();
+ return new CommandProcessingResultBuilder() //
+ .withEntityId(capitalizedIncomeTransaction.getId()) //
+
.withEntityExternalId(capitalizedIncomeTransaction.getExternalId()) //
+ .build();
}
@Override
diff --git
a/fineract-provider/src/main/java/org/apache/fineract/portfolio/loanaccount/api/LoanTransactionsApiResource.java
b/fineract-provider/src/main/java/org/apache/fineract/portfolio/loanaccount/api/LoanTransactionsApiResource.java
index 68dbc254be..89a1c58983 100644
---
a/fineract-provider/src/main/java/org/apache/fineract/portfolio/loanaccount/api/LoanTransactionsApiResource.java
+++
b/fineract-provider/src/main/java/org/apache/fineract/portfolio/loanaccount/api/LoanTransactionsApiResource.java
@@ -91,6 +91,7 @@ public class LoanTransactionsApiResource {
public static final String REAMORTIZE = "reAmortize";
public static final String UNDO_REAMORTIZE = "undoReAmortize";
public static final String CAPITALIZED_INCOME = "capitalizedIncome";
+ public static final String CAPITALIZED_INCOME_ADJUSTMENT =
"capitalizedIncomeAdjustment";
private final Set<String> responseDataParameters = new
HashSet<>(Arrays.asList("id", "type", "date", "currency", "amount",
"externalId",
LoanApiConstants.REVERSAL_EXTERNAL_ID_PARAMNAME,
LoanApiConstants.REVERSED_ON_DATE_PARAMNAME));
@@ -126,11 +127,12 @@ public class LoanTransactionsApiResource {
@QueryParam("command") @Parameter(description = "command") final
String commandParam, @Context final UriInfo uriInfo,
@QueryParam("dateFormat") @Parameter(description = "dateFormat")
final String rawDateFormat,
@QueryParam("transactionDate") @Parameter(description =
"transactionDate") final DateParam transactionDateParam,
- @QueryParam("locale") @Parameter(description = "locale") final
String locale) {
+ @QueryParam("locale") @Parameter(description = "locale") final
String locale,
+ @QueryParam("transactionId") @Parameter(description =
"transactionId") final Long transactionId) {
final DateFormat dateFormat = StringUtils.isBlank(rawDateFormat) ?
null : new DateFormat(rawDateFormat);
- return retrieveTransactionTemplate(loanId, null, commandParam,
uriInfo, dateFormat, transactionDateParam, locale);
+ return retrieveTransactionTemplate(loanId, null, commandParam,
uriInfo, dateFormat, transactionDateParam, locale, transactionId);
}
@GET
@@ -156,11 +158,13 @@ public class LoanTransactionsApiResource {
@QueryParam("command") @Parameter(description = "command") final
String commandParam, @Context final UriInfo uriInfo,
@QueryParam("dateFormat") @Parameter(description = "dateFormat")
final String rawDateFormat,
@QueryParam("transactionDate") @Parameter(description =
"transactionDate") final DateParam transactionDateParam,
- @QueryParam("locale") @Parameter(description = "locale") final
String locale) {
+ @QueryParam("locale") @Parameter(description = "locale") final
String locale,
+ @QueryParam("transactionId") @Parameter(description =
"transactionId") final Long transactionId) {
final DateFormat dateFormat = StringUtils.isBlank(rawDateFormat) ?
null : new DateFormat(rawDateFormat);
- return retrieveTransactionTemplate(null, loanExternalId, commandParam,
uriInfo, dateFormat, transactionDateParam, locale);
+ return retrieveTransactionTemplate(null, loanExternalId, commandParam,
uriInfo, dateFormat, transactionDateParam, locale,
+ transactionId);
}
@GET
@@ -529,6 +533,7 @@ public class LoanTransactionsApiResource {
case accrualAdjustment -> LoanTransactionType.ACCRUAL_ADJUSTMENT;
case capitalizedIncome -> LoanTransactionType.CAPITALIZED_INCOME;
case capitalizedIncomeAmortization ->
LoanTransactionType.CAPITALIZED_INCOME_AMORTIZATION;
+ case capitalizedIncomeAdjustment ->
LoanTransactionType.CAPITALIZED_INCOME_ADJUSTMENT;
default ->
throw new InvalidLoanTransactionTypeException("transaction",
transactionTypeParam.name(), "Unknown transaction type");
};
@@ -598,7 +603,7 @@ public class LoanTransactionsApiResource {
}
private String retrieveTransactionTemplate(Long loanId, String
loanExternalIdStr, String commandParam, UriInfo uriInfo,
- DateFormat dateFormat, DateParam transactionDateParam, String
locale) {
+ DateFormat dateFormat, DateParam transactionDateParam, String
locale, Long transactionId) {
this.context.authenticatedUser().validateHasReadPermission(RESOURCE_NAME_FOR_PERMISSIONS);
ExternalId loanExternalId =
ExternalIdFactory.produce(loanExternalIdStr);
@@ -671,7 +676,10 @@ public class LoanTransactionsApiResource {
transactionData =
this.loanReadPlatformService.retrieveLoanTransactionTemplate(resolvedLoanId);
} else if (CommandParameterUtil.is(commandParam,
LoanApiConstants.CAPITALIZED_INCOME_TRANSACTION_COMMAND)) {
transactionData =
this.loanReadPlatformService.retrieveLoanTransactionTemplate(resolvedLoanId,
- LoanTransactionType.CAPITALIZED_INCOME);
+ LoanTransactionType.CAPITALIZED_INCOME, transactionId);
+ } else if (CommandParameterUtil.is(commandParam,
LoanApiConstants.CAPITALIZED_INCOME_ADJUSTMENT_TRANSACTION_COMMAND)) {
+ transactionData =
this.loanReadPlatformService.retrieveLoanTransactionTemplate(resolvedLoanId,
+ LoanTransactionType.CAPITALIZED_INCOME_ADJUSTMENT,
transactionId);
} else {
throw new UnrecognizedQueryParamException("command", commandParam);
}
diff --git
a/fineract-provider/src/main/java/org/apache/fineract/portfolio/loanaccount/service/LoanReadPlatformServiceImpl.java
b/fineract-provider/src/main/java/org/apache/fineract/portfolio/loanaccount/service/LoanReadPlatformServiceImpl.java
index c7b4a45eac..ca2154bda9 100644
---
a/fineract-provider/src/main/java/org/apache/fineract/portfolio/loanaccount/service/LoanReadPlatformServiceImpl.java
+++
b/fineract-provider/src/main/java/org/apache/fineract/portfolio/loanaccount/service/LoanReadPlatformServiceImpl.java
@@ -50,6 +50,7 @@ import
org.apache.fineract.infrastructure.core.domain.ExternalId;
import org.apache.fineract.infrastructure.core.domain.JdbcSupport;
import org.apache.fineract.infrastructure.core.service.DateUtils;
import org.apache.fineract.infrastructure.core.service.ExternalIdFactory;
+import org.apache.fineract.infrastructure.core.service.MathUtil;
import org.apache.fineract.infrastructure.core.service.Page;
import org.apache.fineract.infrastructure.core.service.PaginationHelper;
import org.apache.fineract.infrastructure.core.service.SearchParameters;
@@ -107,6 +108,7 @@ import
org.apache.fineract.portfolio.loanaccount.data.PaidInAdvanceData;
import
org.apache.fineract.portfolio.loanaccount.data.RepaymentScheduleRelatedLoanData;
import org.apache.fineract.portfolio.loanaccount.data.ScheduleGeneratorDTO;
import org.apache.fineract.portfolio.loanaccount.domain.Loan;
+import
org.apache.fineract.portfolio.loanaccount.domain.LoanCapitalizedIncomeBalance;
import
org.apache.fineract.portfolio.loanaccount.domain.LoanCapitalizedIncomeCalculationType;
import
org.apache.fineract.portfolio.loanaccount.domain.LoanCapitalizedIncomeStrategy;
import
org.apache.fineract.portfolio.loanaccount.domain.LoanCapitalizedIncomeType;
@@ -126,6 +128,7 @@ import
org.apache.fineract.portfolio.loanaccount.loanschedule.data.OverdueLoanSc
import
org.apache.fineract.portfolio.loanaccount.loanschedule.domain.LoanScheduleProcessingType;
import
org.apache.fineract.portfolio.loanaccount.loanschedule.domain.LoanScheduleType;
import org.apache.fineract.portfolio.loanaccount.mapper.LoanTransactionMapper;
+import
org.apache.fineract.portfolio.loanaccount.repository.LoanCapitalizedIncomeBalanceRepository;
import
org.apache.fineract.portfolio.loanaccount.serialization.LoanForeclosureValidator;
import org.apache.fineract.portfolio.loanproduct.data.LoanProductData;
import
org.apache.fineract.portfolio.loanproduct.data.TransactionProcessingStrategyData;
@@ -180,6 +183,7 @@ public class LoanReadPlatformServiceImpl implements
LoanReadPlatformService, Loa
private final LoanTransactionMapper loanTransactionMapper;
private final LoanTransactionProcessingService
loadTransactionProcessingService;
private final LoanBalanceService loanBalanceService;
+ private final LoanCapitalizedIncomeBalanceRepository
loanCapitalizedIncomeBalanceRepository;
@Override
public LoanAccountData retrieveOne(final Long loanId) {
@@ -451,10 +455,52 @@ public class LoanReadPlatformServiceImpl implements
LoanReadPlatformService, Loa
return loanDetails;
}
+ private CurrencyData retriveLoanCurrencyData(final Long loanId) {
+ final LoanCurrencyDataMapper loanCurrencyMapper = new
LoanCurrencyDataMapper(sqlGenerator);
+ final String sql = "select " + loanCurrencyMapper.schema() + " where
l.id = ?";
+
+ return this.jdbcTemplate.queryForObject(sql, loanCurrencyMapper,
loanId);
+ }
+
@Override
- public LoanTransactionData retrieveLoanTransactionTemplate(final Long
loanId, LoanTransactionType transactionType) {
- return
LoanTransactionData.templateOnTop(retrieveLoanTransactionTemplate(loanId),
- LoanEnumerations.transactionType(transactionType));
+ public LoanTransactionData retrieveLoanTransactionTemplate(final Long
loanId, final LoanTransactionType transactionType,
+ final Long transactionId) {
+
+ LoanTransactionData loanTransactionData = null;
+ Collection<PaymentTypeData> paymentOptions = null;
+ BigDecimal transactionAmount = BigDecimal.ZERO;
+ switch (transactionType) {
+ case CAPITALIZED_INCOME:
+ final Loan loan =
loanRepositoryWrapper.findOneWithNotFoundDetection(loanId);
+ if
(loan.getLoanProduct().getLoanProductRelatedDetail().isEnableIncomeCapitalization())
{
+ final BigDecimal capitalizedIncomeBalance =
loanCapitalizedIncomeBalanceRepository.findAllByLoanId(loanId).stream()
+
.map(LoanCapitalizedIncomeBalance::getAmount).reduce(BigDecimal.ZERO,
BigDecimal::add);
+ transactionAmount =
loan.getApprovedPrincipal().subtract(loan.getDisbursedAmount()).subtract(capitalizedIncomeBalance);
+ }
+ paymentOptions =
this.paymentTypeReadPlatformService.retrieveAllPaymentTypes();
+ loanTransactionData =
LoanTransactionData.loanTransactionDataForCreditTemplate(
+ LoanEnumerations.transactionType(transactionType),
DateUtils.getBusinessLocalDate(), transactionAmount,
+ paymentOptions, retriveLoanCurrencyData(loanId));
+
+ break;
+ case CAPITALIZED_INCOME_ADJUSTMENT:
+ final LoanCapitalizedIncomeBalance
loanCapitalizedIncomeBalance = loanCapitalizedIncomeBalanceRepository
+ .findByLoanIdAndLoanTransactionId(loanId,
transactionId);
+
+ transactionAmount = (loanCapitalizedIncomeBalance == null) ?
BigDecimal.ZERO
+ : loanCapitalizedIncomeBalance.getAmount()
+
.subtract(MathUtil.nullToZero(loanCapitalizedIncomeBalance.getAmountAdjustment()));
+ loanTransactionData =
LoanTransactionData.loanTransactionDataForCreditTemplate(
+ LoanEnumerations.transactionType(transactionType),
DateUtils.getBusinessLocalDate(), transactionAmount,
+ paymentOptions, retriveLoanCurrencyData(loanId));
+ break;
+ default:
+ loanTransactionData =
LoanTransactionData.templateOnTop(retrieveLoanTransactionTemplate(loanId),
+ LoanEnumerations.transactionType(transactionType));
+ break;
+ }
+
+ return loanTransactionData;
}
@Override
@@ -646,6 +692,33 @@ public class LoanReadPlatformServiceImpl implements
LoanReadPlatformService, Loa
return loanId;
}
+ private static final class LoanCurrencyDataMapper implements
RowMapper<CurrencyData> {
+
+ private final DatabaseSpecificSQLGenerator sqlGenerator;
+
+ LoanCurrencyDataMapper(DatabaseSpecificSQLGenerator sqlGenerator) {
+ this.sqlGenerator = sqlGenerator;
+ }
+
+ public String schema() {
+ return " l.currency_code as currencyCode, l.currency_digits as
currencyDigits, l.currency_multiplesof as inMultiplesOf, rc."
+ + sqlGenerator.escape("name")
+ + " as currencyName, rc.display_symbol as
currencyDisplaySymbol, rc.internationalized_name_code as currencyNameCode from
m_loan l join m_currency rc on rc."
+ + sqlGenerator.escape("code") + " = l.currency_code ";
+ }
+
+ @Override
+ public CurrencyData mapRow(final ResultSet rs,
@SuppressWarnings("unused") final int rowNum) throws SQLException {
+ final String currencyCode = rs.getString("currencyCode");
+ final String currencyName = rs.getString("currencyName");
+ final String currencyNameCode = rs.getString("currencyNameCode");
+ final String currencyDisplaySymbol =
rs.getString("currencyDisplaySymbol");
+ final Integer currencyDigits = JdbcSupport.getInteger(rs,
"currencyDigits");
+ final Integer inMultiplesOf = JdbcSupport.getInteger(rs,
"inMultiplesOf");
+ return new CurrencyData(currencyCode, currencyName,
currencyDigits, inMultiplesOf, currencyDisplaySymbol, currencyNameCode);
+ }
+ }
+
private static final class LoanMapper implements
RowMapper<LoanAccountData> {
private final DatabaseSpecificSQLGenerator sqlGenerator;
diff --git
a/fineract-provider/src/main/java/org/apache/fineract/portfolio/loanaccount/starter/LoanAccountConfiguration.java
b/fineract-provider/src/main/java/org/apache/fineract/portfolio/loanaccount/starter/LoanAccountConfiguration.java
index 47f02d53ea..3dfa3bcf0d 100644
---
a/fineract-provider/src/main/java/org/apache/fineract/portfolio/loanaccount/starter/LoanAccountConfiguration.java
+++
b/fineract-provider/src/main/java/org/apache/fineract/portfolio/loanaccount/starter/LoanAccountConfiguration.java
@@ -88,6 +88,7 @@ import
org.apache.fineract.portfolio.loanaccount.mapper.LoanChargeMapper;
import
org.apache.fineract.portfolio.loanaccount.mapper.LoanCollateralManagementMapper;
import org.apache.fineract.portfolio.loanaccount.mapper.LoanMapper;
import org.apache.fineract.portfolio.loanaccount.mapper.LoanTransactionMapper;
+import
org.apache.fineract.portfolio.loanaccount.repository.LoanCapitalizedIncomeBalanceRepository;
import
org.apache.fineract.portfolio.loanaccount.rescheduleloan.domain.LoanTermVariationsRepository;
import
org.apache.fineract.portfolio.loanaccount.serialization.LoanApplicationTransitionValidator;
import
org.apache.fineract.portfolio.loanaccount.serialization.LoanApplicationValidator;
@@ -333,14 +334,16 @@ public class LoanAccountConfiguration {
DelinquencyReadPlatformService delinquencyReadPlatformService,
LoanTransactionRepository loanTransactionRepository,
LoanChargePaidByReadService loanChargePaidByReadService,
LoanTransactionRelationReadService loanTransactionRelationReadService,
LoanForeclosureValidator loanForeclosureValidator,
LoanTransactionMapper loanTransactionMapper,
- LoanTransactionProcessingService loanTransactionProcessingService,
LoanBalanceService loanBalanceService) {
+ LoanTransactionProcessingService loanTransactionProcessingService,
LoanBalanceService loanBalanceService,
+ LoanCapitalizedIncomeBalanceRepository
loanCapitalizedIncomeBalanceRepository) {
return new LoanReadPlatformServiceImpl(jdbcTemplate, context,
loanRepositoryWrapper, applicationCurrencyRepository,
loanProductReadPlatformService, clientReadPlatformService,
groupReadPlatformService, loanDropdownReadPlatformService,
fundReadPlatformService, chargeReadPlatformService,
codeValueReadPlatformService, calendarReadPlatformService,
staffReadPlatformService, paginationHelper,
paymentTypeReadPlatformService, floatingRatesReadPlatformService,
loanUtilService, configurationDomainService,
accountDetailsReadPlatformService, columnValidator, sqlGenerator,
delinquencyReadPlatformService, loanTransactionRepository,
loanChargePaidByReadService, loanTransactionRelationReadService,
- loanForeclosureValidator, loanTransactionMapper,
loanTransactionProcessingService, loanBalanceService);
+ loanForeclosureValidator, loanTransactionMapper,
loanTransactionProcessingService, loanBalanceService,
+ loanCapitalizedIncomeBalanceRepository);
}
@Bean
diff --git
a/integration-tests/src/test/java/org/apache/fineract/integrationtests/BaseLoanIntegrationTest.java
b/integration-tests/src/test/java/org/apache/fineract/integrationtests/BaseLoanIntegrationTest.java
index 40030968b4..2721be9376 100644
---
a/integration-tests/src/test/java/org/apache/fineract/integrationtests/BaseLoanIntegrationTest.java
+++
b/integration-tests/src/test/java/org/apache/fineract/integrationtests/BaseLoanIntegrationTest.java
@@ -276,7 +276,7 @@ public abstract class BaseLoanIntegrationTest extends
IntegrationTest {
}
protected GetLoansLoanIdTransactionsTemplateResponse getPrepayAmount(Long
loanId, String date) {
- return
ok(fineractClient().loanTransactions.retrieveTransactionTemplate(loanId,
"prepayLoan", DATETIME_PATTERN, date, "en"));
+ return
ok(fineractClient().loanTransactions.retrieveTransactionTemplate(loanId,
"prepayLoan", DATETIME_PATTERN, date, "en", null));
}
protected Long verifyPrepayAmountByRepayment(Long loanId, String date) {
diff --git
a/integration-tests/src/test/java/org/apache/fineract/integrationtests/LoanTransactionTest.java
b/integration-tests/src/test/java/org/apache/fineract/integrationtests/LoanTransactionTest.java
index 63b0c6cb64..e159f2b849 100644
---
a/integration-tests/src/test/java/org/apache/fineract/integrationtests/LoanTransactionTest.java
+++
b/integration-tests/src/test/java/org/apache/fineract/integrationtests/LoanTransactionTest.java
@@ -25,17 +25,25 @@ import java.math.BigDecimal;
import java.util.List;
import java.util.UUID;
import java.util.concurrent.atomic.AtomicReference;
+import lombok.extern.slf4j.Slf4j;
import org.apache.fineract.client.models.GetLoansLoanIdTransactionsResponse;
import
org.apache.fineract.client.models.GetLoansLoanIdTransactionsTemplateResponse;
import org.apache.fineract.client.models.PostClientsResponse;
+import org.apache.fineract.client.models.PostLoanProductsRequest;
import org.apache.fineract.client.models.PostLoanProductsResponse;
+import org.apache.fineract.client.models.PostLoansLoanIdTransactionsRequest;
+import org.apache.fineract.client.models.PostLoansLoanIdTransactionsResponse;
import org.apache.fineract.client.models.TransactionType;
import org.apache.fineract.integrationtests.common.ClientHelper;
import org.junit.jupiter.api.Assertions;
import org.junit.jupiter.api.Test;
+@Slf4j
public class LoanTransactionTest extends BaseLoanIntegrationTest {
+ private final String capitalizedIncomeCommand = "capitalizedIncome";
+ private final String capitalizedIncomeAdjustmentCommand =
"capitalizedIncomeAdjustment";
+
@Test
public void testGetLoanTransactionsFiltering() {
final PostClientsResponse client =
clientHelper.createClient(ClientHelper.defaultClientCreationRequest());
@@ -94,24 +102,68 @@ public class LoanTransactionTest extends
BaseLoanIntegrationTest {
public void testGetLoanTransactionTemplateForCapitalizedIncome() {
final PostClientsResponse client =
clientHelper.createClient(ClientHelper.defaultClientCreationRequest());
- final PostLoanProductsResponse loanProductsResponse =
loanProductHelper.createLoanProduct(create4IProgressive());
+ final PostLoanProductsResponse loanProductsResponse = loanProductHelper
+
.createLoanProduct(create4IProgressive().enableIncomeCapitalization(true)
+
.capitalizedIncomeCalculationType(PostLoanProductsRequest.CapitalizedIncomeCalculationTypeEnum.FLAT)
+
.capitalizedIncomeStrategy(PostLoanProductsRequest.CapitalizedIncomeStrategyEnum.EQUAL_AMORTIZATION)
+
.deferredIncomeLiabilityAccountId(deferredIncomeLiabilityAccount.getAccountID().longValue())
+
.incomeFromCapitalizationAccountId(feeIncomeAccount.getAccountID().longValue())
+
.capitalizedIncomeType(PostLoanProductsRequest.CapitalizedIncomeTypeEnum.FEE));
final String loanExternalIdStr = UUID.randomUUID().toString();
- final String command = "capitalizedIncome";
runAt("20 December 2024", () -> {
Long loanId = applyAndApproveProgressiveLoan(client.getClientId(),
loanProductsResponse.getResourceId(), "20 December 2024",
430.0, 7.0, 6, (request) ->
request.externalId(loanExternalIdStr));
- disburseLoan(loanId, BigDecimal.valueOf(430), "20 December 2024");
+ disburseLoan(loanId, BigDecimal.valueOf(230), "20 December 2024");
final GetLoansLoanIdTransactionsTemplateResponse
transactionTemplate = loanTransactionHelper.retrieveTransactionTemplate(loanId,
- command, null, null, null);
+ capitalizedIncomeCommand, null, null, null);
assertNotNull(transactionTemplate);
- assertEquals("loanTransactionType." + command,
transactionTemplate.getType().getCode());
+ assertEquals("loanTransactionType." + capitalizedIncomeCommand,
transactionTemplate.getType().getCode());
+ assertEquals(transactionTemplate.getAmount(), 200);
assertThat(transactionTemplate.getPaymentTypeOptions().size() > 0);
});
}
+ @Test
+ public void testGetLoanTransactionTemplateForCapitalizedIncomeAdjustment()
{
+ final PostClientsResponse client =
clientHelper.createClient(ClientHelper.defaultClientCreationRequest());
+
+ final PostLoanProductsResponse loanProductsResponse = loanProductHelper
+
.createLoanProduct(create4IProgressive().enableIncomeCapitalization(true)
+
.capitalizedIncomeCalculationType(PostLoanProductsRequest.CapitalizedIncomeCalculationTypeEnum.FLAT)
+
.capitalizedIncomeStrategy(PostLoanProductsRequest.CapitalizedIncomeStrategyEnum.EQUAL_AMORTIZATION)
+
.deferredIncomeLiabilityAccountId(deferredIncomeLiabilityAccount.getAccountID().longValue())
+
.incomeFromCapitalizationAccountId(feeIncomeAccount.getAccountID().longValue())
+
.capitalizedIncomeType(PostLoanProductsRequest.CapitalizedIncomeTypeEnum.FEE));
+
+ final String loanExternalIdStr = UUID.randomUUID().toString();
+
+ runAt("20 December 2024", () -> {
+ final Long loanId =
applyAndApproveProgressiveLoan(client.getClientId(),
loanProductsResponse.getResourceId(),
+ "20 December 2024", 430.0, 7.0, 6, (request) ->
request.externalId(loanExternalIdStr));
+
+ disburseLoan(loanId, BigDecimal.valueOf(230), "20 December 2024");
+
+ PostLoansLoanIdTransactionsResponse loanTransactionResponse =
loanTransactionHelper.executeLoanTransaction(loanId,
+ new
PostLoansLoanIdTransactionsRequest().dateFormat(DATETIME_PATTERN).transactionDate("20
December 2024").locale("en")
+ .transactionAmount(150.0),
+ capitalizedIncomeCommand);
+ assertNotNull(loanTransactionResponse);
+ final Long transactionId = loanTransactionResponse.getResourceId();
+ assertNotNull(transactionId);
+ log.info("Loan Id {} with transaction id {}", loanId,
transactionId);
+
+ final GetLoansLoanIdTransactionsTemplateResponse
transactionTemplate = loanTransactionHelper.retrieveTransactionTemplate(loanId,
+ capitalizedIncomeAdjustmentCommand, null, null, null,
transactionId);
+
+ assertNotNull(transactionTemplate);
+ assertEquals("loanTransactionType." +
capitalizedIncomeAdjustmentCommand, transactionTemplate.getType().getCode());
+ assertEquals(transactionTemplate.getAmount(), 150);
+ });
+ }
+
}
diff --git
a/integration-tests/src/test/java/org/apache/fineract/integrationtests/common/loans/LoanTransactionHelper.java
b/integration-tests/src/test/java/org/apache/fineract/integrationtests/common/loans/LoanTransactionHelper.java
index 8918a5a146..5de3e0244b 100644
---
a/integration-tests/src/test/java/org/apache/fineract/integrationtests/common/loans/LoanTransactionHelper.java
+++
b/integration-tests/src/test/java/org/apache/fineract/integrationtests/common/loans/LoanTransactionHelper.java
@@ -902,6 +902,11 @@ public class LoanTransactionHelper {
return
postLoanTransaction(createLoanTransactionURL(MAKE_REPAYMENT_COMMAND, loanID),
getRepaymentBodyAsJSON(date, amountToBePaid));
}
+ public PostLoansLoanIdTransactionsResponse executeLoanTransaction(final
Long loanId, final PostLoansLoanIdTransactionsRequest request,
+ final String command) {
+ return
Calls.ok(FineractClientHelper.getFineractClient().loanTransactions.executeLoanTransaction(loanId,
request, command));
+ }
+
public PostLoansLoanIdTransactionsResponse makeLoanRepayment(final Long
loanId, final PostLoansLoanIdTransactionsRequest request) {
return
Calls.ok(FineractClientHelper.getFineractClient().loanTransactions.executeLoanTransaction(loanId,
request, "repayment"));
}
@@ -2332,7 +2337,7 @@ public class LoanTransactionHelper {
public GetLoansLoanIdTransactionsTemplateResponse
getPrepaymentAmount(final Long loanId, final String transactionDate,
String dateformat) {
return
Calls.ok(FineractClientHelper.getFineractClient().loanTransactions.retrieveTransactionTemplate(loanId,
"prepayLoan",
- dateformat, transactionDate, "en"));
+ dateformat, transactionDate, "en", null));
}
// TODO: Rewrite to use fineract-client instead!
@@ -2806,16 +2811,22 @@ public class LoanTransactionHelper {
return chargebackPayload;
}
+ public GetLoansLoanIdTransactionsTemplateResponse
retrieveTransactionTemplate(Long loanId, String command, String dateFormat,
+ String transactionDate, String locale, Long transactionId) {
+ return
Calls.ok(FineractClientHelper.getFineractClient().loanTransactions.retrieveTransactionTemplate(loanId,
command, dateFormat,
+ transactionDate, locale, transactionId));
+ }
+
public GetLoansLoanIdTransactionsTemplateResponse
retrieveTransactionTemplate(Long loanId, String command, String dateFormat,
String transactionDate, String locale) {
return
Calls.ok(FineractClientHelper.getFineractClient().loanTransactions.retrieveTransactionTemplate(loanId,
command, dateFormat,
- transactionDate, locale));
+ transactionDate, locale, null));
}
public GetLoansLoanIdTransactionsTemplateResponse
retrieveTransactionTemplate(String loanExternalIdStr, String command,
String dateFormat, String transactionDate, String locale) {
return
Calls.ok(FineractClientHelper.getFineractClient().loanTransactions.retrieveTransactionTemplate1(loanExternalIdStr,
command,
- dateFormat, transactionDate, locale));
+ dateFormat, transactionDate, locale, null));
}
public GetLoansApprovalTemplateResponse getLoanApprovalTemplate(String
loanExternalIdStr) {