Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
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

Large diffs are not rendered by default.

Original file line number Diff line number Diff line change
Expand Up @@ -863,9 +863,18 @@ private void createWorkingCapitalLoanAccount(final List<String> loanData) {
final PostWorkingCapitalLoansResponse response = ok(
() -> fineractClient.workingCapitalLoans().submitWorkingCapitalLoanApplication(loansRequest));
testContext().set(TestContextKey.LOAN_CREATE_RESPONSE, response);
trackLoanIdIfEnabled(response.getLoanId());
log.info("Working Capital Loan created with ID: {}", response.getLoanId());
}

@SuppressWarnings("unchecked")
private void trackLoanIdIfEnabled(final Long loanId) {
final List<Long> trackedIds = testContext().get(TestContextKey.WC_LOAN_IDS);
if (trackedIds != null) {
trackedIds.add(loanId);
}
}

private void modifyWorkingCapitalLoanAccount(final List<String> loanData) {
final PutWorkingCapitalLoansLoanIdRequest modifyRequest = buildModifyLoanRequest(loanData);

Expand Down Expand Up @@ -945,6 +954,11 @@ private Long extractClientId() {
}

private Long resolveLoanProductId(final String loanProductName) {
if ("WCLP_DELINQUENCY".equals(loanProductName)) {
final PostWorkingCapitalLoanProductsResponse response = testContext()
.get(TestContextKey.WORKING_CAPITAL_LOAN_PRODUCT_CREATE_RESPONSE);
return response.getResourceId();
}
final DefaultWorkingCapitalLoanProduct product = DefaultWorkingCapitalLoanProduct.valueOf(loanProductName);
return workingCapitalLoanProductResolver.resolve(product);
}
Expand Down

Large diffs are not rendered by default.

Original file line number Diff line number Diff line change
Expand Up @@ -20,5 +20,6 @@

public enum DelinquencyAction {
PAUSE, //
RESUME //
RESUME, //
RESCHEDULE //
}
Original file line number Diff line number Diff line change
Expand Up @@ -66,7 +66,7 @@ public class WorkingCapitalLoanDelinquencyActionApiResource {
@Path("{loanId}/delinquency-actions")
@Consumes({ MediaType.APPLICATION_JSON })
@Produces({ MediaType.APPLICATION_JSON })
@Operation(summary = "Create Delinquency Pause Action", description = "Creates a delinquency pause action for a Working Capital loan, extending the active delinquency range period and shifting future periods by the pause duration.")
@Operation(summary = "Create Delinquency Action", description = "Creates a delinquency action (pause or reschedule) for a Working Capital loan.")
@RequestBody(required = true, content = @Content(schema = @Schema(implementation = WorkingCapitalLoanDelinquencyActionApiResourceSwagger.PostWorkingCapitalLoansDelinquencyActionRequest.class)))
@ApiResponses({
@ApiResponse(responseCode = "200", description = "OK", content = @Content(schema = @Schema(implementation = WorkingCapitalLoanDelinquencyActionApiResourceSwagger.PostWorkingCapitalLoansDelinquencyActionResponse.class))),
Expand All @@ -86,7 +86,7 @@ public CommandProcessingResult createDelinquencyAction(@PathParam("loanId") @Par
@Path("external-id/{loanExternalId}/delinquency-actions")
@Consumes({ MediaType.APPLICATION_JSON })
@Produces({ MediaType.APPLICATION_JSON })
@Operation(operationId = "createDelinquencyActionByExternalId", summary = "Create Delinquency Pause Action by external id", description = "Creates a delinquency pause action for a Working Capital loan identified by external id, extending the active delinquency range period and shifting future periods by the pause duration.")
@Operation(operationId = "createDelinquencyActionByExternalId", summary = "Create Delinquency Action by external id", description = "Creates a delinquency action (pause or reschedule) for a Working Capital loan identified by external id.")
@RequestBody(required = true, content = @Content(schema = @Schema(implementation = WorkingCapitalLoanDelinquencyActionApiResourceSwagger.PostWorkingCapitalLoansDelinquencyActionRequest.class)))
@ApiResponses({
@ApiResponse(responseCode = "200", description = "OK", content = @Content(schema = @Schema(implementation = WorkingCapitalLoanDelinquencyActionApiResourceSwagger.PostWorkingCapitalLoansDelinquencyActionResponse.class))),
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,7 @@
package org.apache.fineract.portfolio.workingcapitalloan.api;

import io.swagger.v3.oas.annotations.media.Schema;
import java.math.BigDecimal;

public final class WorkingCapitalLoanDelinquencyActionApiResourceSwagger {

Expand All @@ -29,12 +30,20 @@ public static final class PostWorkingCapitalLoansDelinquencyActionRequest {

private PostWorkingCapitalLoansDelinquencyActionRequest() {}

@Schema(example = "pause")
@Schema(example = "pause", description = "Delinquency action type: pause or reschedule")
public String action;
@Schema(example = "2026-03-05")
@Schema(example = "2026-03-05", description = "Start date of the pause period (required for pause)")
public String startDate;
@Schema(example = "2026-03-12")
@Schema(example = "2026-03-12", description = "End date of the pause period (required for pause)")
public String endDate;
@Schema(example = "2", description = "Minimum payment value (required together with minimumPaymentType)")
public BigDecimal minimumPayment;
@Schema(example = "PERCENTAGE", description = "Minimum payment type: PERCENTAGE, FLAT (required together with minimumPayment)")
public String minimumPaymentType;
@Schema(example = "30", description = "Frequency value (required together with frequencyType)")
public Integer frequency;
@Schema(example = "DAYS", description = "Frequency type: DAYS, WEEKS, MONTHS, YEARS (required together with frequency)")
public String frequencyType;
@Schema(example = "yyyy-MM-dd")
public String dateFormat;
@Schema(example = "en")
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -18,11 +18,14 @@
*/
package org.apache.fineract.portfolio.workingcapitalloan.data;

import java.math.BigDecimal;
import java.time.LocalDate;
import lombok.AllArgsConstructor;
import lombok.Getter;
import lombok.Setter;
import org.apache.fineract.portfolio.delinquency.domain.DelinquencyAction;
import org.apache.fineract.portfolio.delinquency.domain.DelinquencyFrequencyType;
import org.apache.fineract.portfolio.delinquency.domain.DelinquencyMinimumPaymentType;

@AllArgsConstructor
@Getter
Expand All @@ -33,5 +36,9 @@ public class WorkingCapitalLoanDelinquencyActionData {
private DelinquencyAction action;
private LocalDate startDate;
private LocalDate endDate;
private BigDecimal minimumPayment;
private DelinquencyMinimumPaymentType minimumPaymentType;
private Integer frequency;
private DelinquencyFrequencyType frequencyType;

}
Original file line number Diff line number Diff line change
Expand Up @@ -26,12 +26,15 @@
import jakarta.persistence.JoinColumn;
import jakarta.persistence.ManyToOne;
import jakarta.persistence.Table;
import java.math.BigDecimal;
import java.time.LocalDate;
import lombok.Getter;
import lombok.NoArgsConstructor;
import lombok.Setter;
import org.apache.fineract.infrastructure.core.domain.AbstractAuditableWithUTCDateTimeCustom;
import org.apache.fineract.portfolio.delinquency.domain.DelinquencyAction;
import org.apache.fineract.portfolio.delinquency.domain.DelinquencyFrequencyType;
import org.apache.fineract.portfolio.delinquency.domain.DelinquencyMinimumPaymentType;

@Getter
@Setter
Expand All @@ -51,7 +54,21 @@ public class WorkingCapitalLoanDelinquencyAction extends AbstractAuditableWithUT
@Column(name = "start_date", nullable = false)
private LocalDate startDate;

@Column(name = "end_date", nullable = false)
@Column(name = "end_date")
private LocalDate endDate;

@Column(name = "minimum_payment", scale = 6, precision = 19)
private BigDecimal minimumPayment;

@Enumerated(EnumType.STRING)
@Column(name = "minimum_payment_type")
private DelinquencyMinimumPaymentType minimumPaymentType;

@Column(name = "frequency")
private Integer frequency;

@Enumerated(EnumType.STRING)
@Column(name = "frequency_type")
private DelinquencyFrequencyType frequencyType;

}
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,7 @@
import jakarta.persistence.ManyToOne;
import jakarta.persistence.Table;
import jakarta.persistence.UniqueConstraint;
import jakarta.persistence.Version;
import java.math.BigDecimal;
import java.time.LocalDate;
import lombok.Getter;
Expand All @@ -40,6 +41,10 @@
@UniqueConstraint(columnNames = { "wc_loan_id", "period_number" }, name = "uc_wc_delinquency_range_schedule_loan_period") })
public class WorkingCapitalLoanDelinquencyRangeSchedule extends AbstractAuditableWithUTCDateTimeCustom<Long> {

@Version
@Column(name = "version")
private Integer version;

@ManyToOne(fetch = FetchType.LAZY)
@JoinColumn(name = "wc_loan_id", nullable = false)
private WorkingCapitalLoan loan;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,8 @@
package org.apache.fineract.portfolio.workingcapitalloan.repository;

import java.util.List;
import java.util.Optional;
import org.apache.fineract.portfolio.delinquency.domain.DelinquencyAction;
import org.apache.fineract.portfolio.workingcapitalloan.domain.WorkingCapitalLoanDelinquencyAction;
import org.springframework.data.jpa.repository.JpaRepository;
import org.springframework.stereotype.Repository;
Expand All @@ -28,4 +30,7 @@ public interface WorkingCapitalLoanDelinquencyActionRepository extends JpaReposi

List<WorkingCapitalLoanDelinquencyAction> findByWorkingCapitalLoanIdOrderById(Long workingCapitalLoanId);

Optional<WorkingCapitalLoanDelinquencyAction> findTopByWorkingCapitalLoanIdAndActionOrderByIdDesc(Long workingCapitalLoanId,
DelinquencyAction action);

}
Original file line number Diff line number Diff line change
Expand Up @@ -39,7 +39,8 @@ public List<WorkingCapitalLoanDelinquencyActionData> retrieveDelinquencyActions(
}

private WorkingCapitalLoanDelinquencyActionData toData(final WorkingCapitalLoanDelinquencyAction action) {
return new WorkingCapitalLoanDelinquencyActionData(action.getId(), action.getAction(), action.getStartDate(), action.getEndDate());
return new WorkingCapitalLoanDelinquencyActionData(action.getId(), action.getAction(), action.getStartDate(), action.getEndDate(),
action.getMinimumPayment(), action.getMinimumPaymentType(), action.getFrequency(), action.getFrequencyType());
}

}
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,7 @@
import org.apache.fineract.infrastructure.core.api.JsonCommand;
import org.apache.fineract.infrastructure.core.data.CommandProcessingResult;
import org.apache.fineract.infrastructure.core.data.CommandProcessingResultBuilder;
import org.apache.fineract.portfolio.delinquency.domain.DelinquencyAction;
import org.apache.fineract.portfolio.workingcapitalloan.domain.WorkingCapitalLoan;
import org.apache.fineract.portfolio.workingcapitalloan.domain.WorkingCapitalLoanDelinquencyAction;
import org.apache.fineract.portfolio.workingcapitalloan.exception.WorkingCapitalLoanNotFoundException;
Expand Down Expand Up @@ -58,7 +59,11 @@ public CommandProcessingResult createDelinquencyAction(final Long workingCapital
final WorkingCapitalLoanDelinquencyAction saved = actionRepository.saveAndFlush(action);
log.debug("Created WC loan delinquency action {} for loan {}", action.getAction(), workingCapitalLoanId);

rangeScheduleService.extendPeriodsForPause(workingCapitalLoan, action.getStartDate(), action.getEndDate());
if (DelinquencyAction.PAUSE.equals(action.getAction())) {
rangeScheduleService.extendPeriodsForPause(workingCapitalLoan, action.getStartDate(), action.getEndDate());
} else if (DelinquencyAction.RESCHEDULE.equals(action.getAction())) {
rangeScheduleService.rescheduleMinimumPayment(workingCapitalLoan, action);
}

return new CommandProcessingResultBuilder() //
.withCommandId(command.commandId()) //
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,7 @@
import java.util.List;
import org.apache.fineract.portfolio.workingcapitalloan.data.WorkingCapitalLoanDelinquencyRangeScheduleData;
import org.apache.fineract.portfolio.workingcapitalloan.domain.WorkingCapitalLoan;
import org.apache.fineract.portfolio.workingcapitalloan.domain.WorkingCapitalLoanDelinquencyAction;

public interface WorkingCapitalLoanDelinquencyRangeScheduleService {

Expand All @@ -40,4 +41,6 @@ public interface WorkingCapitalLoanDelinquencyRangeScheduleService {

void extendPeriodsForPause(WorkingCapitalLoan loan, LocalDate pauseStart, LocalDate pauseEnd);

void rescheduleMinimumPayment(WorkingCapitalLoan loan, WorkingCapitalLoanDelinquencyAction rescheduleAction);

}
Loading
Loading