Skip to content
Open
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 @@ -757,9 +757,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 @@ -839,6 +848,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,18 @@ 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 percentage (required for reschedule)")
public BigDecimal minimumPayment;
@Schema(example = "30", description = "Frequency value (required for reschedule)")
public Integer frequency;
@Schema(example = "DAYS", description = "Frequency type: DAYS, WEEKS, MONTHS, YEARS (required for reschedule)")
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,13 @@
*/
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;

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

}
Original file line number Diff line number Diff line change
Expand Up @@ -26,12 +26,14 @@
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;

@Getter
@Setter
Expand All @@ -51,7 +53,17 @@ 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;

@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 @@ -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.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