Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
15 commits
Select commit Hold shift + click to select a range
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -204,6 +204,8 @@ public static final class PostCreateRescheduleLoansRequest {
public Long rescheduleReasonId;
@Schema(example = "20 September 2011")
public String submittedOnDate;
@Schema(example = "true")
public Boolean recalculateInterest;
}

@Schema(description = "PostUpdateRescheduleLoansRequest")
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -1408,6 +1408,14 @@ private PostLoansRequest() {}
public String daysInYearCustomStrategy;
@Schema(example = "individual")
public String loanType;
@Schema(example = "false", description = "Take the rate from the product's floating rate instead of interestRatePerPeriod")
public Boolean isFloatingInterestRate;
@Schema(example = "0", description = "Added to the floating rate when isFloatingInterestRate is true")
public BigDecimal interestRateDifferential;
@Schema(example = "1", description = "Meeting calendar to attach the loan to; required for jlg loans")
public Long calendarId;
@Schema(example = "true", description = "Sync the disbursement date with the attached meeting")
public Boolean syncDisbursementWithMeeting;
@Schema(example = "20 September 2011")
public String submittedOnDate;
@Schema(example = "786444UUUYYH7")
Expand All @@ -1418,10 +1426,12 @@ private PostLoansRequest() {}
public Boolean allowFullTermForTranche;
@Schema(description = "Maximum allowed outstanding balance")
public BigDecimal maxOutstandingLoanBalance;
@Schema(example = "[2011, 10, 20]")
public LocalDate repaymentsStartingFromDate;
@Schema(example = "20 September 2011")
public String repaymentsStartingFromDate;
@Schema(example = "1")
public Integer graceOnInterestCharged;
@Schema(example = "20 September 2011")
public String interestChargedFromDate;
@Schema(example = "1")
public Integer graceOnPrincipalPayment;
@Schema(example = "1")
Expand Down Expand Up @@ -1467,6 +1477,8 @@ private PostLoansRequest() {}
public List<PostLoansRequestCollateralData> collateral;
@Schema(example = "1")
public Long linkAccountId;
@Schema(example = "true", description = "Requires linkAccountId when true")
public Boolean createStandingInstructionAtDisbursement;

