remove need for undo resource - align undo of state transitions with state transitions allowing for note to be added through ui.

This commit is contained in:
Keith Woodlock
2012-05-28 17:20:29 +01:00
parent d127003d6d
commit 66d3babb06
13 changed files with 207 additions and 168 deletions
@@ -29,10 +29,10 @@ import org.mifosng.data.command.CalculateLoanScheduleCommand;
import org.mifosng.data.command.LoanStateTransitionCommand;
import org.mifosng.data.command.LoanTransactionCommand;
import org.mifosng.data.command.SubmitLoanApplicationCommand;
import org.mifosng.data.command.UndoLoanApprovalCommand;
import org.mifosng.data.command.UndoLoanDisbursalCommand;
import org.mifosng.data.command.UndoStateTransitionCommand;
import org.mifosng.platform.api.infrastructure.ApiDataConversionService;
import org.mifosng.platform.api.infrastructure.ApiJSONFormattingService;
import org.mifosng.platform.exceptions.UnrecognizedQueryParamException;
import org.mifosng.platform.loan.service.CalculationPlatformService;
import org.mifosng.platform.loan.service.LoanReadPlatformService;
import org.mifosng.platform.loan.service.LoanWritePlatformService;
@@ -70,8 +70,8 @@ public class LoansApiResource {
@GET
@Path("template")
@Consumes({ MediaType.APPLICATION_JSON, MediaType.APPLICATION_XML })
@Produces({ MediaType.APPLICATION_JSON })
@Consumes({ MediaType.APPLICATION_JSON, MediaType.APPLICATION_XML})
@Produces({ MediaType.APPLICATION_JSON})
public String retrieveDetailsForNewLoanApplicationStepOne(
@QueryParam("clientId") final Long clientId,
@QueryParam("productId") final Long productId,
@@ -88,8 +88,8 @@ public class LoansApiResource {
@GET
@Path("{loanId}")
@Consumes({ MediaType.APPLICATION_JSON, MediaType.APPLICATION_XML })
@Produces({ MediaType.APPLICATION_JSON })
@Consumes({ MediaType.APPLICATION_JSON, MediaType.APPLICATION_XML})
@Produces({ MediaType.APPLICATION_JSON})
public String retrieveLoanAccountDetails(
@PathParam("loanId") final Long loanId, @Context UriInfo uriInfo) {
@@ -103,8 +103,8 @@ public class LoansApiResource {
}
@POST
@Consumes({ MediaType.APPLICATION_JSON, MediaType.APPLICATION_XML })
@Produces({ MediaType.APPLICATION_JSON })
@Consumes({ MediaType.APPLICATION_JSON, MediaType.APPLICATION_XML})
@Produces({ MediaType.APPLICATION_JSON})
public Response calculateLoanSchedule(
@QueryParam("command") final String commandParam,
final SubmitLoanApplicationCommand command) {
@@ -170,8 +170,8 @@ public class LoansApiResource {
@DELETE
@Path("{loanId}")
@Consumes({ MediaType.APPLICATION_JSON, MediaType.APPLICATION_XML })
@Produces({ MediaType.APPLICATION_JSON })
@Consumes({ MediaType.APPLICATION_JSON, MediaType.APPLICATION_XML})
@Produces({ MediaType.APPLICATION_JSON})
public Response deleteLoanApplication(@PathParam("loanId") final Long loanId) {
EntityIdentifier identifier = this.loanWritePlatformService
@@ -182,10 +182,9 @@ public class LoansApiResource {
@POST
@Path("{loanId}")
@Consumes({ MediaType.APPLICATION_JSON, MediaType.APPLICATION_XML })
@Produces({ MediaType.APPLICATION_JSON })
public Response stateTransitions(@PathParam("loanId") final Long loanId,
@QueryParam("command") final String commandParam,
@Consumes({ MediaType.APPLICATION_JSON, MediaType.APPLICATION_XML})
@Produces({ MediaType.APPLICATION_JSON})
public Response stateTransitions(@PathParam("loanId") final Long loanId, @QueryParam("command") final String commandParam,
final LoanStateTransitionCommand command) {
LocalDate eventDate = this.apiDataConversionService.convertFrom(
@@ -194,63 +193,47 @@ public class LoansApiResource {
command.setLoanId(loanId);
command.setEventDate(eventDate);
Response response = null;
if (StringUtils.isNotBlank(commandParam)
&& commandParam.trim().equalsIgnoreCase("reject")) {
EntityIdentifier identifier = this.loanWritePlatformService
.rejectLoan(command);
return Response.ok().entity(identifier).build();
} else if (StringUtils.isNotBlank(commandParam)
&& commandParam.trim().equalsIgnoreCase("withdrewbyclient")) {
EntityIdentifier identifier = this.loanWritePlatformService
.withdrawLoan(command);
return Response.ok().entity(identifier).build();
} else if (StringUtils.isNotBlank(commandParam)
&& commandParam.trim().equalsIgnoreCase("approve")) {
EntityIdentifier identifier = this.loanWritePlatformService
.approveLoanApplication(command);
return Response.ok().entity(identifier).build();
} else if (StringUtils.isNotBlank(commandParam)
&& commandParam.trim().equalsIgnoreCase("disburse")) {
EntityIdentifier identifier = this.loanWritePlatformService
.disburseLoan(command);
return Response.ok().entity(identifier).build();
if (is(commandParam, "reject")) {
EntityIdentifier identifier = this.loanWritePlatformService.rejectLoan(command);
response = Response.ok().entity(identifier).build();
} else if (is(commandParam, "withdrewbyclient")) {
EntityIdentifier identifier = this.loanWritePlatformService.withdrawLoan(command);
response = Response.ok().entity(identifier).build();
} else if (is(commandParam, "approve")) {
EntityIdentifier identifier = this.loanWritePlatformService.approveLoanApplication(command);
response = Response.ok().entity(identifier).build();
} else if (is(commandParam, "disburse")) {
EntityIdentifier identifier = this.loanWritePlatformService.disburseLoan(command);
response = Response.ok().entity(identifier).build();
}
UndoStateTransitionCommand undoCommand = new UndoStateTransitionCommand(loanId, command.getComment());
if (is(commandParam, "undoapproval")) {
EntityIdentifier identifier = this.loanWritePlatformService.undoLoanApproval(undoCommand);
response = Response.ok().entity(identifier).build();
} else if (is(commandParam, "undodisbursal")) {
EntityIdentifier identifier = this.loanWritePlatformService.undoLoanDisbursal(undoCommand);
response = Response.ok().entity(identifier).build();
}
if (response == null) {
throw new UnrecognizedQueryParamException("command", commandParam);
}
return Response.ok().build();
return response;
}
@POST
@Path("{loanId}/undo")
@Consumes({ MediaType.APPLICATION_JSON, MediaType.APPLICATION_XML })
@Produces({ MediaType.APPLICATION_JSON })
public Response undoStateTransitions(
@PathParam("loanId") final Long loanId,
@QueryParam("command") final String commandParam) {
if (StringUtils.isNotBlank(commandParam)
&& commandParam.trim().equalsIgnoreCase("undoapproval")) {
UndoLoanApprovalCommand undoCommand = new UndoLoanApprovalCommand(
loanId);
EntityIdentifier identifier = this.loanWritePlatformService
.undoLoanApproval(undoCommand);
return Response.ok().entity(identifier).build();
} else if (StringUtils.isNotBlank(commandParam)
&& commandParam.trim().equalsIgnoreCase("undodisbursal")) {
UndoLoanDisbursalCommand undoCommand = new UndoLoanDisbursalCommand(
loanId);
EntityIdentifier identifier = this.loanWritePlatformService
.undloLoanDisbursal(undoCommand);
return Response.ok().entity(identifier).build();
}
return Response.ok().build();
private boolean is(final String commandParam, final String commandValue) {
return StringUtils.isNotBlank(commandParam) && commandParam.trim().equalsIgnoreCase(commandValue);
}
@POST
@Path("{loanId}/transactions")
@Consumes({ MediaType.APPLICATION_JSON, MediaType.APPLICATION_XML })
@Produces({ MediaType.APPLICATION_JSON })
@Consumes({ MediaType.APPLICATION_JSON, MediaType.APPLICATION_XML})
@Produces({ MediaType.APPLICATION_JSON})
public Response executeLoanTransaction(
@PathParam("loanId") final Long loanId,
@QueryParam("transactionType") final String transactionType,
@@ -282,8 +265,8 @@ public class LoansApiResource {
@GET
@Path("{loanId}/transactions/template")
@Consumes({ MediaType.APPLICATION_JSON, MediaType.APPLICATION_XML })
@Produces({ MediaType.APPLICATION_JSON })
@Consumes({ MediaType.APPLICATION_JSON, MediaType.APPLICATION_XML})
@Produces({ MediaType.APPLICATION_JSON})
public String retrieveNewRepaymentDetails(
@PathParam("loanId") final Long loanId,
@QueryParam("type") final String transactionType,
@@ -308,8 +291,8 @@ public class LoansApiResource {
@GET
@Path("{loanId}/transactions/{repaymentId}")
@Consumes({ MediaType.APPLICATION_JSON, MediaType.APPLICATION_XML })
@Produces({ MediaType.APPLICATION_JSON })
@Consumes({ MediaType.APPLICATION_JSON, MediaType.APPLICATION_XML})
@Produces({ MediaType.APPLICATION_JSON})
public String retrieveRepaymentDetails(
@PathParam("loanId") final Long loanId,
@PathParam("repaymentId") final Long repaymentId,
@@ -326,8 +309,8 @@ public class LoansApiResource {
@PUT
@Path("{loanId}/transactions/{repaymentId}")
@Consumes({ MediaType.APPLICATION_JSON, MediaType.APPLICATION_XML })
@Produces({ MediaType.APPLICATION_JSON, MediaType.APPLICATION_XML })
@Consumes({ MediaType.APPLICATION_JSON, MediaType.APPLICATION_XML})
@Produces({ MediaType.APPLICATION_JSON})
public Response adjustLoanTransaction(
@PathParam("loanId") final Long loanId,
@PathParam("repaymentId") final Long repaymentId,
@@ -29,9 +29,9 @@ public class UnrecognizedPropertyExceptionMapper implements ExceptionMapper<Unre
String parameterName = exception.getUnrecognizedPropertyName();
StringBuilder validationErrorCode = new StringBuilder("error.msg.parameter.").append(parameterName).append(".unsupported");
StringBuilder validationErrorCode = new StringBuilder("error.msg.parameter.unsupported");
StringBuilder defaultEnglishMessage = new StringBuilder("The parameter ").append(parameterName).append(" is not supported.");
ApiParameterError error = ApiParameterError.parameterError(validationErrorCode.toString(), defaultEnglishMessage.toString(), parameterName);
ApiParameterError error = ApiParameterError.parameterError(validationErrorCode.toString(), defaultEnglishMessage.toString(), parameterName, parameterName);
List<ApiParameterError> errors = new ArrayList<ApiParameterError>();
errors.add(error);
@@ -0,0 +1,47 @@
package org.mifosng.platform.api.errorhandling;
import java.util.ArrayList;
import java.util.List;
import javax.ws.rs.core.Response;
import javax.ws.rs.core.Response.Status;
import javax.ws.rs.ext.ExceptionMapper;
import javax.ws.rs.ext.Provider;
import org.codehaus.jackson.map.exc.UnrecognizedPropertyException;
import org.mifosng.data.ApiGlobalErrorResponse;
import org.mifosng.data.ApiParameterError;
import org.mifosng.platform.exceptions.UnrecognizedQueryParamException;
import org.springframework.context.annotation.Scope;
import org.springframework.stereotype.Component;
/**
* An {@link ExceptionMapper} to map {@link UnrecognizedPropertyException} thrown by platform into a HTTP API friendly format.
*
* The {@link UnrecognizedPropertyException} is typically thrown when a parameter is passed during and post or put that is not expected.
*/
@Provider
@Component
@Scope("singleton")
public class UnrecognizedQueryParamExceptionMapper implements ExceptionMapper<UnrecognizedQueryParamException> {
@Override
public Response toResponse(UnrecognizedQueryParamException exception) {
String parameterName = exception.getQueryParamKey();
String parameterValue = exception.getQueryParamValue();
StringBuilder validationErrorCode = new StringBuilder("error.msg.query.parameter.value.unsupported");
StringBuilder defaultEnglishMessage = new StringBuilder("The query parameter ").append(parameterName).append(" has an unsupported value of: ").append(parameterValue);
ApiParameterError error = ApiParameterError.parameterError(validationErrorCode.toString(), defaultEnglishMessage.toString(), parameterName, parameterName, parameterValue);
List<ApiParameterError> errors = new ArrayList<ApiParameterError>();
errors.add(error);
ApiGlobalErrorResponse invalidParameterError = ApiGlobalErrorResponse.badClientRequest(
"validation.msg.validation.errors.exist",
"Validation errors exist.", errors);
return Response.status(Status.BAD_REQUEST).entity(invalidParameterError).build();
}
}
@@ -0,0 +1,20 @@
package org.mifosng.platform.exceptions;
public class UnrecognizedQueryParamException extends RuntimeException {
private final String queryParamKey;
private final String queryParamValue;
public UnrecognizedQueryParamException(String queryParamKey, String queryParamValue) {
this.queryParamKey = queryParamKey;
this.queryParamValue = queryParamValue;
}
public String getQueryParamKey() {
return queryParamKey;
}
public String getQueryParamValue() {
return queryParamValue;
}
}
@@ -5,8 +5,7 @@ import org.mifosng.data.command.AdjustLoanTransactionCommand;
import org.mifosng.data.command.LoanStateTransitionCommand;
import org.mifosng.data.command.LoanTransactionCommand;
import org.mifosng.data.command.SubmitLoanApplicationCommand;
import org.mifosng.data.command.UndoLoanApprovalCommand;
import org.mifosng.data.command.UndoLoanDisbursalCommand;
import org.mifosng.data.command.UndoStateTransitionCommand;
import org.springframework.security.access.prepost.PreAuthorize;
public interface LoanWritePlatformService {
@@ -21,7 +20,7 @@ public interface LoanWritePlatformService {
EntityIdentifier approveLoanApplication(LoanStateTransitionCommand command);
@PreAuthorize(value = "hasAnyRole('PORTFOLIO_MANAGEMENT_SUPER_USER_ROLE', 'CAN_UNDO_LOAN_APPROVAL_ROLE')")
EntityIdentifier undoLoanApproval(UndoLoanApprovalCommand command);
EntityIdentifier undoLoanApproval(UndoStateTransitionCommand command);
@PreAuthorize(value = "hasAnyRole('PORTFOLIO_MANAGEMENT_SUPER_USER_ROLE', 'CAN_REJECT_LOAN_ROLE', 'CAN_REJECT_LOAN_IN_THE_PAST_ROLE')")
EntityIdentifier rejectLoan(LoanStateTransitionCommand command);
@@ -33,7 +32,7 @@ public interface LoanWritePlatformService {
EntityIdentifier disburseLoan(LoanStateTransitionCommand command);
@PreAuthorize(value = "hasAnyRole('PORTFOLIO_MANAGEMENT_SUPER_USER_ROLE', 'CAN_UNDO_LOAN_DISBURSAL_ROLE')")
public EntityIdentifier undloLoanDisbursal(UndoLoanDisbursalCommand command);
public EntityIdentifier undoLoanDisbursal(UndoStateTransitionCommand command);
@PreAuthorize(value = "hasAnyRole('PORTFOLIO_MANAGEMENT_SUPER_USER_ROLE', 'CAN_MAKE_LOAN_REPAYMENT_ROLE', 'CAN_MAKE_LOAN_REPAYMENT_IN_THE_PAST_ROLE')")
public EntityIdentifier makeLoanRepayment(LoanTransactionCommand command);
@@ -17,8 +17,7 @@ import org.mifosng.data.command.CalculateLoanScheduleCommand;
import org.mifosng.data.command.LoanStateTransitionCommand;
import org.mifosng.data.command.LoanTransactionCommand;
import org.mifosng.data.command.SubmitLoanApplicationCommand;
import org.mifosng.data.command.UndoLoanApprovalCommand;
import org.mifosng.data.command.UndoLoanDisbursalCommand;
import org.mifosng.data.command.UndoStateTransitionCommand;
import org.mifosng.platform.client.domain.Client;
import org.mifosng.platform.client.domain.ClientRepository;
import org.mifosng.platform.client.domain.Note;
@@ -213,7 +212,7 @@ public class LoanWritePlatformServiceJpaRepositoryImpl implements LoanWritePlatf
@Transactional
@Override
public EntityIdentifier undoLoanApproval(final UndoLoanApprovalCommand command) {
public EntityIdentifier undoLoanApproval(final UndoStateTransitionCommand command) {
AppUser currentUser = context.authenticatedUser();
@@ -225,8 +224,10 @@ public class LoanWritePlatformServiceJpaRepositoryImpl implements LoanWritePlatf
loan.undoApproval(defaultLoanLifecycleStateMachine());
this.loanRepository.save(loan);
Note note = Note.loanNote(currentUser.getOrganisation(), loan, "Undo of approval.");
this.noteRepository.save(note);
if (StringUtils.isNotBlank(command.getComment())) {
Note note = Note.loanNote(currentUser.getOrganisation(), loan, command.getComment());
this.noteRepository.save(note);
}
return new EntityIdentifier(loan.getClient().getId());
}
@@ -381,7 +382,7 @@ public class LoanWritePlatformServiceJpaRepositoryImpl implements LoanWritePlatf
@Transactional
@Override
public EntityIdentifier undloLoanDisbursal(final UndoLoanDisbursalCommand command) {
public EntityIdentifier undoLoanDisbursal(final UndoStateTransitionCommand command) {
AppUser currentUser = context.authenticatedUser();
@@ -398,9 +399,10 @@ public class LoanWritePlatformServiceJpaRepositoryImpl implements LoanWritePlatf
this.loanRepository.save(loan);
// TODO - this may not be wanted.
Note note = Note.loanNote(currentUser.getOrganisation(), loan, "Undo of disbursal.");
this.noteRepository.save(note);
if (StringUtils.isNotBlank(command.getComment())) {
Note note = Note.loanNote(currentUser.getOrganisation(), loan, command.getComment());
this.noteRepository.save(note);
}
return new EntityIdentifier(loan.getClient().getId());
}