FINERACT-2134: Missing charge paid by references and journal entries for disbursement occuring accruals
This commit is contained in:
committed by
Arnold Gálovics
parent
39d95f393b
commit
33f666ccc3
+13
@@ -1267,6 +1267,19 @@ final class LoansApiResourceSwagger {
|
|||||||
public BigDecimal disbursedAmountPercentageForDownPayment;
|
public BigDecimal disbursedAmountPercentageForDownPayment;
|
||||||
@Schema(example = "false")
|
@Schema(example = "false")
|
||||||
public Boolean enableAutoRepaymentForDownPayment;
|
public Boolean enableAutoRepaymentForDownPayment;
|
||||||
|
|
||||||
|
public List<PostLoansRequestChargeData> charges;
|
||||||
|
|
||||||
|
static final class PostLoansRequestChargeData {
|
||||||
|
|
||||||
|
private PostLoansRequestChargeData() {}
|
||||||
|
|
||||||
|
@Schema(example = "1")
|
||||||
|
public Long chargeId;
|
||||||
|
|
||||||
|
@Schema(example = "1.0")
|
||||||
|
public BigDecimal amount;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@Schema(description = "PostLoansResponse")
|
@Schema(description = "PostLoansResponse")
|
||||||
|
|||||||
+12
-2
@@ -152,6 +152,7 @@ import org.apache.fineract.portfolio.loanaccount.domain.GroupLoanIndividualMonit
|
|||||||
import org.apache.fineract.portfolio.loanaccount.domain.Loan;
|
import org.apache.fineract.portfolio.loanaccount.domain.Loan;
|
||||||
import org.apache.fineract.portfolio.loanaccount.domain.LoanAccountDomainService;
|
import org.apache.fineract.portfolio.loanaccount.domain.LoanAccountDomainService;
|
||||||
import org.apache.fineract.portfolio.loanaccount.domain.LoanCharge;
|
import org.apache.fineract.portfolio.loanaccount.domain.LoanCharge;
|
||||||
|
import org.apache.fineract.portfolio.loanaccount.domain.LoanChargePaidBy;
|
||||||
import org.apache.fineract.portfolio.loanaccount.domain.LoanCollateralManagement;
|
import org.apache.fineract.portfolio.loanaccount.domain.LoanCollateralManagement;
|
||||||
import org.apache.fineract.portfolio.loanaccount.domain.LoanDisbursementDetails;
|
import org.apache.fineract.portfolio.loanaccount.domain.LoanDisbursementDetails;
|
||||||
import org.apache.fineract.portfolio.loanaccount.domain.LoanEvent;
|
import org.apache.fineract.portfolio.loanaccount.domain.LoanEvent;
|
||||||
@@ -330,8 +331,8 @@ public class LoanWritePlatformServiceJpaRepositoryImpl implements LoanWritePlatf
|
|||||||
|
|
||||||
businessEventNotifierService.notifyPreBusinessEvent(new LoanDisbursalBusinessEvent(loan));
|
businessEventNotifierService.notifyPreBusinessEvent(new LoanDisbursalBusinessEvent(loan));
|
||||||
|
|
||||||
final List<Long> existingTransactionIds = new ArrayList<>();
|
List<Long> existingTransactionIds = new ArrayList<>();
|
||||||
final List<Long> existingReversedTransactionIds = new ArrayList<>();
|
List<Long> existingReversedTransactionIds = new ArrayList<>();
|
||||||
|
|
||||||
final AppUser currentUser = getAppUserIfPresent();
|
final AppUser currentUser = getAppUserIfPresent();
|
||||||
final Map<String, Object> changes = new LinkedHashMap<>();
|
final Map<String, Object> changes = new LinkedHashMap<>();
|
||||||
@@ -489,6 +490,8 @@ public class LoanWritePlatformServiceJpaRepositoryImpl implements LoanWritePlatf
|
|||||||
loanAccrualTransactionBusinessEventService.raiseBusinessEventForAccrualTransactions(loan, existingTransactionIds);
|
loanAccrualTransactionBusinessEventService.raiseBusinessEventForAccrualTransactions(loan, existingTransactionIds);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
existingTransactionIds = new ArrayList<>(loan.findExistingTransactionIds());
|
||||||
|
existingReversedTransactionIds = new ArrayList<>(loan.findExistingReversedTransactionIds());
|
||||||
final Set<LoanCharge> loanCharges = loan.getActiveCharges();
|
final Set<LoanCharge> loanCharges = loan.getActiveCharges();
|
||||||
final Map<Long, BigDecimal> disBuLoanCharges = new HashMap<>();
|
final Map<Long, BigDecimal> disBuLoanCharges = new HashMap<>();
|
||||||
for (final LoanCharge loanCharge : loanCharges) {
|
for (final LoanCharge loanCharge : loanCharges) {
|
||||||
@@ -499,10 +502,17 @@ public class LoanWritePlatformServiceJpaRepositoryImpl implements LoanWritePlatf
|
|||||||
if (loanCharge.isDisbursementCharge()) {
|
if (loanCharge.isDisbursementCharge()) {
|
||||||
LoanTransaction loanTransaction = LoanTransaction.accrueTransaction(loan, loan.getOffice(), actualDisbursementDate,
|
LoanTransaction loanTransaction = LoanTransaction.accrueTransaction(loan, loan.getOffice(), actualDisbursementDate,
|
||||||
loanCharge.amount(), null, loanCharge.amount(), null, externalIdFactory.create());
|
loanCharge.amount(), null, loanCharge.amount(), null, externalIdFactory.create());
|
||||||
|
loanTransaction.updateLoan(loan);
|
||||||
|
LoanChargePaidBy loanChargePaidBy = new LoanChargePaidBy(loanTransaction, loanCharge,
|
||||||
|
loanCharge.getAmount(loan.getCurrency()).getAmount(), 1);
|
||||||
|
loanTransaction.getLoanChargesPaid().add(loanChargePaidBy);
|
||||||
|
loan.addLoanTransaction(loanTransaction);
|
||||||
LoanTransaction savedLoanTransaction = loanTransactionRepository.saveAndFlush(loanTransaction);
|
LoanTransaction savedLoanTransaction = loanTransactionRepository.saveAndFlush(loanTransaction);
|
||||||
businessEventNotifierService.notifyPostBusinessEvent(new LoanAccrualTransactionCreatedBusinessEvent(savedLoanTransaction));
|
businessEventNotifierService.notifyPostBusinessEvent(new LoanAccrualTransactionCreatedBusinessEvent(savedLoanTransaction));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
postJournalEntries(loan, existingTransactionIds, existingReversedTransactionIds);
|
||||||
|
|
||||||
for (final Map.Entry<Long, BigDecimal> entrySet : disBuLoanCharges.entrySet()) {
|
for (final Map.Entry<Long, BigDecimal> entrySet : disBuLoanCharges.entrySet()) {
|
||||||
final PortfolioAccountData savingAccountData = this.accountAssociationsReadPlatformService.retriveLoanLinkedAssociation(loanId);
|
final PortfolioAccountData savingAccountData = this.accountAssociationsReadPlatformService.retriveLoanLinkedAssociation(loanId);
|
||||||
final SavingsAccount fromSavingsAccount = null;
|
final SavingsAccount fromSavingsAccount = null;
|
||||||
|
|||||||
+41
@@ -18,6 +18,7 @@
|
|||||||
*/
|
*/
|
||||||
package org.apache.fineract.integrationtests;
|
package org.apache.fineract.integrationtests;
|
||||||
|
|
||||||
|
import static java.lang.System.lineSeparator;
|
||||||
import static org.apache.fineract.infrastructure.businessdate.domain.BusinessDateType.BUSINESS_DATE;
|
import static org.apache.fineract.infrastructure.businessdate.domain.BusinessDateType.BUSINESS_DATE;
|
||||||
import static org.apache.fineract.integrationtests.BaseLoanIntegrationTest.TransactionProcessingStrategyCode.ADVANCED_PAYMENT_ALLOCATION_STRATEGY;
|
import static org.apache.fineract.integrationtests.BaseLoanIntegrationTest.TransactionProcessingStrategyCode.ADVANCED_PAYMENT_ALLOCATION_STRATEGY;
|
||||||
import static org.apache.fineract.integrationtests.common.loans.LoanApplicationTestBuilder.DUE_PENALTY_INTEREST_PRINCIPAL_FEE_IN_ADVANCE_PENALTY_INTEREST_PRINCIPAL_FEE_STRATEGY;
|
import static org.apache.fineract.integrationtests.common.loans.LoanApplicationTestBuilder.DUE_PENALTY_INTEREST_PRINCIPAL_FEE_IN_ADVANCE_PENALTY_INTEREST_PRINCIPAL_FEE_STRATEGY;
|
||||||
@@ -26,6 +27,7 @@ import static org.junit.jupiter.api.Assertions.assertNotNull;
|
|||||||
import static org.junit.jupiter.api.Assertions.assertNull;
|
import static org.junit.jupiter.api.Assertions.assertNull;
|
||||||
import static org.junit.jupiter.api.Assertions.assertThrows;
|
import static org.junit.jupiter.api.Assertions.assertThrows;
|
||||||
import static org.junit.jupiter.api.Assertions.assertTrue;
|
import static org.junit.jupiter.api.Assertions.assertTrue;
|
||||||
|
import static org.junit.jupiter.api.Assertions.fail;
|
||||||
|
|
||||||
import io.restassured.builder.RequestSpecBuilder;
|
import io.restassured.builder.RequestSpecBuilder;
|
||||||
import io.restassured.builder.ResponseSpecBuilder;
|
import io.restassured.builder.ResponseSpecBuilder;
|
||||||
@@ -39,6 +41,7 @@ import java.time.format.DateTimeFormatter;
|
|||||||
import java.util.ArrayList;
|
import java.util.ArrayList;
|
||||||
import java.util.Arrays;
|
import java.util.Arrays;
|
||||||
import java.util.Collections;
|
import java.util.Collections;
|
||||||
|
import java.util.Comparator;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
import java.util.Locale;
|
import java.util.Locale;
|
||||||
import java.util.Objects;
|
import java.util.Objects;
|
||||||
@@ -59,6 +62,7 @@ import org.apache.fineract.client.models.GetJournalEntriesTransactionIdResponse;
|
|||||||
import org.apache.fineract.client.models.GetLoansLoanIdRepaymentPeriod;
|
import org.apache.fineract.client.models.GetLoansLoanIdRepaymentPeriod;
|
||||||
import org.apache.fineract.client.models.GetLoansLoanIdResponse;
|
import org.apache.fineract.client.models.GetLoansLoanIdResponse;
|
||||||
import org.apache.fineract.client.models.GetLoansLoanIdTransactions;
|
import org.apache.fineract.client.models.GetLoansLoanIdTransactions;
|
||||||
|
import org.apache.fineract.client.models.JournalEntryTransactionItem;
|
||||||
import org.apache.fineract.client.models.PaymentAllocationOrder;
|
import org.apache.fineract.client.models.PaymentAllocationOrder;
|
||||||
import org.apache.fineract.client.models.PostChargesResponse;
|
import org.apache.fineract.client.models.PostChargesResponse;
|
||||||
import org.apache.fineract.client.models.PostLoanProductsRequest;
|
import org.apache.fineract.client.models.PostLoanProductsRequest;
|
||||||
@@ -641,6 +645,9 @@ public abstract class BaseLoanIntegrationTest {
|
|||||||
loanTransactionHelper.undoLastDisbursalLoan(loanId, new PostLoansLoanIdRequest());
|
loanTransactionHelper.undoLastDisbursalLoan(loanId, new PostLoansLoanIdRequest());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Note: this is buggy because if multiple journal entries are for the same account, amount and type, the
|
||||||
|
// verification will pass
|
||||||
|
// not all journal entries have been validated - since there might be duplicates
|
||||||
protected void verifyJournalEntries(Long loanId, Journal... entries) {
|
protected void verifyJournalEntries(Long loanId, Journal... entries) {
|
||||||
GetJournalEntriesTransactionIdResponse journalEntriesForLoan = journalEntryHelper.getJournalEntriesForLoan(loanId);
|
GetJournalEntriesTransactionIdResponse journalEntriesForLoan = journalEntryHelper.getJournalEntriesForLoan(loanId);
|
||||||
Assertions.assertEquals(entries.length, journalEntriesForLoan.getPageItems().size());
|
Assertions.assertEquals(entries.length, journalEntriesForLoan.getPageItems().size());
|
||||||
@@ -653,6 +660,27 @@ public abstract class BaseLoanIntegrationTest {
|
|||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
protected void verifyJournalEntriesSequentially(Long loanId, Journal... entries) {
|
||||||
|
GetJournalEntriesTransactionIdResponse journalEntriesForLoan = journalEntryHelper.getJournalEntriesForLoan(loanId);
|
||||||
|
List<JournalEntryTransactionItem> sortedJournalEntries = journalEntriesForLoan.getPageItems().stream()
|
||||||
|
.sorted(Comparator.comparing(JournalEntryTransactionItem::getId)).toList();
|
||||||
|
for (int i = 0; i < entries.length && i < journalEntriesForLoan.getPageItems().size(); i++) {
|
||||||
|
Journal journalEntry = entries[i];
|
||||||
|
JournalEntryTransactionItem item = sortedJournalEntries.get(i);
|
||||||
|
boolean found = Objects.equals(item.getAmount(), journalEntry.amount)
|
||||||
|
&& Objects.equals(item.getGlAccountId(), journalEntry.account.getAccountID().longValue())
|
||||||
|
&& Objects.requireNonNull(item.getEntryType()).getValue().equals(journalEntry.type);
|
||||||
|
assertTrue(found, "Journal entry mismatch at position " + i + "." + lineSeparator() + "Wanted Journal entry: " + journalEntry
|
||||||
|
+ lineSeparator() + "Actual Journal entry: " + item);
|
||||||
|
}
|
||||||
|
if (journalEntriesForLoan.getPageItems().size() > entries.length) {
|
||||||
|
fail("Some Journal Entries are not verified. The missing entries are here: "
|
||||||
|
+ sortedJournalEntries.subList(entries.length, sortedJournalEntries.size()));
|
||||||
|
}
|
||||||
|
Assertions.assertEquals(entries.length, journalEntriesForLoan.getPageItems().size(),
|
||||||
|
"There were more journal entries expected than actually present.");
|
||||||
|
}
|
||||||
|
|
||||||
protected void verifyTRJournalEntries(Long transactionId, Journal... entries) {
|
protected void verifyTRJournalEntries(Long transactionId, Journal... entries) {
|
||||||
GetJournalEntriesTransactionIdResponse journalEntriesForLoan = journalEntryHelper.getJournalEntries("L" + transactionId.toString());
|
GetJournalEntriesTransactionIdResponse journalEntriesForLoan = journalEntryHelper.getJournalEntries("L" + transactionId.toString());
|
||||||
Assertions.assertEquals(entries.length, journalEntriesForLoan.getPageItems().size());
|
Assertions.assertEquals(entries.length, journalEntriesForLoan.getPageItems().size());
|
||||||
@@ -675,6 +703,13 @@ public abstract class BaseLoanIntegrationTest {
|
|||||||
return loanChargeId.longValue();
|
return loanChargeId.longValue();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
protected Long createDisbursementPercentageCharge(double percentageAmount) {
|
||||||
|
Integer chargeId = ChargesHelper.createCharges(requestSpec, responseSpec, ChargesHelper
|
||||||
|
.getLoanDisbursementJSON(ChargesHelper.CHARGE_CALCULATION_TYPE_PERCENTAGE_AMOUNT, String.valueOf(percentageAmount)));
|
||||||
|
assertNotNull(chargeId);
|
||||||
|
return chargeId.longValue();
|
||||||
|
}
|
||||||
|
|
||||||
protected void verifyRepaymentSchedule(Long loanId, Installment... installments) {
|
protected void verifyRepaymentSchedule(Long loanId, Installment... installments) {
|
||||||
GetLoansLoanIdResponse loanResponse = loanTransactionHelper.getLoan(requestSpec, responseSpec, loanId.intValue());
|
GetLoansLoanIdResponse loanResponse = loanTransactionHelper.getLoan(requestSpec, responseSpec, loanId.intValue());
|
||||||
DateTimeFormatter dateTimeFormatter = DateTimeFormatter.ofPattern(DATETIME_PATTERN);
|
DateTimeFormatter dateTimeFormatter = DateTimeFormatter.ofPattern(DATETIME_PATTERN);
|
||||||
@@ -1192,6 +1227,11 @@ public abstract class BaseLoanIntegrationTest {
|
|||||||
public static final Integer FLAT = 1;
|
public static final Integer FLAT = 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public static class InterestRecalculationCompoundingMethod {
|
||||||
|
|
||||||
|
public static final Integer NONE = 0;
|
||||||
|
}
|
||||||
|
|
||||||
public static class RepaymentFrequencyType {
|
public static class RepaymentFrequencyType {
|
||||||
|
|
||||||
public static final Integer MONTHS = 2;
|
public static final Integer MONTHS = 2;
|
||||||
@@ -1227,6 +1267,7 @@ public abstract class BaseLoanIntegrationTest {
|
|||||||
|
|
||||||
public static class RescheduleStrategyMethod {
|
public static class RescheduleStrategyMethod {
|
||||||
|
|
||||||
|
public static final Integer REDUCE_EMI_AMOUNT = 3;
|
||||||
public static final Integer ADJUST_LAST_UNPAID_PERIOD = 4;
|
public static final Integer ADJUST_LAST_UNPAID_PERIOD = 4;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
+3
@@ -18,6 +18,9 @@
|
|||||||
*/
|
*/
|
||||||
package org.apache.fineract.integrationtests.common.accounting;
|
package org.apache.fineract.integrationtests.common.accounting;
|
||||||
|
|
||||||
|
import lombok.ToString;
|
||||||
|
|
||||||
|
@ToString
|
||||||
public class Account {
|
public class Account {
|
||||||
|
|
||||||
public enum AccountType {
|
public enum AccountType {
|
||||||
|
|||||||
+133
@@ -0,0 +1,133 @@
|
|||||||
|
/**
|
||||||
|
* 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.integrationtests.loan.repayment;
|
||||||
|
|
||||||
|
import java.math.BigDecimal;
|
||||||
|
import java.util.List;
|
||||||
|
import org.apache.fineract.client.models.ChargeData;
|
||||||
|
import org.apache.fineract.client.models.PostLoanProductsRequest;
|
||||||
|
import org.apache.fineract.client.models.PostLoanProductsResponse;
|
||||||
|
import org.apache.fineract.client.models.PostLoansLoanIdResponse;
|
||||||
|
import org.apache.fineract.client.models.PostLoansRequest;
|
||||||
|
import org.apache.fineract.client.models.PostLoansRequestChargeData;
|
||||||
|
import org.apache.fineract.client.models.PostLoansResponse;
|
||||||
|
import org.apache.fineract.integrationtests.BaseLoanIntegrationTest;
|
||||||
|
import org.apache.fineract.integrationtests.common.ClientHelper;
|
||||||
|
import org.junit.jupiter.api.Test;
|
||||||
|
|
||||||
|
public class LoanRepaymentTest extends BaseLoanIntegrationTest {
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void test_LoanRepaymentWorks_WhenDisbursementChargeIsAvailable_AndAccrualAccounting_AndDailyRecalculateInterest_AndDailyInterestCalculationPeriod() {
|
||||||
|
|
||||||
|
runAt("01 January 2023", () -> {
|
||||||
|
// Create Client
|
||||||
|
Long clientId = clientHelper.createClient(ClientHelper.defaultClientCreationRequest()).getClientId();
|
||||||
|
|
||||||
|
int numberOfRepayments = 3;
|
||||||
|
int repaymentEvery = 1;
|
||||||
|
|
||||||
|
// Create charges
|
||||||
|
double charge1Amount = 1.0;
|
||||||
|
double charge2Amount = 1.5;
|
||||||
|
Long charge1Id = createDisbursementPercentageCharge(charge1Amount);
|
||||||
|
Long charge2Id = createDisbursementPercentageCharge(charge2Amount);
|
||||||
|
|
||||||
|
// Create Loan Product
|
||||||
|
PostLoanProductsRequest product = createOnePeriod30DaysLongNoInterestPeriodicAccrualProduct() //
|
||||||
|
.numberOfRepayments(numberOfRepayments) //
|
||||||
|
.repaymentEvery(repaymentEvery) //
|
||||||
|
.installmentAmountInMultiplesOf(null) //
|
||||||
|
.repaymentFrequencyType(RepaymentFrequencyType.MONTHS.longValue()) //
|
||||||
|
.interestType(InterestType.DECLINING_BALANCE)//
|
||||||
|
.interestCalculationPeriodType(InterestCalculationPeriodType.DAILY)//
|
||||||
|
.interestRecalculationCompoundingMethod(InterestRecalculationCompoundingMethod.NONE)//
|
||||||
|
.rescheduleStrategyMethod(RescheduleStrategyMethod.ADJUST_LAST_UNPAID_PERIOD)//
|
||||||
|
.isInterestRecalculationEnabled(true)//
|
||||||
|
.recalculationRestFrequencyInterval(1)//
|
||||||
|
.recalculationRestFrequencyType(RecalculationRestFrequencyType.DAILY)//
|
||||||
|
.rescheduleStrategyMethod(RescheduleStrategyMethod.REDUCE_EMI_AMOUNT)//
|
||||||
|
.allowPartialPeriodInterestCalcualtion(false)//
|
||||||
|
.disallowExpectedDisbursements(false)//
|
||||||
|
.allowApprovedDisbursedAmountsOverApplied(false)//
|
||||||
|
.overAppliedNumber(null)//
|
||||||
|
.overAppliedCalculationType(null)//
|
||||||
|
.multiDisburseLoan(null)//
|
||||||
|
.charges(List.of(new ChargeData().id(charge1Id), new ChargeData().id(charge2Id)));//
|
||||||
|
|
||||||
|
PostLoanProductsResponse loanProductResponse = loanProductHelper.createLoanProduct(product);
|
||||||
|
Long loanProductId = loanProductResponse.getResourceId();
|
||||||
|
|
||||||
|
// Apply and Approve Loan
|
||||||
|
double amount = 1000.0;
|
||||||
|
|
||||||
|
PostLoansRequest applicationRequest = applyLoanRequest(clientId, loanProductId, "01 January 2023", amount, numberOfRepayments)//
|
||||||
|
.repaymentEvery(repaymentEvery)//
|
||||||
|
.loanTermFrequency(numberOfRepayments)//
|
||||||
|
.repaymentFrequencyType(RepaymentFrequencyType.MONTHS)//
|
||||||
|
.loanTermFrequencyType(RepaymentFrequencyType.MONTHS)//
|
||||||
|
.interestType(InterestType.DECLINING_BALANCE)//
|
||||||
|
.interestCalculationPeriodType(InterestCalculationPeriodType.DAILY)//
|
||||||
|
.charges(List.of(//
|
||||||
|
new PostLoansRequestChargeData().chargeId(charge1Id).amount(BigDecimal.valueOf(charge1Amount)), //
|
||||||
|
new PostLoansRequestChargeData().chargeId(charge2Id).amount(BigDecimal.valueOf(charge2Amount))//
|
||||||
|
));//
|
||||||
|
|
||||||
|
PostLoansResponse postLoansResponse = loanTransactionHelper.applyLoan(applicationRequest);
|
||||||
|
|
||||||
|
PostLoansLoanIdResponse approvedLoanResult = loanTransactionHelper.approveLoan(postLoansResponse.getResourceId(),
|
||||||
|
approveLoanRequest(amount, "01 January 2023"));
|
||||||
|
|
||||||
|
Long loanId = approvedLoanResult.getLoanId();
|
||||||
|
|
||||||
|
// disburse Loan
|
||||||
|
disburseLoan(loanId, BigDecimal.valueOf(1000.0), "01 January 2023");
|
||||||
|
|
||||||
|
// verify transactions
|
||||||
|
verifyTransactions(loanId, //
|
||||||
|
transaction(1000.0, "Disbursement", "01 January 2023"), //
|
||||||
|
transaction(25.0, "Repayment (at time of disbursement)", "01 January 2023"), //
|
||||||
|
transaction(10.0, "Accrual", "01 January 2023"), //
|
||||||
|
transaction(15.0, "Accrual", "01 January 2023") //
|
||||||
|
);
|
||||||
|
|
||||||
|
// verify journal entries
|
||||||
|
verifyJournalEntries(loanId, //
|
||||||
|
journalEntry(1000.0, loansReceivableAccount, "DEBIT"), //
|
||||||
|
journalEntry(1000.0, fundSource, "CREDIT"), //
|
||||||
|
journalEntry(25.0, feeIncomeAccount, "CREDIT"), //
|
||||||
|
journalEntry(25.0, fundSource, "DEBIT"), //
|
||||||
|
journalEntry(10.0, feeReceivableAccount, "DEBIT"), //
|
||||||
|
journalEntry(10.0, feeIncomeAccount, "CREDIT"), //
|
||||||
|
journalEntry(15.0, feeReceivableAccount, "DEBIT"), //
|
||||||
|
journalEntry(15.0, feeIncomeAccount, "CREDIT") //
|
||||||
|
);
|
||||||
|
|
||||||
|
// repay 500
|
||||||
|
addRepaymentForLoan(loanId, 500.0, "01 January 2023");
|
||||||
|
|
||||||
|
// verify transactions
|
||||||
|
verifyTransactions(loanId, //
|
||||||
|
transaction(1000.0, "Disbursement", "01 January 2023"), //
|
||||||
|
transaction(25.0, "Repayment (at time of disbursement)", "01 January 2023"), //
|
||||||
|
transaction(500.0, "Repayment", "01 January 2023") //
|
||||||
|
);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
Reference in New Issue
Block a user