@Schema(description = """
Optional array of originators to associate with this loan. \
Expand Down Expand Up @@ -1803,8 +1815,10 @@ static final class PostLoansLoanIdDisbursementData {

private PostLoansLoanIdDisbursementData() {}

@Schema(example = "[2012, 4, 3]")
public LocalDate expectedDisbursementDate;
// Parsed with the request's dateFormat, like every other date on this DTO. Declaring it
// LocalDate made a generated client serialise ISO into a body declaring "dd MMMM yyyy".
@Schema(example = "1 November 2023")
public String expectedDisbursementDate;
@Schema(example = "22000")
public BigDecimal principal;
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -6302,7 +6302,7 @@ private static Long createLoanProduct(final String principal, final String repay
boolean autoPayForDownPayment, LoanScheduleType loanScheduleType, LoanScheduleProcessingType loanScheduleProcessingType,
AdvancedPaymentData allocationRuleData, final Account... accounts) {
LOG.info("------------------------------CREATING NEW LOAN PRODUCT ---------------------------------------");
final String loanProductJSON = new LoanProductTestBuilder().withMinPrincipal(principal).withPrincipal(principal)
final PostLoanProductsRequest loanProductRequest = new LoanProductTestBuilder().withMinPrincipal(principal).withPrincipal(principal)
.withRepaymentTypeAsDays().withRepaymentAfterEvery(repaymentAfterEvery).withNumberOfRepayments(numberOfRepayments)
.withEnableDownPayment(true, "25", autoPayForDownPayment).withinterestRatePerPeriod("0")
.withInterestRateFrequencyTypeAsMonths()
Expand All @@ -6311,30 +6311,30 @@ private static Long createLoanProduct(final String principal, final String repay
.addAdvancedPaymentAllocation(allocationRuleData).withInterestCalculationPeriodTypeAsRepaymentPeriod(true)
.withInterestTypeAsDecliningBalance().withMultiDisburse().withDisallowExpectedDisbursements(true)
.withLoanScheduleType(loanScheduleType).withLoanScheduleProcessingType(loanScheduleProcessingType).withDaysInMonth("30")
.withDaysInYear("365").withMoratorium("0", "0").build(null);
return loanHelper.createLoanProductFromJson(loanProductJSON);
.withDaysInYear("365").withMoratorium("0", "0").buildRequest(null);
return loanHelper.createLoanProduct(loanProductRequest).getResourceId();
}

private static Long createLoanProduct(final String principal, final String repaymentAfterEvery, final String numberOfRepayments,
boolean autoPayForDownPayment, LoanScheduleType loanScheduleType, final Account... accounts) {
LOG.info("------------------------------CREATING NEW LOAN PRODUCT ---------------------------------------");
final String loanProductJSON = new LoanProductTestBuilder().withMinPrincipal(principal).withPrincipal(principal)
final PostLoanProductsRequest loanProductRequest = new LoanProductTestBuilder().withMinPrincipal(principal).withPrincipal(principal)
.withRepaymentTypeAsDays().withRepaymentAfterEvery(repaymentAfterEvery).withNumberOfRepayments(numberOfRepayments)
.withEnableDownPayment(true, "25", autoPayForDownPayment).withinterestRatePerPeriod("0")
.withInterestRateFrequencyTypeAsMonths()
.withRepaymentStrategy(EarlyPaymentLoanRepaymentScheduleTransactionProcessor.STRATEGY_CODE)
.withAmortizationTypeAsEqualPrincipalPayment().withInterestTypeAsFlat().withAccountingRulePeriodicAccrual(accounts)
.withInterestCalculationPeriodTypeAsRepaymentPeriod(true).withInterestTypeAsDecliningBalance().withMultiDisburse()
.withDisallowExpectedDisbursements(true).withLoanScheduleType(loanScheduleType).withDaysInMonth("30").withDaysInYear("365")
.withMoratorium("0", "0").build(null);
return loanHelper.createLoanProductFromJson(loanProductJSON);
.withMoratorium("0", "0").buildRequest(null);
return loanHelper.createLoanProduct(loanProductRequest).getResourceId();
}

private static ArrayList<HashMap<String, Object>> createLoanProductGetError(final String principal, final String repaymentAfterEvery,
final String numberOfRepayments, boolean autoPayForDownPayment, LoanScheduleType loanScheduleType,
LoanScheduleProcessingType loanScheduleProcessingType, AdvancedPaymentData allocationRuleData, final Account... accounts) {
LOG.info("------------------------------CREATING NEW LOAN PRODUCT ---------------------------------------");
final String loanProductJSON = new LoanProductTestBuilder().withMinPrincipal(principal).withPrincipal(principal)
final PostLoanProductsRequest loanProductRequest = new LoanProductTestBuilder().withMinPrincipal(principal).withPrincipal(principal)
.withRepaymentTypeAsDays().withRepaymentAfterEvery(repaymentAfterEvery).withNumberOfRepayments(numberOfRepayments)
.withEnableDownPayment(true, "25", autoPayForDownPayment).withinterestRatePerPeriod("0")
.withInterestRateFrequencyTypeAsMonths()
Expand All @@ -6343,8 +6343,8 @@ private static ArrayList<HashMap<String, Object>> createLoanProductGetError(fina
.addAdvancedPaymentAllocation(allocationRuleData).withInterestCalculationPeriodTypeAsRepaymentPeriod(true)
.withInterestTypeAsDecliningBalance().withMultiDisburse().withDisallowExpectedDisbursements(true)
.withLoanScheduleType(loanScheduleType).withLoanScheduleProcessingType(loanScheduleProcessingType).withDaysInMonth("30")
.withDaysInYear("365").withMoratorium("0", "0").build(null);
return loanHelper.getLoanProductError(loanProductJSON, CommonConstants.RESPONSE_ERROR);
.withDaysInYear("365").withMoratorium("0", "0").buildRequest(null);
return loanHelper.getLoanProductError(loanProductRequest, CommonConstants.RESPONSE_ERROR);
}

private static Long createLoanProduct(final String principal, final String repaymentAfterEvery, final String numberOfRepayments,
Expand All @@ -6355,7 +6355,7 @@ private static Long createLoanProduct(final String principal, final String repay
AdvancedPaymentData merchantIssuedRefundAllocation = createPaymentAllocation("MERCHANT_ISSUED_REFUND", "REAMORTIZATION");
AdvancedPaymentData payoutRefundAllocation = createPaymentAllocation("PAYOUT_REFUND", "NEXT_INSTALLMENT");
LOG.info("------------------------------CREATING NEW LOAN PRODUCT ---------------------------------------");
final String loanProductJSON = new LoanProductTestBuilder().withMinPrincipal(principal).withPrincipal(principal)
final PostLoanProductsRequest loanProductRequest = new LoanProductTestBuilder().withMinPrincipal(principal).withPrincipal(principal)
.withRepaymentTypeAsDays().withRepaymentAfterEvery(repaymentAfterEvery).withNumberOfRepayments(numberOfRepayments)
.withEnableDownPayment(downPaymentEnabled, downPaymentPercentage, autoPayForDownPayment).withinterestRatePerPeriod("0")
.withInterestRateFrequencyTypeAsMonths()
Expand All @@ -6366,8 +6366,8 @@ private static Long createLoanProduct(final String principal, final String repay
.withInterestCalculationPeriodTypeAsRepaymentPeriod(true).withInterestTypeAsDecliningBalance().withMultiDisburse()
.withDisallowExpectedDisbursements(true).withLoanScheduleType(loanScheduleType)
.withLoanScheduleProcessingType(loanScheduleProcessingType).withDaysInMonth("30").withDaysInYear("365")
.withMoratorium("0", "0").build(null);
return loanHelper.createLoanProductFromJson(loanProductJSON);
.withMoratorium("0", "0").buildRequest(null);
return loanHelper.createLoanProduct(loanProductRequest).getResourceId();
}

private static void validatePeriod(GetLoansLoanIdResponse loanDetails, Integer index, LocalDate dueDate, LocalDate paidDate,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -22,12 +22,14 @@
import static org.junit.jupiter.api.Assertions.assertNotNull;
import static org.junit.jupiter.api.Assertions.assertThrows;

import java.math.BigDecimal;
import org.apache.fineract.client.feign.util.CallFailedRuntimeException;
import org.apache.fineract.client.models.GetLoansLoanIdChargesChargeIdResponse;
import org.apache.fineract.client.models.PostLoanProductsRequest;
import org.apache.fineract.client.models.PostLoansLoanIdChargesRequest;
import org.apache.fineract.client.models.PostLoansLoanIdChargesResponse;
import org.apache.fineract.integrationtests.client.feign.FeignLoanTestBase;
import org.apache.fineract.integrationtests.common.loans.LoanApplicationTestBuilder;
import org.apache.fineract.integrationtests.client.feign.modules.LoanRequestBuilders;
import org.apache.fineract.integrationtests.common.loans.LoanProductTestBuilder;
import org.junit.jupiter.api.BeforeEach;
import org.junit.jupiter.api.Test;
Expand All @@ -48,9 +50,9 @@ public void checkNewClientLoanChargeSavesExternalId() {

final Long loanProductId = createLoanProduct(false, NONE);

final Long loanId = applyForLoanApplication(clientId, loanProductId, "12,000.00");
final Long loanId = applyForLoanWithPrincipal(clientId, loanProductId, "12,000.00");
approveLoan(loanId, approveLoanRequest(12000.0, "20 September 2011"));
disburseLoanWithNetDisbursalAmount(loanId, "20 September 2011", "12,000.00");
disburseLoanWithNetDisbursalAmount(loanId, "20 September 2011", "12000.00");

final Long chargeDefId = chargesHelper.createLoanSpecifiedDueDatePercentageOfInterestFee(1.0).getResourceId();

Expand All @@ -70,9 +72,9 @@ public void checkNewClientLoanChargeFindsDuplicateExternalId() {

final Long loanProductId = createLoanProduct(false, NONE);

final Long loanId = applyForLoanApplication(clientId, loanProductId, "12,000.00");
final Long loanId = applyForLoanWithPrincipal(clientId, loanProductId, "12,000.00");
approveLoan(loanId, approveLoanRequest(12000.0, "20 September 2011"));
disburseLoanWithNetDisbursalAmount(loanId, "20 September 2011", "12,000.00");
disburseLoanWithNetDisbursalAmount(loanId, "20 September 2011", "12000.00");

final Long chargeDefId = chargesHelper.createLoanSpecifiedDueDatePercentageOfInterestFee(1.0).getResourceId();

Expand Down Expand Up @@ -103,25 +105,12 @@ private Long createLoanProduct(final boolean multiDisburseLoan, final String acc
if (multiDisburseLoan) {
builder = builder.withInterestCalculationPeriodTypeAsRepaymentPeriod(true);
}
final String loanProductJSON = builder.build(null);
return createLoanProductFromJson(loanProductJSON);
final PostLoanProductsRequest loanProductRequest = builder.buildRequest(null);
return createLoanProduct(loanProductRequest);
}

private Long applyForLoanApplication(final Long clientId, final Long loanProductId, String principal) {
final String loanApplicationJSON = new LoanApplicationTestBuilder() //
.withPrincipal(principal) //
.withLoanTermFrequency("4") //
.withLoanTermFrequencyAsMonths() //
.withNumberOfRepayments("4") //
.withRepaymentEveryAfter("1") //
.withRepaymentFrequencyTypeAsMonths() //
.withInterestRatePerPeriod("2") //
.withAmortizationTypeAsEqualInstallments() //
.withInterestTypeAsDecliningBalance() //
.withInterestCalculationPeriodTypeSameAsRepaymentPeriod() //
.withExpectedDisbursementDate("20 September 2011") //
.withSubmittedOnDate("20 September 2011") //
.build(clientId.toString(), loanProductId.toString(), null);
return applyForLoanFromJson(loanApplicationJSON);
private Long applyForLoanWithPrincipal(final Long clientId, final Long loanProductId, String principal) {
return applyForLoan(LoanRequestBuilders.legacyIndividualApplication(clientId, loanProductId, principal, 4, new BigDecimal("2"),
"20 September 2011"));
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -39,6 +39,7 @@
import org.apache.fineract.client.models.GetLoansLoanIdSummary;
import org.apache.fineract.client.models.GetLoansLoanIdTransactions;
import org.apache.fineract.client.models.GetLoansLoanIdTransactionsTransactionIdResponse;
import org.apache.fineract.client.models.PostLoanProductsRequest;
import org.apache.fineract.client.models.PostLoansLoanIdRequest;
import org.apache.fineract.client.models.PostLoansLoanIdTransactionsRequest;
import org.apache.fineract.client.models.PostLoansLoanIdTransactionsResponse;
Expand All @@ -49,7 +50,6 @@
import org.apache.fineract.integrationtests.common.Utils;
import org.apache.fineract.integrationtests.common.accounting.Account;
import org.apache.fineract.integrationtests.common.accounting.JournalEntry;
import org.apache.fineract.integrationtests.common.loans.LoanApplicationTestBuilder;
import org.apache.fineract.integrationtests.common.loans.LoanProductTestBuilder;
import org.apache.fineract.portfolio.loanaccount.loanschedule.domain.LoanScheduleType;
import org.junit.jupiter.api.Assertions;
Expand Down Expand Up @@ -104,28 +104,15 @@ private Long createLoanProduct(LoanProductTestBuilder loanProductTestBuilder, fi
loanProductTestBuilder = loanProductTestBuilder.withInterestCalculationPeriodTypeAsRepaymentPeriod(true);
loanProductTestBuilder = loanProductTestBuilder.withMaxTrancheCount("30");
}
final String loanProductJSON = loanProductTestBuilder.build(null);
return createLoanProductFromJson(loanProductJSON);
final PostLoanProductsRequest loanProductRequest = loanProductTestBuilder.buildRequest(null);
return createLoanProduct(loanProductRequest);
}

private Long applyForLoanApplication(final Long clientID, final Long loanProductID, String principal, String submitDate,
String repaymentStrategy) {
final String loanApplicationJSON = new LoanApplicationTestBuilder() //
.withPrincipal(principal) //
.withLoanTermFrequency("4") //
.withLoanTermFrequencyAsMonths() //
.withNumberOfRepayments("4") //
.withRepaymentEveryAfter("1") //
.withRepaymentFrequencyTypeAsMonths() //
.withInterestRatePerPeriod("2") //
.withAmortizationTypeAsEqualInstallments() //
.withInterestTypeAsDecliningBalance() //
.withInterestCalculationPeriodTypeSameAsRepaymentPeriod() //
.withExpectedDisbursementDate(submitDate) //
.withSubmittedOnDate(submitDate) //
.withRepaymentStrategy(repaymentStrategy) //
.build(clientID.toString(), loanProductID.toString(), null);
return applyForLoanFromJson(loanApplicationJSON);
return applyForLoan(
LoanRequestBuilders.legacyIndividualApplication(clientID, loanProductID, principal, 4, new BigDecimal("2"), submitDate)
.transactionProcessingStrategyCode(repaymentStrategy));
}

private Long fromStartToDisburseLoan(LoanProductTestBuilder loanProductTestBuilder, String submitApproveDisburseDate, String principal,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -136,6 +136,8 @@ public class ClientLoanIntegrationTest extends FeignLoanTestBase {
/** The loan/product JSON builders this test replaced used {@code en_GB}; keep it so number parsing is unchanged. */
private static final String LOCALE = "en_GB";
private static final String OVERRIDE_MESSAGE = "Loan overrode the product's %s";
/** The disburse-to-savings JSON builder this test replaced always sent this note; keep the payload unchanged. */
private static final String DISBURSE_NOTE = "DISBURSE NOTE";
/** The interoperation repayment body was built with plain {@code en}, unlike the {@code en_GB} used elsewhere. */
private static final String INTEROP_LOCALE = "en";

Expand Down Expand Up @@ -7298,8 +7300,9 @@ private Long applyForLoanApplicationForInterestRecalculationWithFirstRepaymentDa
.expectedDisbursementDate(disbursementDate)//
.submittedOnDate(disbursementDate)//
.transactionProcessingStrategyCode(repaymentStrategy)//
.collateral(createClientCollateral(clientId));
return applyForLoan(LoanRequestBuilders.applyLoanWithLegacyDates(request, null, firstRepaymentDate));
.collateral(createClientCollateral(clientId))//
.repaymentsStartingFromDate(firstRepaymentDate);
return applyForLoan(request);
}

private PostLoansResponse applyForLoanApplicationForOnePeriod30DaysLongNoInterestPeriodicAccrual(Long clientId, Long loanProductId,
Expand Down Expand Up @@ -7824,7 +7827,8 @@ private GetLoansLoanIdResponse disburseToSavingsWithNetDisbursalAmount(String da
.actualDisbursementDate(date)//
.dateFormat(DATETIME_PATTERN)//
.locale(LOCALE)//
.netDisbursalAmount(netDisbursalAmount));
.netDisbursalAmount(netDisbursalAmount)//
.note(DISBURSE_NOTE));
return getLoanDetails(loanId);
}

Expand Down
Loading
Loading