FINERACT-2232: Loan account capitalized income transaction template

This commit is contained in:
Jose Alberto Hernandez
2025-04-24 11:48:10 +02:00
committed by Adam Saghy
parent 13c99f98ab
commit 205b39ddf0
11 changed files with 78 additions and 10 deletions
@@ -174,6 +174,7 @@ public interface LoanApiConstants {
// Commands
String CHARGEBACK_TRANSACTION_COMMAND = "chargeback";
String MARK_AS_FRAUD_COMMAND = "markAsFraud";
String CAPITALIZED_INCOME_TRANSACTION_COMMAND = "capitalizedIncome";
// Data Validator names
String LOAN_FRAUD_DATAVALIDATOR_PREFIX = "loans.fraud";
@@ -75,7 +75,19 @@ final class LoanTransactionsApiResourceSwagger {
public String displaySymbolValue;
}
public GetLoansTransactionType transactionType;
static final class GetPaymentTypeOptions {
private GetPaymentTypeOptions() {}
@Schema(example = "10")
public Long id;
@Schema(example = "check")
public String name;
@Schema(example = "1")
public Integer position;
}
public GetLoansTransactionType type;
@Schema(example = "[2009, 8, 1]")
public LocalDate date;
public GetLoansTotal total;
@@ -94,6 +106,8 @@ final class LoanTransactionsApiResourceSwagger {
public GetLoanCurrency currency;
public List<GetLoanProductsChargeOffReasonOptions> chargeOffReasonOptions;
public List<GetPaymentTypeOptions> paymentTypeOptions;
}
public static final class GetLoanCurrency {
@@ -216,7 +216,16 @@ public class LoanTransactionData implements Serializable {
loanTransactionData.externalId, loanTransactionData.transfer, loanTransactionData.fixedEmiAmount,
loanTransactionData.outstandingLoanBalance, loanTransactionData.manuallyReversed, loanTransactionData.loanId,
loanTransactionData.externalLoanId);
}
public static LoanTransactionData templateOnTop(final LoanTransactionData loanTransactionData, final LoanTransactionEnumData typeOf) {
return new LoanTransactionData(loanTransactionData.id, loanTransactionData.officeId, loanTransactionData.officeName, typeOf,
loanTransactionData.paymentDetailData, loanTransactionData.currency, loanTransactionData.date, loanTransactionData.amount,
loanTransactionData.netDisbursalAmount, loanTransactionData.principalPortion, loanTransactionData.interestPortion,
loanTransactionData.feeChargesPortion, loanTransactionData.penaltyChargesPortion, loanTransactionData.overpaymentPortion,
loanTransactionData.unrecognizedIncomePortion, loanTransactionData.paymentTypeOptions, loanTransactionData.externalId,
loanTransactionData.transfer, loanTransactionData.fixedEmiAmount, loanTransactionData.outstandingLoanBalance,
loanTransactionData.manuallyReversed, loanTransactionData.loanId, loanTransactionData.externalLoanId);
}
@Default // Default constructor for mapper
@@ -67,6 +67,7 @@ public class LoanTransactionEnumData implements Serializable {
private final boolean accrualActivity;
private final boolean interestRefund;
private final boolean accrualAdjustment;
private final boolean capitalizedIncome;
public LoanTransactionEnumData(final Long id, final String code, final String value) {
this.id = id;
@@ -103,6 +104,7 @@ public class LoanTransactionEnumData implements Serializable {
this.reAmortize = Long.valueOf(LoanTransactionType.REAMORTIZE.getValue()).equals(this.id);
this.interestRefund = Long.valueOf(LoanTransactionType.INTEREST_REFUND.getValue()).equals(this.id);
this.accrualAdjustment = Long.valueOf(LoanTransactionType.ACCRUAL_ADJUSTMENT.getValue()).equals(this.id);
this.capitalizedIncome = Long.valueOf(LoanTransactionType.CAPITALIZED_INCOME.getValue()).equals(this.id);
}
public boolean isRepaymentType() {
@@ -67,6 +67,7 @@ public enum LoanTransactionType {
ACCRUAL_ACTIVITY(32, "loanTransactionType.accrualActivity"), //
INTEREST_REFUND(33, "loanTransactionType.interestRefund"), //
ACCRUAL_ADJUSTMENT(34, "loanTransactionType.accrualAdjustment"), //
CAPITALIZED_INCOME(35, "loanTransactionType.capitalizedIncome"), //
;
private final Integer value;
@@ -117,6 +118,7 @@ public enum LoanTransactionType {
case 32 -> LoanTransactionType.ACCRUAL_ACTIVITY;
case 33 -> LoanTransactionType.INTEREST_REFUND;
case 34 -> LoanTransactionType.ACCRUAL_ADJUSTMENT;
case 35 -> LoanTransactionType.CAPITALIZED_INCOME;
default -> LoanTransactionType.INVALID;
};
}
@@ -233,4 +235,8 @@ public enum LoanTransactionType {
public boolean isAccrualAdjustment() {
return this == LoanTransactionType.ACCRUAL_ADJUSTMENT;
}
public boolean isCapitalizedIncome() {
return this == LoanTransactionType.CAPITALIZED_INCOME;
}
}
@@ -325,6 +325,8 @@ public final class LoanEnumerations {
LoanTransactionType.INTEREST_REFUND.getCode(), "Interest Refund");
case ACCRUAL_ADJUSTMENT -> new LoanTransactionEnumData(LoanTransactionType.ACCRUAL_ADJUSTMENT.getValue().longValue(),
LoanTransactionType.ACCRUAL_ADJUSTMENT.getCode(), "Accrual Adjustment");
case CAPITALIZED_INCOME -> new LoanTransactionEnumData(LoanTransactionType.CAPITALIZED_INCOME.getValue().longValue(),
LoanTransactionType.CAPITALIZED_INCOME.getCode(), "Capitalized Income");
};
}
@@ -664,6 +664,9 @@ public class LoanTransactionsApiResource {
transactionData = this.loanReadPlatformService.retrieveLoanChargeOffTemplate(resolvedLoanId);
} else if (CommandParameterUtil.is(commandParam, DOWN_PAYMENT)) {
transactionData = this.loanReadPlatformService.retrieveLoanTransactionTemplate(resolvedLoanId);
} else if (CommandParameterUtil.is(commandParam, LoanApiConstants.CAPITALIZED_INCOME_TRANSACTION_COMMAND)) {
transactionData = this.loanReadPlatformService.retrieveLoanTransactionTemplate(resolvedLoanId,
LoanTransactionType.CAPITALIZED_INCOME);
} else {
throw new UnrecognizedQueryParamException("command", commandParam);
}
@@ -63,6 +63,8 @@ public interface LoanReadPlatformService {
LoanTransactionData retrieveLoanTransactionTemplate(Long loanId);
LoanTransactionData retrieveLoanTransactionTemplate(Long loanId, LoanTransactionType transactionType);
LoanTransactionData retrieveWaiveInterestDetails(Long loanId);
LoanTransactionData retrieveLoanTransaction(Long loanId, Long transactionId);
@@ -111,7 +111,6 @@ import org.apache.fineract.portfolio.loanaccount.domain.LoanCapitalizedIncomeCal
import org.apache.fineract.portfolio.loanaccount.domain.LoanCapitalizedIncomeStrategy;
import org.apache.fineract.portfolio.loanaccount.domain.LoanChargeOffBehaviour;
import org.apache.fineract.portfolio.loanaccount.domain.LoanRepaymentScheduleInstallment;
import org.apache.fineract.portfolio.loanaccount.domain.LoanRepaymentScheduleTransactionProcessorFactory;
import org.apache.fineract.portfolio.loanaccount.domain.LoanRepositoryWrapper;
import org.apache.fineract.portfolio.loanaccount.domain.LoanStatus;
import org.apache.fineract.portfolio.loanaccount.domain.LoanSubStatus;
@@ -166,7 +165,6 @@ public class LoanReadPlatformServiceImpl implements LoanReadPlatformService, Loa
private final StaffReadPlatformService staffReadPlatformService;
private final PaginationHelper paginationHelper;
private final PaymentTypeReadPlatformService paymentTypeReadPlatformService;
private final LoanRepaymentScheduleTransactionProcessorFactory loanRepaymentScheduleTransactionProcessorFactory;
private final FloatingRatesReadPlatformService floatingRatesReadPlatformService;
private final LoanUtilService loanUtilService;
private final ConfigurationDomainService configurationDomainService;
@@ -179,7 +177,6 @@ public class LoanReadPlatformServiceImpl implements LoanReadPlatformService, Loa
private final LoanTransactionRelationReadService loanTransactionRelationReadService;
private final LoanForeclosureValidator loanForeclosureValidator;
private final LoanTransactionMapper loanTransactionMapper;
private final org.apache.fineract.portfolio.loanaccount.mapper.LoanMapper loanMapper;
private final LoanTransactionProcessingService loadTransactionProcessingService;
@Override
@@ -452,6 +449,12 @@ public class LoanReadPlatformServiceImpl implements LoanReadPlatformService, Loa
return loanDetails;
}
@Override
public LoanTransactionData retrieveLoanTransactionTemplate(final Long loanId, LoanTransactionType transactionType) {
return LoanTransactionData.templateOnTop(retrieveLoanTransactionTemplate(loanId),
LoanEnumerations.transactionType(transactionType));
}
@Override
public LoanTransactionData retrieveLoanTransactionTemplate(final Long loanId) {
@@ -323,22 +323,20 @@ public class LoanAccountConfiguration {
CodeValueReadPlatformService codeValueReadPlatformService, CalendarReadPlatformService calendarReadPlatformService,
StaffReadPlatformService staffReadPlatformService, PaginationHelper paginationHelper,
PaymentTypeReadPlatformService paymentTypeReadPlatformService,
LoanRepaymentScheduleTransactionProcessorFactory loanRepaymentScheduleTransactionProcessorFactory,
FloatingRatesReadPlatformService floatingRatesReadPlatformService, LoanUtilService loanUtilService,
ConfigurationDomainService configurationDomainService, AccountDetailsReadPlatformService accountDetailsReadPlatformService,
ColumnValidator columnValidator, DatabaseSpecificSQLGenerator sqlGenerator,
DelinquencyReadPlatformService delinquencyReadPlatformService, LoanTransactionRepository loanTransactionRepository,
LoanChargePaidByReadService loanChargePaidByReadService, LoanTransactionRelationReadService loanTransactionRelationReadService,
LoanForeclosureValidator loanForeclosureValidator, LoanTransactionMapper loanTransactionMapper, LoanMapper loanMapper,
LoanForeclosureValidator loanForeclosureValidator, LoanTransactionMapper loanTransactionMapper,
LoanTransactionProcessingService loanTransactionProcessingService) {
return new LoanReadPlatformServiceImpl(jdbcTemplate, context, loanRepositoryWrapper, applicationCurrencyRepository,
loanProductReadPlatformService, clientReadPlatformService, groupReadPlatformService, loanDropdownReadPlatformService,
fundReadPlatformService, chargeReadPlatformService, codeValueReadPlatformService, calendarReadPlatformService,
staffReadPlatformService, paginationHelper, paymentTypeReadPlatformService,
loanRepaymentScheduleTransactionProcessorFactory, floatingRatesReadPlatformService, loanUtilService,
configurationDomainService, accountDetailsReadPlatformService, columnValidator, sqlGenerator,
staffReadPlatformService, paginationHelper, paymentTypeReadPlatformService, floatingRatesReadPlatformService,
loanUtilService, configurationDomainService, accountDetailsReadPlatformService, columnValidator, sqlGenerator,
delinquencyReadPlatformService, loanTransactionRepository, loanChargePaidByReadService, loanTransactionRelationReadService,
loanForeclosureValidator, loanTransactionMapper, loanMapper, loanTransactionProcessingService);
loanForeclosureValidator, loanTransactionMapper, loanTransactionProcessingService);
}
@Bean
@@ -18,11 +18,15 @@
*/
package org.apache.fineract.integrationtests;
import static org.junit.Assert.assertNotNull;
import static org.junit.jupiter.api.Assertions.assertEquals;
import java.math.BigDecimal;
import java.util.List;
import java.util.UUID;
import java.util.concurrent.atomic.AtomicReference;
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.PostLoanProductsResponse;
import org.apache.fineract.client.models.TransactionType;
@@ -86,4 +90,28 @@ public class LoanTransactionTest extends BaseLoanIntegrationTest {
});
}
@Test
public void testGetLoanTransactionTemplateForCapitalizedIncome() {
final PostClientsResponse client = clientHelper.createClient(ClientHelper.defaultClientCreationRequest());
final PostLoanProductsResponse loanProductsResponse = loanProductHelper.createLoanProduct(create4IProgressive());
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");
final GetLoansLoanIdTransactionsTemplateResponse transactionTemplate = loanTransactionHelper.retrieveTransactionTemplate(loanId,
command, null, null, null);
assertNotNull(transactionTemplate);
assertEquals("loanTransactionType." + command, transactionTemplate.getType().getCode());
assertThat(transactionTemplate.getPaymentTypeOptions().size() > 0);
});
}
}