Skip to content

Commit

Permalink
FINERACT-2152: API update and delete interest pause
Browse files Browse the repository at this point in the history
  • Loading branch information
kulminsky authored and adamsaghy committed Jan 8, 2025
1 parent d2afd1a commit 8663c05
Show file tree
Hide file tree
Showing 18 changed files with 675 additions and 131 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -159,8 +159,7 @@ public static CommandSource fullEntryFrom(final CommandWrapper wrapper, final Js
.transactionId(command.getTransactionId()) //
.creditBureauId(command.getCreditBureauId()) //
.organisationCreditBureauId(command.getOrganisationCreditBureauId()) //
.loanExternalId(command.getLoanExternalId()) //
.build(); //
.loanExternalId(command.getLoanExternalId()).build(); //
}

public String getPermissionCode() {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -251,8 +251,16 @@ public boolean isInterestPauseResource() {
return this.entityName.equalsIgnoreCase("INTEREST_PAUSE");
}

public boolean isInterestPauseExternalIdResource() {
return this.entityName.equalsIgnoreCase("INTEREST_PAUSE") && this.href.contains("/external-id/");
public boolean isInterestPauseCreateResource() {
return this.entityName.equalsIgnoreCase("INTEREST_PAUSE") && "CREATE".equalsIgnoreCase(this.actionName);
}

public boolean isInterestPauseUpdateResource() {
return this.entityName.equalsIgnoreCase("INTEREST_PAUSE") && "UPDATE".equalsIgnoreCase(this.actionName);
}

public boolean isInterestPauseDeleteResource() {
return this.entityName.equalsIgnoreCase("INTEREST_PAUSE") && "DELETE".equalsIgnoreCase(this.actionName);
}

public Long commandId() {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -3732,4 +3732,22 @@ public CommandWrapperBuilder createInterestPauseByExternalId(final String loanEx
this.href = "/v1/loans/external-id/" + loanExternalId + "/interest-pauses";
return this;
}

public CommandWrapperBuilder deleteInterestPause(final long loanId, final long variationId) {
this.actionName = "DELETE";
this.entityName = "INTEREST_PAUSE";
this.loanId = loanId;
this.entityId = variationId;
this.href = "/v1/loans/" + loanId + "/interest-pauses/" + variationId;
return this;
}

public CommandWrapperBuilder updateInterestPause(final long loanId, final long variationId) {
this.actionName = "UPDATE";
this.entityName = "INTEREST_PAUSE";
this.loanId = loanId;
this.entityId = variationId;
this.href = "/v1/loans/" + loanId + "/interest-pauses/" + variationId;
return this;
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -249,8 +249,16 @@ private NewCommandSourceHandler findCommandHandler(final CommandWrapper wrapper)
} else {
throw new UnsupportedCommandException(wrapper.commandName());
}
} else if (wrapper.isInterestPauseResource() || wrapper.isInterestPauseExternalIdResource()) {
handler = applicationContext.getBean("interestPauseCommandHandler", NewCommandSourceHandler.class);
} else if (wrapper.isInterestPauseResource()) {
if (wrapper.isInterestPauseCreateResource()) {
handler = applicationContext.getBean("createInterestPauseCommandHandler", NewCommandSourceHandler.class);
} else if (wrapper.isInterestPauseUpdateResource()) {
handler = applicationContext.getBean("updateInterestPauseCommandHandler", NewCommandSourceHandler.class);
} else if (wrapper.isInterestPauseDeleteResource()) {
handler = applicationContext.getBean("deleteInterestPauseCommandHandler", NewCommandSourceHandler.class);
} else {
throw new UnsupportedCommandException(wrapper.commandName());
}
} else {
handler = commandHandlerProvider.getHandler(wrapper.entityName(), wrapper.actionName());
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -25,12 +25,15 @@
import io.swagger.v3.oas.annotations.responses.ApiResponses;
import io.swagger.v3.oas.annotations.tags.Tag;
import jakarta.ws.rs.Consumes;
import jakarta.ws.rs.DELETE;
import jakarta.ws.rs.GET;
import jakarta.ws.rs.POST;
import jakarta.ws.rs.PUT;
import jakarta.ws.rs.Path;
import jakarta.ws.rs.PathParam;
import jakarta.ws.rs.Produces;
import jakarta.ws.rs.core.MediaType;
import jakarta.ws.rs.core.Response;
import java.util.List;
import lombok.RequiredArgsConstructor;
import org.apache.fineract.commands.domain.CommandWrapper;
Expand All @@ -50,6 +53,7 @@
public class LoanInterestPauseApiResource {

private static final String RESOURCE_NAME_FOR_PERMISSIONS = "LOAN";
private static final String MODIFY_RESOURCE_NAME_FOR_PERMISSIONS = "UPDATE LOAN";

private final PlatformSecurityContext context;
private final PortfolioCommandSourceWritePlatformService commandsSourceWritePlatformService;
Expand All @@ -64,7 +68,7 @@ public class LoanInterestPauseApiResource {
public CommandProcessingResult createInterestPause(@PathParam("loanId") @Parameter(description = "loanId") final Long loanId,
@RequestBody(required = true) final InterestPauseRequestDto request) {

this.context.authenticatedUser().validateHasReadPermission(RESOURCE_NAME_FOR_PERMISSIONS);
this.context.authenticatedUser().validateHasReadPermission(MODIFY_RESOURCE_NAME_FOR_PERMISSIONS);

final CommandWrapper commandRequest = new CommandWrapperBuilder().createInterestPause(loanId).withJson(request.toJson()).build();

Expand All @@ -81,7 +85,7 @@ public CommandProcessingResult createInterestPauseByExternalId(
@PathParam("loanExternalId") @Parameter(description = "loanExternalId") final String loanExternalId,
@RequestBody(required = true) final InterestPauseRequestDto request) {

this.context.authenticatedUser().validateHasReadPermission(RESOURCE_NAME_FOR_PERMISSIONS);
this.context.authenticatedUser().validateHasReadPermission(MODIFY_RESOURCE_NAME_FOR_PERMISSIONS);

final CommandWrapper commandRequest = new CommandWrapperBuilder().createInterestPauseByExternalId(loanExternalId)
.withJson(request.toJson()).build();
Expand Down Expand Up @@ -114,4 +118,38 @@ public List<InterestPauseResponseDto> retrieveInterestPausesByExternalId(

return this.interestPauseReadPlatformService.retrieveInterestPauses(loanExternalId);
}

@DELETE
@Path("/{loanId}/interest-pauses/{variationId}")
@Operation(summary = "Delete an interest pause period", description = "Deletes a specific interest pause period by its variation ID.")
@ApiResponses({ @ApiResponse(responseCode = "204", description = "No Content") })
public Response deleteInterestPause(@PathParam("loanId") @Parameter(description = "loanId") final Long loanId,
@PathParam("variationId") @Parameter(description = "variationId") final Long variationId) {

this.context.authenticatedUser().validateHasReadPermission(MODIFY_RESOURCE_NAME_FOR_PERMISSIONS);

final CommandWrapper commandRequest = new CommandWrapperBuilder().deleteInterestPause(loanId, variationId).build();

this.commandsSourceWritePlatformService.logCommandSource(commandRequest);

return Response.noContent().build();
}

@PUT
@Path("/{loanId}/interest-pauses/{variationId}")
@Consumes({ MediaType.APPLICATION_JSON })
@Produces({ MediaType.APPLICATION_JSON })
@Operation(summary = "Update an interest pause period", description = "Updates a specific interest pause period by its variation ID.")
@ApiResponses({ @ApiResponse(responseCode = "200", description = "OK") })
public CommandProcessingResult updateInterestPause(@PathParam("loanId") @Parameter(description = "loanId") final Long loanId,
@PathParam("variationId") @Parameter(description = "variationId") final Long variationId,
@RequestBody(required = true) final InterestPauseRequestDto request) {

this.context.authenticatedUser().validateHasReadPermission(MODIFY_RESOURCE_NAME_FOR_PERMISSIONS);

final CommandWrapper commandRequest = new CommandWrapperBuilder().updateInterestPause(loanId, variationId)
.withJson(request.toJson()).build();

return this.commandsSourceWritePlatformService.logCommandSource(commandRequest);
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -27,32 +27,28 @@
import org.apache.fineract.portfolio.interestpauses.service.InterestPauseWritePlatformService;
import org.springframework.stereotype.Component;

@Component("interestPauseCommandHandler")
@Component("createInterestPauseCommandHandler")
@RequiredArgsConstructor
public class InterestPauseCommandHandler implements NewCommandSourceHandler {
public class CreateInterestPauseCommandHandler implements NewCommandSourceHandler {

private final InterestPauseWritePlatformService interestPauseService;

@Override
public CommandProcessingResult processCommand(final JsonCommand command) {
CommandProcessingResult result;

final String startDate = command.stringValueOfParameterNamed("startDate");
final String endDate = command.stringValueOfParameterNamed("endDate");
final String dateFormat = command.stringValueOfParameterNamed("dateFormat");
final String locale = command.stringValueOfParameterNamed("locale");

if (command.getLoanId() != null) {
final Long loanId = command.getLoanId();
result = interestPauseService.createInterestPause(loanId, startDate, endDate, dateFormat, locale);
return interestPauseService.createInterestPause(loanId, startDate, endDate, dateFormat, locale);
} else if (command.getLoanExternalId() != null) {
final ExternalId loanExternalId = command.getLoanExternalId();
result = interestPauseService.createInterestPause(loanExternalId, startDate, endDate, dateFormat, locale);
return interestPauseService.createInterestPause(loanExternalId, startDate, endDate, dateFormat, locale);
} else {
throw new PlatformApiDataValidationException("validation.msg.missing.loan.id.or.external.id",
"Either loanId or loanExternalId must be provided.", "loanId");
}

return result;
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,41 @@
/**
* 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.portfolio.interestpauses.handler;

import lombok.RequiredArgsConstructor;
import org.apache.fineract.commands.handler.NewCommandSourceHandler;
import org.apache.fineract.infrastructure.core.api.JsonCommand;
import org.apache.fineract.infrastructure.core.data.CommandProcessingResult;
import org.apache.fineract.portfolio.interestpauses.service.InterestPauseWritePlatformService;
import org.springframework.stereotype.Component;

@Component("deleteInterestPauseCommandHandler")
@RequiredArgsConstructor
public class DeleteInterestPauseCommandHandler implements NewCommandSourceHandler {

private final InterestPauseWritePlatformService interestPauseService;

@Override
public CommandProcessingResult processCommand(final JsonCommand command) {
final Long loanId = command.getLoanId();
final Long termVariationId = command.getResourceId();

return interestPauseService.deleteInterestPause(loanId, termVariationId);
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,45 @@
/**
* 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.portfolio.interestpauses.handler;

import lombok.RequiredArgsConstructor;
import org.apache.fineract.commands.handler.NewCommandSourceHandler;
import org.apache.fineract.infrastructure.core.api.JsonCommand;
import org.apache.fineract.infrastructure.core.data.CommandProcessingResult;
import org.apache.fineract.portfolio.interestpauses.service.InterestPauseWritePlatformService;
import org.springframework.stereotype.Component;

@Component("updateInterestPauseCommandHandler")
@RequiredArgsConstructor
public class UpdateInterestPauseCommandHandler implements NewCommandSourceHandler {

private final InterestPauseWritePlatformService interestPauseService;

@Override
public CommandProcessingResult processCommand(final JsonCommand command) {
final Long loanId = command.getLoanId();
final Long termVariationId = command.getResourceId();
final String startDate = command.stringValueOfParameterNamed("startDate");
final String endDate = command.stringValueOfParameterNamed("endDate");
final String dateFormat = command.stringValueOfParameterNamed("dateFormat");
final String locale = command.stringValueOfParameterNamed("locale");

return interestPauseService.updateInterestPause(loanId, termVariationId, startDate, endDate, dateFormat, locale);
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,21 @@

public interface InterestPauseWritePlatformService {

/**
* Create a new interest pause period for a loan identified by its external ID.
*
* @param loanExternalId
* the external ID of the loan
* @param startDate
* the start date of the interest pause period (inclusive)
* @param endDate
* the end date of the interest pause period (inclusive)
* @param dateFormat
* the format of the provided dates
* @param locale
* the locale used for date parsing
* @return the ID of the created loan term variation representing the interest pause
*/
CommandProcessingResult createInterestPause(ExternalId loanExternalId, String startDate, String endDate, String dateFormat,
String locale);

Expand All @@ -35,7 +50,42 @@ CommandProcessingResult createInterestPause(ExternalId loanExternalId, String st
* the start date of the interest pause period (inclusive)
* @param endDate
* the end date of the interest pause period (inclusive)
* @param dateFormat
* the format of the provided dates
* @param locale
* the locale used for date parsing
* @return the ID of the created loan term variation representing the interest pause
*/
CommandProcessingResult createInterestPause(Long loanId, String startDate, String endDate, String dateFormat, String locale);

/**
* Delete an existing interest pause period for a loan.
*
* @param loanId
* the ID of the loan
* @param variationId
* the ID of the loan term variation representing the interest pause
* @return the result of the delete operation
*/
CommandProcessingResult deleteInterestPause(Long loanId, Long variationId);

/**
* Update an existing interest pause period for a loan identified by its internal ID.
*
* @param loanId
* the ID of the loan
* @param variationId
* the ID of the loan term variation representing the interest pause to be updated
* @param startDateString
* the new start date of the interest pause period (inclusive) as a string
* @param endDateString
* the new end date of the interest pause period (inclusive) as a string
* @param dateFormat
* the format of the provided dates (e.g., "yyyy-MM-dd")
* @param locale
* the locale used for parsing the provided dates
* @return the updated loan term variation ID along with the updated fields
*/
CommandProcessingResult updateInterestPause(Long loanId, Long variationId, String startDateString, String endDateString,
String dateFormat, String locale);
}
Loading

0 comments on commit 8663c05

Please sign in to comment.