minor changes to client images and updates to documentation
This commit is contained in:
+55
-14
@@ -14,6 +14,7 @@ import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
import java.util.Random;
|
||||
|
||||
import org.apache.commons.lang.StringUtils;
|
||||
import org.mifosplatform.infrastructure.core.data.ApiParameterError;
|
||||
import org.mifosplatform.infrastructure.core.domain.Base64EncodedImage;
|
||||
import org.mifosplatform.infrastructure.core.exception.ImageDataURLNotValidException;
|
||||
@@ -31,6 +32,49 @@ public class FileUtils {
|
||||
|
||||
public static final String MIFOSX_BASE_DIR = System.getProperty("user.home") + File.separator + ".mifosx";
|
||||
|
||||
public static enum IMAGE_MIME_TYPE {
|
||||
GIF("image/gif"), JPEG("image/jpeg"), PNG("image/png");
|
||||
|
||||
private final String value;
|
||||
|
||||
private IMAGE_MIME_TYPE(final String value) {
|
||||
this.value = value;
|
||||
}
|
||||
|
||||
public String getValue() {
|
||||
return this.value;
|
||||
}
|
||||
};
|
||||
|
||||
public static enum IMAGE_FILE_EXTENSION {
|
||||
GIF(".gif"), JPEG(".jpeg"), JPG(".jpg"), PNG(".png");
|
||||
|
||||
private final String value;
|
||||
|
||||
private IMAGE_FILE_EXTENSION(final String value) {
|
||||
this.value = value;
|
||||
}
|
||||
|
||||
public String getValue() {
|
||||
return this.value;
|
||||
}
|
||||
};
|
||||
|
||||
public static enum IMAGE_DATA_URI_SUFFIX {
|
||||
GIF("data:" + IMAGE_MIME_TYPE.GIF.getValue() + ";base64,"), JPEG("data:" + IMAGE_MIME_TYPE.JPEG.getValue() + ";base64,"), PNG(
|
||||
"data:" + IMAGE_MIME_TYPE.PNG.getValue() + ";base64,");
|
||||
|
||||
private final String value;
|
||||
|
||||
private IMAGE_DATA_URI_SUFFIX(final String value) {
|
||||
this.value = value;
|
||||
}
|
||||
|
||||
public String getValue() {
|
||||
return this.value;
|
||||
}
|
||||
};
|
||||
|
||||
public static Random random = new Random();
|
||||
|
||||
/**
|
||||
@@ -138,7 +182,8 @@ public class FileUtils {
|
||||
* @param mimeType
|
||||
*/
|
||||
public static void validateImageMimeType(String mimeType) {
|
||||
if (!(mimeType.equalsIgnoreCase("image/gif") || mimeType.equalsIgnoreCase("image/jpeg") || mimeType.equalsIgnoreCase("image/png"))) { throw new ImageUploadException(); }
|
||||
if (!(mimeType.equalsIgnoreCase(IMAGE_MIME_TYPE.GIF.getValue()) || mimeType.equalsIgnoreCase(IMAGE_MIME_TYPE.JPEG.getValue()) || mimeType
|
||||
.equalsIgnoreCase(IMAGE_MIME_TYPE.PNG.getValue()))) { throw new ImageUploadException(); }
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -149,19 +194,15 @@ public class FileUtils {
|
||||
public static Base64EncodedImage extractImageFromDataURL(String dataURL) {
|
||||
String fileExtension = "";
|
||||
String base64EncodedString = null;
|
||||
String gifDataURLSnippet = "data:image/gif;base64,";
|
||||
String pngDataURLSnippet = "data:image/png;base64,";
|
||||
String jpegDataURLSnippet = "data:image/jpeg;base64,";
|
||||
|
||||
if (dataURL.contains(gifDataURLSnippet)) {
|
||||
base64EncodedString = dataURL.replaceAll(gifDataURLSnippet, "");
|
||||
fileExtension = ".gif";
|
||||
} else if (dataURL.contains(pngDataURLSnippet)) {
|
||||
base64EncodedString = dataURL.replaceAll(pngDataURLSnippet, "");
|
||||
fileExtension = ".png";
|
||||
} else if (dataURL.contains(jpegDataURLSnippet)) {
|
||||
base64EncodedString = dataURL.replaceAll(jpegDataURLSnippet, "");
|
||||
fileExtension = ".jpeg";
|
||||
if (StringUtils.startsWith(dataURL, IMAGE_DATA_URI_SUFFIX.GIF.getValue())) {
|
||||
base64EncodedString = dataURL.replaceAll(IMAGE_DATA_URI_SUFFIX.GIF.getValue(), "");
|
||||
fileExtension = IMAGE_FILE_EXTENSION.GIF.getValue();
|
||||
} else if (StringUtils.startsWith(dataURL, IMAGE_DATA_URI_SUFFIX.PNG.getValue())) {
|
||||
base64EncodedString = dataURL.replaceAll(IMAGE_DATA_URI_SUFFIX.PNG.getValue(), "");
|
||||
fileExtension = IMAGE_FILE_EXTENSION.PNG.getValue();
|
||||
} else if (StringUtils.startsWith(dataURL, IMAGE_DATA_URI_SUFFIX.JPEG.getValue())) {
|
||||
base64EncodedString = dataURL.replaceAll(IMAGE_DATA_URI_SUFFIX.JPEG.getValue(), "");
|
||||
fileExtension = IMAGE_FILE_EXTENSION.JPEG.getValue();
|
||||
} else {
|
||||
throw new ImageDataURLNotValidException();
|
||||
}
|
||||
|
||||
+3
-3
@@ -11,14 +11,14 @@ public class LoanChargeCannotBeDeletedException extends AbstractPlatformDomainRu
|
||||
|
||||
/*** enum of reasons of why Loan Charge cannot be waived **/
|
||||
public static enum LOAN_CHARGE_CANNOT_BE_DELETED_REASON {
|
||||
ALREADY_PAID, ALREADY_WAIVED, LOAN_APPROVED;
|
||||
ALREADY_PAID, ALREADY_WAIVED, LOAN_NOT_IN_SUBMITTED_AND_PENDING_APPROVAL_STAGE;
|
||||
|
||||
public String errorMessage() {
|
||||
if (name().toString().equalsIgnoreCase("ALREADY_PAID")) {
|
||||
return "This loan charge has been partially/completely paid";
|
||||
} else if (name().toString().equalsIgnoreCase("ALREADY_WAIVED")) {
|
||||
return "This loan charge has already been waived";
|
||||
} else if (name().toString().equalsIgnoreCase("LOAN_APPROVED")) { return "This charge cannot be deleted as the loan it is associated with has already been approved"; }
|
||||
} else if (name().toString().equalsIgnoreCase("LOAN_NOT_IN_SUBMITTED_AND_PENDING_APPROVAL_STAGE")) { return "This charge cannot be deleted as the loan it is associated with is not in submitted and pending approval stage"; }
|
||||
return name().toString();
|
||||
}
|
||||
|
||||
@@ -27,7 +27,7 @@ public class LoanChargeCannotBeDeletedException extends AbstractPlatformDomainRu
|
||||
return "error.msg.loan.charge.already.paid";
|
||||
} else if (name().toString().equalsIgnoreCase("ALREADY_WAIVED")) {
|
||||
return "error.msg.loan.charge.already.waived";
|
||||
} else if (name().toString().equalsIgnoreCase("LOAN_APPROVED")) { return "error.msg.loan.charge.associated.loan.already.approved"; }
|
||||
} else if (name().toString().equalsIgnoreCase("LOAN_NOT_IN_SUBMITTED_AND_PENDING_APPROVAL_STAGE")) { return "error.msg.loan.charge.associated.loan.not.in.submitted.and.pending.approval.stage"; }
|
||||
return name().toString();
|
||||
}
|
||||
}
|
||||
|
||||
+38
@@ -0,0 +1,38 @@
|
||||
/**
|
||||
* This Source Code Form is subject to the terms of the Mozilla Public
|
||||
* License, v. 2.0. If a copy of the MPL was not distributed with this file,
|
||||
* You can obtain one at http://mozilla.org/MPL/2.0/.
|
||||
*/
|
||||
package org.mifosplatform.portfolio.charge.exception;
|
||||
|
||||
import org.mifosplatform.infrastructure.core.exception.AbstractPlatformDomainRuleException;
|
||||
|
||||
public class LoanChargeCannotBeUpdatedException extends AbstractPlatformDomainRuleException {
|
||||
|
||||
/*** enum of reasons of why Loan Charge cannot be waived **/
|
||||
public static enum LOAN_CHARGE_CANNOT_BE_UPDATED_REASON {
|
||||
ALREADY_PAID, ALREADY_WAIVED, LOAN_NOT_IN_SUBMITTED_AND_PENDING_APPROVAL_STAGE;
|
||||
|
||||
public String errorMessage() {
|
||||
if (name().toString().equalsIgnoreCase("ALREADY_PAID")) {
|
||||
return "This loan charge has been partially/completely paid";
|
||||
} else if (name().toString().equalsIgnoreCase("ALREADY_WAIVED")) {
|
||||
return "This loan charge has already been waived";
|
||||
} else if (name().toString().equalsIgnoreCase("LOAN_NOT_IN_SUBMITTED_AND_PENDING_APPROVAL_STAGE")) { return "This charge cannot be updated as the loan it is associated with is not in submitted and pending approval stage"; }
|
||||
return name().toString();
|
||||
}
|
||||
|
||||
public String errorCode() {
|
||||
if (name().toString().equalsIgnoreCase("ALREADY_PAID")) {
|
||||
return "error.msg.loan.charge.already.paid";
|
||||
} else if (name().toString().equalsIgnoreCase("ALREADY_WAIVED")) {
|
||||
return "error.msg.loan.charge.already.waived";
|
||||
} else if (name().toString().equalsIgnoreCase("LOAN_NOT_IN_SUBMITTED_AND_PENDING_APPROVAL_STAGE")) { return "error.msg.loan.charge.associated.loan.not.in.submitted.and.pending.approval.stage"; }
|
||||
return name().toString();
|
||||
}
|
||||
}
|
||||
|
||||
public LoanChargeCannotBeUpdatedException(final LOAN_CHARGE_CANNOT_BE_UPDATED_REASON reason, final Long loanChargeId) {
|
||||
super(reason.errorCode(), reason.errorMessage(), loanChargeId);
|
||||
}
|
||||
}
|
||||
+130
-105
@@ -5,6 +5,7 @@
|
||||
*/
|
||||
package org.mifosplatform.portfolio.client.api;
|
||||
|
||||
import java.io.File;
|
||||
import java.io.InputStream;
|
||||
|
||||
import javax.ws.rs.Consumes;
|
||||
@@ -17,12 +18,18 @@ import javax.ws.rs.Path;
|
||||
import javax.ws.rs.PathParam;
|
||||
import javax.ws.rs.Produces;
|
||||
import javax.ws.rs.core.MediaType;
|
||||
import javax.ws.rs.core.Response;
|
||||
import javax.ws.rs.core.Response.ResponseBuilder;
|
||||
|
||||
import org.apache.commons.lang.StringUtils;
|
||||
import org.mifosplatform.infrastructure.core.api.ApiConstants;
|
||||
import org.mifosplatform.infrastructure.core.data.CommandProcessingResult;
|
||||
import org.mifosplatform.infrastructure.core.domain.Base64EncodedImage;
|
||||
import org.mifosplatform.infrastructure.core.serialization.DefaultToApiJsonSerializer;
|
||||
import org.mifosplatform.infrastructure.core.service.FileUtils;
|
||||
import org.mifosplatform.infrastructure.core.service.FileUtils.IMAGE_DATA_URI_SUFFIX;
|
||||
import org.mifosplatform.infrastructure.core.service.FileUtils.IMAGE_FILE_EXTENSION;
|
||||
import org.mifosplatform.infrastructure.core.service.FileUtils.IMAGE_MIME_TYPE;
|
||||
import org.mifosplatform.infrastructure.security.service.PlatformSecurityContext;
|
||||
import org.mifosplatform.portfolio.client.data.ClientData;
|
||||
import org.mifosplatform.portfolio.client.exception.ImageNotFoundException;
|
||||
@@ -42,128 +49,146 @@ import com.sun.jersey.multipart.FormDataParam;
|
||||
@Scope("singleton")
|
||||
public class ClientImagesApiResource {
|
||||
|
||||
private final PlatformSecurityContext context;
|
||||
private final ClientReadPlatformService clientReadPlatformService;
|
||||
private final ClientWritePlatformService clientWritePlatformService;
|
||||
private final DefaultToApiJsonSerializer<ClientData> toApiJsonSerializer;
|
||||
private final PlatformSecurityContext context;
|
||||
private final ClientReadPlatformService clientReadPlatformService;
|
||||
private final ClientWritePlatformService clientWritePlatformService;
|
||||
private final DefaultToApiJsonSerializer<ClientData> toApiJsonSerializer;
|
||||
|
||||
@Autowired
|
||||
public ClientImagesApiResource(final PlatformSecurityContext context,
|
||||
final ClientReadPlatformService readPlatformService,
|
||||
final ClientWritePlatformService clientWritePlatformService,
|
||||
final DefaultToApiJsonSerializer<ClientData> toApiJsonSerializer) {
|
||||
this.context = context;
|
||||
this.clientReadPlatformService = readPlatformService;
|
||||
this.clientWritePlatformService = clientWritePlatformService;
|
||||
this.toApiJsonSerializer = toApiJsonSerializer;
|
||||
}
|
||||
@Autowired
|
||||
public ClientImagesApiResource(final PlatformSecurityContext context, final ClientReadPlatformService readPlatformService,
|
||||
final ClientWritePlatformService clientWritePlatformService, final DefaultToApiJsonSerializer<ClientData> toApiJsonSerializer) {
|
||||
this.context = context;
|
||||
this.clientReadPlatformService = readPlatformService;
|
||||
this.clientWritePlatformService = clientWritePlatformService;
|
||||
this.toApiJsonSerializer = toApiJsonSerializer;
|
||||
}
|
||||
|
||||
/**
|
||||
* Upload images through multi-part form upload
|
||||
*/
|
||||
@POST
|
||||
@Consumes({ MediaType.MULTIPART_FORM_DATA })
|
||||
@Produces({ MediaType.APPLICATION_JSON })
|
||||
public String addNewClientImage(
|
||||
@PathParam("clientId") final Long clientId,
|
||||
@HeaderParam("Content-Length") final Long fileSize,
|
||||
@FormDataParam("file") final InputStream inputStream,
|
||||
@FormDataParam("file") final FormDataContentDisposition fileDetails,
|
||||
@FormDataParam("file") final FormDataBodyPart bodyPart) {
|
||||
/**
|
||||
* Upload images through multi-part form upload
|
||||
*/
|
||||
@POST
|
||||
@Consumes({ MediaType.MULTIPART_FORM_DATA })
|
||||
@Produces({ MediaType.APPLICATION_JSON })
|
||||
public String addNewClientImage(@PathParam("clientId") final Long clientId, @HeaderParam("Content-Length") final Long fileSize,
|
||||
@FormDataParam("file") final InputStream inputStream, @FormDataParam("file") final FormDataContentDisposition fileDetails,
|
||||
@FormDataParam("file") final FormDataBodyPart bodyPart) {
|
||||
|
||||
// TODO: vishwas might need more advances validation (like reading magic
|
||||
// number) for handling malicious clients
|
||||
// and clients not setting mime type
|
||||
FileUtils.validateClientImageNotEmpty(fileDetails.getFileName());
|
||||
FileUtils.validateImageMimeType(bodyPart.getMediaType().toString());
|
||||
FileUtils.validateFileSizeWithinPermissibleRange(fileSize,
|
||||
fileDetails.getFileName(),
|
||||
ApiConstants.MAX_FILE_UPLOAD_SIZE_IN_MB);
|
||||
// TODO: vishwas might need more advances validation (like reading magic
|
||||
// number) for handling malicious clients
|
||||
// and clients not setting mime type
|
||||
FileUtils.validateClientImageNotEmpty(fileDetails.getFileName());
|
||||
FileUtils.validateImageMimeType(bodyPart.getMediaType().toString());
|
||||
FileUtils.validateFileSizeWithinPermissibleRange(fileSize, fileDetails.getFileName(), ApiConstants.MAX_FILE_UPLOAD_SIZE_IN_MB);
|
||||
|
||||
final CommandProcessingResult result = this.clientWritePlatformService
|
||||
.saveOrUpdateClientImage(clientId, fileDetails.getFileName(),
|
||||
inputStream);
|
||||
final CommandProcessingResult result = this.clientWritePlatformService.saveOrUpdateClientImage(clientId, fileDetails.getFileName(),
|
||||
inputStream);
|
||||
|
||||
return this.toApiJsonSerializer.serialize(result);
|
||||
}
|
||||
return this.toApiJsonSerializer.serialize(result);
|
||||
}
|
||||
|
||||
/**
|
||||
* Upload image as a Data URL (essentially a base64 encoded stream)
|
||||
*/
|
||||
@POST
|
||||
@Consumes({ MediaType.APPLICATION_JSON })
|
||||
@Produces({ MediaType.APPLICATION_JSON })
|
||||
public String addNewClientImage(@PathParam("clientId") final Long clientId,
|
||||
final String jsonRequestBody) {
|
||||
/**
|
||||
* Upload image as a Data URL (essentially a base64 encoded stream)
|
||||
*/
|
||||
@POST
|
||||
@Consumes({ MediaType.TEXT_PLAIN, MediaType.TEXT_HTML, MediaType.APPLICATION_JSON })
|
||||
@Produces({ MediaType.APPLICATION_JSON })
|
||||
public String addNewClientImage(@PathParam("clientId") final Long clientId, final String jsonRequestBody) {
|
||||
|
||||
final Base64EncodedImage base64EncodedImage = FileUtils
|
||||
.extractImageFromDataURL(jsonRequestBody);
|
||||
final Base64EncodedImage base64EncodedImage = FileUtils.extractImageFromDataURL(jsonRequestBody);
|
||||
|
||||
final CommandProcessingResult result = this.clientWritePlatformService
|
||||
.saveOrUpdateClientImage(clientId, base64EncodedImage);
|
||||
final CommandProcessingResult result = this.clientWritePlatformService.saveOrUpdateClientImage(clientId, base64EncodedImage);
|
||||
|
||||
return this.toApiJsonSerializer.serialize(result);
|
||||
}
|
||||
return this.toApiJsonSerializer.serialize(result);
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns a base 64 encoded client image
|
||||
*/
|
||||
@GET
|
||||
@Consumes({ MediaType.APPLICATION_JSON })
|
||||
@Produces({ MediaType.APPLICATION_JSON })
|
||||
public String retrieveClientImage(@PathParam("clientId") final Long clientId) {
|
||||
/**
|
||||
* Returns a base 64 encoded client image Data URI
|
||||
*/
|
||||
@GET
|
||||
@Consumes({ MediaType.TEXT_PLAIN, MediaType.TEXT_HTML, MediaType.APPLICATION_JSON })
|
||||
@Produces({ MediaType.TEXT_PLAIN })
|
||||
public String retrieveClientImage(@PathParam("clientId") final Long clientId) {
|
||||
|
||||
context.authenticatedUser().validateHasReadPermission("CLIENTIMAGE");
|
||||
context.authenticatedUser().validateHasReadPermission("CLIENTIMAGE");
|
||||
|
||||
final ClientData clientData = this.clientReadPlatformService
|
||||
.retrieveIndividualClient(clientId);
|
||||
final ClientData clientData = this.clientReadPlatformService.retrieveIndividualClient(clientId);
|
||||
|
||||
if (clientData.imageKeyDoesNotExist()) {
|
||||
throw new ImageNotFoundException("clients", clientId);
|
||||
}
|
||||
if (clientData.imageKeyDoesNotExist()) { throw new ImageNotFoundException("clients", clientId); }
|
||||
|
||||
return Base64.encodeFromFile(clientData.imageKey());
|
||||
}
|
||||
// TODO: Need a better way of determining image type
|
||||
String imageDataURISuffix = IMAGE_DATA_URI_SUFFIX.JPEG.getValue();
|
||||
if (StringUtils.endsWith(clientData.imageKey(), IMAGE_FILE_EXTENSION.GIF.getValue())) {
|
||||
imageDataURISuffix = IMAGE_DATA_URI_SUFFIX.GIF.getValue();
|
||||
} else if (StringUtils.endsWith(clientData.imageKey(), IMAGE_FILE_EXTENSION.PNG.getValue())) {
|
||||
imageDataURISuffix = IMAGE_DATA_URI_SUFFIX.PNG.getValue();
|
||||
}
|
||||
|
||||
/**
|
||||
* This method is added only for consistency with other URL patterns and for
|
||||
* maintaining consistency of usage of the HTTP "verb" at the client side
|
||||
*/
|
||||
@PUT
|
||||
@Consumes({ MediaType.MULTIPART_FORM_DATA })
|
||||
@Produces({ MediaType.APPLICATION_JSON })
|
||||
public String updateClientImage(
|
||||
@PathParam("clientId") final Long clientId,
|
||||
@HeaderParam("Content-Length") final Long fileSize,
|
||||
@FormDataParam("file") final InputStream inputStream,
|
||||
@FormDataParam("file") final FormDataContentDisposition fileDetails,
|
||||
@FormDataParam("file") final FormDataBodyPart bodyPart) {
|
||||
String clientImageAsBase64Text = imageDataURISuffix + Base64.encodeFromFile(clientData.imageKey());
|
||||
|
||||
return addNewClientImage(clientId, fileSize, inputStream, fileDetails,
|
||||
bodyPart);
|
||||
}
|
||||
return clientImageAsBase64Text;
|
||||
}
|
||||
|
||||
@DELETE
|
||||
@Consumes({ MediaType.APPLICATION_JSON })
|
||||
@Produces({ MediaType.APPLICATION_JSON })
|
||||
public String deleteClientImage(@PathParam("clientId") final Long clientId) {
|
||||
this.clientWritePlatformService.deleteClientImage(clientId);
|
||||
@GET
|
||||
@Consumes({ MediaType.APPLICATION_JSON })
|
||||
@Produces({ MediaType.APPLICATION_OCTET_STREAM })
|
||||
public Response downloadClientImage(@PathParam("clientId") final Long clientId) {
|
||||
|
||||
return this.toApiJsonSerializer.serialize(new CommandProcessingResult(
|
||||
clientId));
|
||||
}
|
||||
context.authenticatedUser().validateHasReadPermission("CLIENTIMAGE");
|
||||
final ClientData clientData = this.clientReadPlatformService.retrieveIndividualClient(clientId);
|
||||
|
||||
if (clientData.imageKeyDoesNotExist()) { throw new ImageNotFoundException("clients", clientId); }
|
||||
|
||||
File image = new File(clientData.imageKey());
|
||||
String imageName = image.getName();
|
||||
ResponseBuilder response = Response.ok(image);
|
||||
response.header("Content-Disposition", "attachment; filename=\"" + imageName + "\"");
|
||||
|
||||
// TODO: Need a better way of determining image type
|
||||
|
||||
// determine image type
|
||||
String contentType = IMAGE_MIME_TYPE.JPEG.getValue();
|
||||
if (StringUtils.endsWith(imageName, IMAGE_FILE_EXTENSION.GIF.getValue())) {
|
||||
contentType = IMAGE_MIME_TYPE.GIF.getValue();
|
||||
} else if (StringUtils.endsWith(imageName, IMAGE_FILE_EXTENSION.PNG.getValue())) {
|
||||
contentType = IMAGE_MIME_TYPE.PNG.getValue();
|
||||
}
|
||||
|
||||
response.header("Content-Type", contentType);
|
||||
return response.build();
|
||||
}
|
||||
|
||||
/**
|
||||
* This method is added only for consistency with other URL patterns and for
|
||||
* maintaining consistency of usage of the HTTP "verb" at the client side
|
||||
*/
|
||||
@PUT
|
||||
@Consumes({ MediaType.MULTIPART_FORM_DATA })
|
||||
@Produces({ MediaType.APPLICATION_JSON })
|
||||
public String updateClientImage(@PathParam("clientId") final Long clientId, @HeaderParam("Content-Length") final Long fileSize,
|
||||
@FormDataParam("file") final InputStream inputStream, @FormDataParam("file") final FormDataContentDisposition fileDetails,
|
||||
@FormDataParam("file") final FormDataBodyPart bodyPart) {
|
||||
return addNewClientImage(clientId, fileSize, inputStream, fileDetails, bodyPart);
|
||||
}
|
||||
|
||||
/**
|
||||
* This method is added only for consistency with other URL patterns and for
|
||||
* maintaining consistency of usage of the HTTP "verb" at the client side
|
||||
*
|
||||
* Upload image as a Data URL (essentially a base64 encoded stream)
|
||||
*/
|
||||
@PUT
|
||||
@Consumes({ MediaType.TEXT_PLAIN, MediaType.TEXT_HTML, MediaType.APPLICATION_JSON })
|
||||
@Produces({ MediaType.APPLICATION_JSON })
|
||||
public String updateClientImage(@PathParam("clientId") final Long clientId, final String jsonRequestBody) {
|
||||
return addNewClientImage(clientId, jsonRequestBody);
|
||||
}
|
||||
|
||||
@DELETE
|
||||
@Consumes({ MediaType.APPLICATION_JSON })
|
||||
@Produces({ MediaType.APPLICATION_JSON })
|
||||
public String deleteClientImage(@PathParam("clientId") final Long clientId) {
|
||||
this.clientWritePlatformService.deleteClientImage(clientId);
|
||||
return this.toApiJsonSerializer.serialize(new CommandProcessingResult(clientId));
|
||||
}
|
||||
|
||||
/**
|
||||
* This method is added only for consistency with other URL patterns and for
|
||||
* maintaining consistency of usage of the HTTP "verb" at the client side
|
||||
*
|
||||
* Upload image as a Data URL (essentially a base64 encoded stream)
|
||||
*/
|
||||
@PUT
|
||||
@Consumes({ MediaType.APPLICATION_JSON })
|
||||
@Produces({ MediaType.APPLICATION_JSON })
|
||||
public String updateClientImage(@PathParam("clientId") final Long clientId,
|
||||
final String jsonRequestBody) {
|
||||
return addNewClientImage(clientId, jsonRequestBody);
|
||||
}
|
||||
}
|
||||
+2
-2
@@ -5,9 +5,9 @@
|
||||
*/
|
||||
package org.mifosplatform.portfolio.client.exception;
|
||||
|
||||
import org.mifosplatform.infrastructure.core.exception.AbstractPlatformDomainRuleException;
|
||||
import org.mifosplatform.infrastructure.core.exception.AbstractPlatformResourceNotFoundException;
|
||||
|
||||
public class ImageNotFoundException extends AbstractPlatformDomainRuleException {
|
||||
public class ImageNotFoundException extends AbstractPlatformResourceNotFoundException {
|
||||
|
||||
public ImageNotFoundException(final String resource, final Long resourceId) {
|
||||
super("error.msg.entity.image.invalid", "Image for resource " + resource + " with Identifier " + resourceId + " does not exist",
|
||||
|
||||
+5
-5
@@ -23,21 +23,21 @@ public class DefaultLoanLifecycleStateMachine implements LoanLifecycleStateMachi
|
||||
switch (loanEvent) {
|
||||
case LOAN_CREATED:
|
||||
if (from == null) {
|
||||
newState = stateOf(LoanStatus.SUBMITED_AND_PENDING_APPROVAL, allowedLoanStatuses);
|
||||
newState = stateOf(LoanStatus.SUBMITTED_AND_PENDING_APPROVAL, allowedLoanStatuses);
|
||||
}
|
||||
break;
|
||||
case LOAN_REJECTED:
|
||||
if (from.hasStateOf(LoanStatus.SUBMITED_AND_PENDING_APPROVAL)) {
|
||||
if (from.hasStateOf(LoanStatus.SUBMITTED_AND_PENDING_APPROVAL)) {
|
||||
newState = stateOf(LoanStatus.REJECTED, allowedLoanStatuses);
|
||||
}
|
||||
break;
|
||||
case LOAN_APPROVED:
|
||||
if (from.hasStateOf(LoanStatus.SUBMITED_AND_PENDING_APPROVAL)) {
|
||||
if (from.hasStateOf(LoanStatus.SUBMITTED_AND_PENDING_APPROVAL)) {
|
||||
newState = stateOf(LoanStatus.APPROVED, allowedLoanStatuses);
|
||||
}
|
||||
break;
|
||||
case LOAN_WITHDRAWN:
|
||||
if (this.anyOfAllowedWhenComingFrom(from, LoanStatus.SUBMITED_AND_PENDING_APPROVAL, LoanStatus.APPROVED)) {
|
||||
if (this.anyOfAllowedWhenComingFrom(from, LoanStatus.SUBMITTED_AND_PENDING_APPROVAL, LoanStatus.APPROVED)) {
|
||||
newState = stateOf(LoanStatus.WITHDRAWN_BY_CLIENT, allowedLoanStatuses);
|
||||
}
|
||||
break;
|
||||
@@ -48,7 +48,7 @@ public class DefaultLoanLifecycleStateMachine implements LoanLifecycleStateMachi
|
||||
break;
|
||||
case LOAN_APPROVAL_UNDO:
|
||||
if (from.hasStateOf(LoanStatus.APPROVED)) {
|
||||
newState = stateOf(LoanStatus.SUBMITED_AND_PENDING_APPROVAL, allowedLoanStatuses);
|
||||
newState = stateOf(LoanStatus.SUBMITTED_AND_PENDING_APPROVAL, allowedLoanStatuses);
|
||||
}
|
||||
break;
|
||||
case LOAN_DISBURSAL_UNDO:
|
||||
|
||||
+3
-3
@@ -11,7 +11,7 @@ package org.mifosplatform.portfolio.loanaccount.domain;
|
||||
public enum LoanStatus {
|
||||
|
||||
INVALID(0, "loanStatusType.invalid"), //
|
||||
SUBMITED_AND_PENDING_APPROVAL(100, "loanStatusType.submitted.and.pending.approval"), //
|
||||
SUBMITTED_AND_PENDING_APPROVAL(100, "loanStatusType.submitted.and.pending.approval"), //
|
||||
APPROVED(200, "loanStatusType.approved"), //
|
||||
ACTIVE(300, "loanStatusType.active"), //
|
||||
WITHDRAWN_BY_CLIENT(400, "loanStatusType.withdrawn.by.client"), //
|
||||
@@ -29,7 +29,7 @@ public enum LoanStatus {
|
||||
LoanStatus enumeration = LoanStatus.INVALID;
|
||||
switch (statusValue) {
|
||||
case 100:
|
||||
enumeration = LoanStatus.SUBMITED_AND_PENDING_APPROVAL;
|
||||
enumeration = LoanStatus.SUBMITTED_AND_PENDING_APPROVAL;
|
||||
break;
|
||||
case 200:
|
||||
enumeration = LoanStatus.APPROVED;
|
||||
@@ -77,7 +77,7 @@ public enum LoanStatus {
|
||||
}
|
||||
|
||||
public boolean isSubmittedAndPendingApproval() {
|
||||
return this.value.equals(LoanStatus.SUBMITED_AND_PENDING_APPROVAL.getValue());
|
||||
return this.value.equals(LoanStatus.SUBMITTED_AND_PENDING_APPROVAL.getValue());
|
||||
}
|
||||
|
||||
public boolean isApproved() {
|
||||
|
||||
+11
-5
@@ -26,6 +26,8 @@ import org.mifosplatform.portfolio.charge.domain.Charge;
|
||||
import org.mifosplatform.portfolio.charge.domain.ChargeRepositoryWrapper;
|
||||
import org.mifosplatform.portfolio.charge.exception.LoanChargeCannotBeDeletedException;
|
||||
import org.mifosplatform.portfolio.charge.exception.LoanChargeCannotBeDeletedException.LOAN_CHARGE_CANNOT_BE_DELETED_REASON;
|
||||
import org.mifosplatform.portfolio.charge.exception.LoanChargeCannotBeUpdatedException;
|
||||
import org.mifosplatform.portfolio.charge.exception.LoanChargeCannotBeUpdatedException.LOAN_CHARGE_CANNOT_BE_UPDATED_REASON;
|
||||
import org.mifosplatform.portfolio.charge.exception.LoanChargeCannotBeWaivedException;
|
||||
import org.mifosplatform.portfolio.charge.exception.LoanChargeCannotBeWaivedException.LOAN_CHARGE_CANNOT_BE_WAIVED_REASON;
|
||||
import org.mifosplatform.portfolio.charge.exception.LoanChargeNotFoundException;
|
||||
@@ -529,6 +531,11 @@ public class LoanWritePlatformServiceJpaRepositoryImpl implements LoanWritePlatf
|
||||
final Loan loan = retrieveLoanBy(loanId);
|
||||
final LoanCharge loanCharge = retrieveLoanChargeBy(loanId, loanChargeId);
|
||||
|
||||
// Charges may be edited only when the loan associated with them are
|
||||
// yet to be approved (are in submitted and pending status)
|
||||
if (!loan.status().isSubmittedAndPendingApproval()) { throw new LoanChargeCannotBeUpdatedException(
|
||||
LOAN_CHARGE_CANNOT_BE_UPDATED_REASON.LOAN_NOT_IN_SUBMITTED_AND_PENDING_APPROVAL_STAGE, loanCharge.getId()); }
|
||||
|
||||
final Map<String, Object> changes = loan.updateLoanCharge(loanCharge, command);
|
||||
|
||||
this.loanRepository.save(loan);
|
||||
@@ -597,11 +604,10 @@ public class LoanWritePlatformServiceJpaRepositoryImpl implements LoanWritePlatf
|
||||
final Loan loan = retrieveLoanBy(loanId);
|
||||
final LoanCharge loanCharge = retrieveLoanChargeBy(loanId, loanChargeId);
|
||||
|
||||
// validate loan charge is not partly paid or waived
|
||||
if (loanCharge.isWaived()) {
|
||||
throw new LoanChargeCannotBeDeletedException(LOAN_CHARGE_CANNOT_BE_DELETED_REASON.ALREADY_WAIVED, loanCharge.getId());
|
||||
} else if (loanCharge.isPaidOrPartiallyPaid(loan.getCurrency())) { throw new LoanChargeCannotBeDeletedException(
|
||||
LOAN_CHARGE_CANNOT_BE_DELETED_REASON.ALREADY_PAID, loanCharge.getId()); }
|
||||
// Charges may be deleted only when the loan associated with them are
|
||||
// yet to be approved (are in submitted and pending status)
|
||||
if (!loan.status().isSubmittedAndPendingApproval()) { throw new LoanChargeCannotBeDeletedException(
|
||||
LOAN_CHARGE_CANNOT_BE_DELETED_REASON.LOAN_NOT_IN_SUBMITTED_AND_PENDING_APPROVAL_STAGE, loanCharge.getId()); }
|
||||
|
||||
loan.removeLoanCharge(loanCharge);
|
||||
this.loanRepository.save(loan);
|
||||
|
||||
+3
-3
@@ -263,9 +263,9 @@ public class LoanEnumerations {
|
||||
case INVALID:
|
||||
optionData = new LoanStatusEnumData(LoanStatus.INVALID.getValue().longValue(), LoanStatus.INVALID.getCode(), "Invalid");
|
||||
break;
|
||||
case SUBMITED_AND_PENDING_APPROVAL:
|
||||
optionData = new LoanStatusEnumData(LoanStatus.SUBMITED_AND_PENDING_APPROVAL.getValue().longValue(),
|
||||
LoanStatus.SUBMITED_AND_PENDING_APPROVAL.getCode(), "Submitted and pending approval");
|
||||
case SUBMITTED_AND_PENDING_APPROVAL:
|
||||
optionData = new LoanStatusEnumData(LoanStatus.SUBMITTED_AND_PENDING_APPROVAL.getValue().longValue(),
|
||||
LoanStatus.SUBMITTED_AND_PENDING_APPROVAL.getCode(), "Submitted and pending approval");
|
||||
break;
|
||||
case APPROVED:
|
||||
optionData = new LoanStatusEnumData(LoanStatus.APPROVED.getValue().longValue(), LoanStatus.APPROVED.getCode(), "Approved");
|
||||
|
||||
Reference in New Issue
Block a user