wip: Loan Collateral

This commit is contained in:
Vishwas Babu AJ
2013-03-27 03:42:21 +05:30
parent b8e4cf3dc9
commit 69d228a502
29 changed files with 942 additions and 160 deletions
+12
View File
@@ -0,0 +1,12 @@
ALTER TABLE `m_loan_collateral`
ADD COLUMN `value` DECIMAL(19,6) NULL DEFAULT NULL AFTER `type_cv_id`;
INSERT INTO `m_permission` (`grouping`, `code`, `entity_name`, `action_name`, `can_maker_checker`)
VALUES('portfolio', 'CREATE_COLLATERAL', 'COLLATERAL', 'CREATE', '0'),
('portfolio', 'READ_COLLATERAL', 'COLLATERAL', 'READ', '0'),
('portfolio', 'UPDATE_COLLATERAL', 'COLLATERAL', 'UPDATE', '0'),
('portfolio', 'DELETE_COLLATERAL', 'COLLATERAL', 'DELETE', '0'),
('portfolio', 'CREATE_COLLATERAL_CHECKER', 'COLLATERAL', 'CREATE', '0'),
('portfolio', 'UPDATE_COLLATERAL_CHECKER', 'COLLATERAL', 'UPDATE', '0'),
('portfolio', 'DELETE_COLLATERAL_CHECKER', 'COLLATERAL', 'DELETE', '0');
@@ -277,6 +277,10 @@ public class CommandWrapper {
return this.entityName.equalsIgnoreCase("LOANCHARGE");
}
public boolean isCollateralResource() {
return this.entityName.equalsIgnoreCase("COLLATERAL");
}
public boolean isApproveLoanApplication() {
return this.actionName.equalsIgnoreCase("APPROVE") && this.entityName.equalsIgnoreCase("LOAN");
}
@@ -800,4 +800,31 @@ public class CommandWrapperBuilder {
this.href = "/groups/" + groupId;
return this;
}
public CommandWrapperBuilder createCollateral(final Long loanId) {
this.actionName = "CREATE";
this.entityName = "COLLATERAL";
this.entityId = null;
this.loanId = loanId;
this.href = "/loans/" + loanId + "/collaterals/template";
return this;
}
public CommandWrapperBuilder updateCollateral(final Long loanId, final Long collateralId) {
this.actionName = "UPDATE";
this.entityName = "COLLATERAL";
this.entityId = collateralId;
this.loanId = loanId;
this.href = "/loans/" + loanId + "/collaterals/" + collateralId;
return this;
}
public CommandWrapperBuilder deleteCollateral(final Long loanId, final Long collateralId) {
this.actionName = "DELETE";
this.entityName = "COLLATERAL";
this.entityId = collateralId;
this.loanId = loanId;
this.href = "/loans/" + loanId + "/collaterals/" + collateralId;
return this;
}
}
@@ -69,7 +69,8 @@ public class SynchronousCommandProcessingService implements CommandProcessingSer
commandSourceResult = CommandSource.fullEntryFrom(wrapper, command, maker);
}
commandSourceResult.updateResourceId(result.resourceId());
commandSourceResult.updateForAudit(result.getOfficeId(), result.getGroupId(), result.getClientId(), result.getLoanId(), result.getSavingsId());
commandSourceResult.updateForAudit(result.getOfficeId(), result.getGroupId(), result.getClientId(), result.getLoanId(),
result.getSavingsId());
String changesOnlyJson = null;
if (result.hasChanges()) {
@@ -192,6 +193,16 @@ public class SynchronousCommandProcessingService implements CommandProcessingSer
} else {
throw new UnsupportedCommandException(wrapper.commandName());
}
} else if (wrapper.isCollateralResource()) {
if (wrapper.isCreate()) {
handler = applicationContext.getBean("createCollateralCommandHandler", NewCommandSourceHandler.class);
} else if (wrapper.isUpdate()) {
handler = applicationContext.getBean("updateCollateralCommandHandler", NewCommandSourceHandler.class);
} else if (wrapper.isDelete()) {
handler = applicationContext.getBean("deleteCollateralCommandHandler", NewCommandSourceHandler.class);
} else {
throw new UnsupportedCommandException(wrapper.commandName());
}
} else if (wrapper.isCodeResource()) {
if (wrapper.isCreate()) {
handler = applicationContext.getBean("createCodeCommandHandler", NewCommandSourceHandler.class);
@@ -0,0 +1,45 @@
/**
* 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.collateral.api;
import java.util.HashSet;
import java.util.Set;
public class CollateralApiConstants {
/***
* Enum of all parameters passed in while creating/updating a collateral
***/
public static enum COLLATERAL_JSON_INPUT_PARAMS {
LOAN_ID("loanId"), COLLATERAL_ID("collateralId"), COLLATERAL_TYPE_ID("collateralTypeId"), VALUE("value"), DESCRIPTION("description");
private final String value;
private COLLATERAL_JSON_INPUT_PARAMS(final String value) {
this.value = value;
}
private static final Set<String> values = new HashSet<String>();
static {
for (COLLATERAL_JSON_INPUT_PARAMS type : COLLATERAL_JSON_INPUT_PARAMS.values()) {
values.add(type.value);
}
}
public static Set<String> getAllValues() {
return values;
}
@Override
public String toString() {
return name().toString().replaceAll("_", " ");
}
public String getValue() {
return this.value;
}
}
}
@@ -0,0 +1,158 @@
/**
* 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.collateral.api;
import java.util.Arrays;
import java.util.Collection;
import java.util.HashSet;
import java.util.List;
import java.util.Set;
import javax.ws.rs.Consumes;
import javax.ws.rs.DELETE;
import javax.ws.rs.GET;
import javax.ws.rs.POST;
import javax.ws.rs.PUT;
import javax.ws.rs.Path;
import javax.ws.rs.PathParam;
import javax.ws.rs.Produces;
import javax.ws.rs.core.Context;
import javax.ws.rs.core.MediaType;
import javax.ws.rs.core.UriInfo;
import org.mifosplatform.commands.domain.CommandWrapper;
import org.mifosplatform.commands.service.CommandWrapperBuilder;
import org.mifosplatform.commands.service.PortfolioCommandSourceWritePlatformService;
import org.mifosplatform.infrastructure.codes.data.CodeValueData;
import org.mifosplatform.infrastructure.codes.service.CodeValueReadPlatformService;
import org.mifosplatform.infrastructure.core.api.ApiRequestParameterHelper;
import org.mifosplatform.infrastructure.core.data.CommandProcessingResult;
import org.mifosplatform.infrastructure.core.serialization.ApiRequestJsonSerializationSettings;
import org.mifosplatform.infrastructure.core.serialization.DefaultToApiJsonSerializer;
import org.mifosplatform.infrastructure.security.service.PlatformSecurityContext;
import org.mifosplatform.portfolio.collateral.data.CollateralData;
import org.mifosplatform.portfolio.collateral.service.CollateralReadPlatformService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Scope;
import org.springframework.stereotype.Component;
@Path("/loans/{loanId}/collaterals")
@Component
@Scope("singleton")
public class CollateralsApiResource {
private static final Set<String> RESPONSE_DATA_PARAMETERS = new HashSet<String>(Arrays.asList("id", "type", "value", "description",
"allowedCollateralTypes"));
private final String resourceNameForPermission = "COLLATERAL";
private final CollateralReadPlatformService collateralReadPlatformService;
private final DefaultToApiJsonSerializer<CollateralData> apiJsonSerializerService;
private final ApiRequestParameterHelper apiRequestParameterHelper;
private final PortfolioCommandSourceWritePlatformService commandsSourceWritePlatformService;
private final PlatformSecurityContext context;
private final CodeValueReadPlatformService codeValueReadPlatformService;
@Autowired
public CollateralsApiResource(final PlatformSecurityContext context, final CollateralReadPlatformService collateralReadPlatformService,
final DefaultToApiJsonSerializer<CollateralData> toApiJsonSerializer,
final ApiRequestParameterHelper apiRequestParameterHelper,
final PortfolioCommandSourceWritePlatformService commandsSourceWritePlatformService,
final CodeValueReadPlatformService codeValueReadPlatformService) {
this.context = context;
this.apiRequestParameterHelper = apiRequestParameterHelper;
this.commandsSourceWritePlatformService = commandsSourceWritePlatformService;
this.apiJsonSerializerService = toApiJsonSerializer;
this.collateralReadPlatformService = collateralReadPlatformService;
this.codeValueReadPlatformService = codeValueReadPlatformService;
}
@GET
@Path("template")
@Consumes({ MediaType.APPLICATION_JSON })
@Produces({ MediaType.APPLICATION_JSON })
public String newCollateralTemplate(@Context final UriInfo uriInfo) {
context.authenticatedUser().validateHasReadPermission(resourceNameForPermission);
this.context.authenticatedUser().validateHasReadPermission(this.resourceNameForPermission);
final Collection<CodeValueData> codeValues = this.codeValueReadPlatformService.retrieveCodeValuesByCode("LoanCollateral");
final CollateralData collateralData = CollateralData.template(codeValues);
final ApiRequestJsonSerializationSettings settings = this.apiRequestParameterHelper.process(uriInfo.getQueryParameters());
return this.apiJsonSerializerService.serialize(settings, collateralData, RESPONSE_DATA_PARAMETERS);
}
@GET
@Consumes({ MediaType.APPLICATION_JSON })
@Produces({ MediaType.APPLICATION_JSON })
public String retrieveCollateralDetails(@Context final UriInfo uriInfo, @PathParam("loanId") final Long loanId) {
context.authenticatedUser().validateHasReadPermission(resourceNameForPermission);
List<CollateralData> CollateralDatas = collateralReadPlatformService.retrieveCollateralsForValidLoan(loanId);
final ApiRequestJsonSerializationSettings settings = apiRequestParameterHelper.process(uriInfo.getQueryParameters());
return this.apiJsonSerializerService.serialize(settings, CollateralDatas, RESPONSE_DATA_PARAMETERS);
}
@GET
@Path("{collateralId}")
@Consumes({ MediaType.APPLICATION_JSON })
@Produces({ MediaType.APPLICATION_JSON })
public String retrieveCollateralDetails(@Context final UriInfo uriInfo, @PathParam("loanId") final Long loanId,
@PathParam("collateralId") final Long CollateralId) {
context.authenticatedUser().validateHasReadPermission(resourceNameForPermission);
CollateralData CollateralData = collateralReadPlatformService.retrieveCollateral(loanId, CollateralId);
final ApiRequestJsonSerializationSettings settings = apiRequestParameterHelper.process(uriInfo.getQueryParameters());
if (settings.isTemplate()) {
final Collection<CodeValueData> codeValues = this.codeValueReadPlatformService.retrieveCodeValuesByCode("LoanCollateral");
CollateralData = CollateralData.template(CollateralData, codeValues);
}
return this.apiJsonSerializerService.serialize(settings, CollateralData, RESPONSE_DATA_PARAMETERS);
}
@POST
@Consumes({ MediaType.APPLICATION_JSON })
@Produces({ MediaType.APPLICATION_JSON })
public String createCollateral(@PathParam("loanId") final Long loanId, final String apiRequestBodyAsJson) {
final CommandWrapper commandRequest = new CommandWrapperBuilder().createCollateral(loanId).withJson(apiRequestBodyAsJson).build();
final CommandProcessingResult result = this.commandsSourceWritePlatformService.logCommandSource(commandRequest);
return this.apiJsonSerializerService.serialize(result);
}
@PUT
@Path("{collateralId}")
@Consumes({ MediaType.APPLICATION_JSON })
@Produces({ MediaType.APPLICATION_JSON })
public String updateCollateral(@PathParam("loanId") final Long loanId, @PathParam("collateralId") final Long collateralId,
final String jsonRequestBody) {
final CommandWrapper commandRequest = new CommandWrapperBuilder().updateCollateral(loanId, collateralId).withJson(jsonRequestBody)
.build();
final CommandProcessingResult result = this.commandsSourceWritePlatformService.logCommandSource(commandRequest);
return this.apiJsonSerializerService.serialize(result);
}
@DELETE
@Path("{collateralId}")
@Consumes({ MediaType.APPLICATION_JSON })
@Produces({ MediaType.APPLICATION_JSON })
public String deleteCollateral(@PathParam("loanId") final Long loanId, @PathParam("collateralId") final Long collateralId) {
final CommandWrapper commandRequest = new CommandWrapperBuilder().deleteCollateral(loanId, collateralId).build();
final CommandProcessingResult result = this.commandsSourceWritePlatformService.logCommandSource(commandRequest);
return this.apiJsonSerializerService.serialize(result);
}
}
@@ -0,0 +1,68 @@
/**
* 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.collateral.command;
import java.math.BigDecimal;
import java.util.ArrayList;
import java.util.List;
import org.mifosplatform.infrastructure.core.data.ApiParameterError;
import org.mifosplatform.infrastructure.core.data.DataValidatorBuilder;
import org.mifosplatform.infrastructure.core.exception.PlatformApiDataValidationException;
/**
* Immutable command for creating or updating details of a Collateral.
*/
public class CollateralCommand {
private final Long collateralTypeId;
private final BigDecimal value;
private final String description;
public CollateralCommand(final Long collateralTypeId, final BigDecimal value, final String description) {
this.collateralTypeId = collateralTypeId;
this.value = value;
this.description = description;
}
public Long getCollateralTypeId() {
return this.collateralTypeId;
}
public BigDecimal getValue() {
return this.value;
}
public String getDescription() {
return this.description;
}
public void validateForCreate() {
List<ApiParameterError> dataValidationErrors = new ArrayList<ApiParameterError>();
DataValidatorBuilder baseDataValidator = new DataValidatorBuilder(dataValidationErrors).resource("collateral");
baseDataValidator.reset().parameter("collateralTypeId").value(this.collateralTypeId).notNull().integerGreaterThanZero();
baseDataValidator.reset().parameter("value").value(this.value).ignoreIfNull().positiveAmount();
baseDataValidator.reset().parameter("description").value(this.description).ignoreIfNull().notExceedingLengthOf(500);
if (!dataValidationErrors.isEmpty()) { throw new PlatformApiDataValidationException("validation.msg.validation.errors.exist",
"Validation errors exist.", dataValidationErrors); }
}
public void validateForUpdate() {
List<ApiParameterError> dataValidationErrors = new ArrayList<ApiParameterError>();
DataValidatorBuilder baseDataValidator = new DataValidatorBuilder(dataValidationErrors).resource("collateral");
baseDataValidator.reset().parameter("collateralTypeId").value(this.collateralTypeId).ignoreIfNull().integerGreaterThanZero();
baseDataValidator.reset().parameter("value").value(this.value).ignoreIfNull().positiveAmount();
baseDataValidator.reset().parameter("description").value(this.description).ignoreIfNull().notExceedingLengthOf(500);
if (!dataValidationErrors.isEmpty()) { throw new PlatformApiDataValidationException("validation.msg.validation.errors.exist",
"Validation errors exist.", dataValidationErrors); }
}
}
@@ -0,0 +1,53 @@
/**
* 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.collateral.data;
import java.math.BigDecimal;
import java.util.Collection;
import org.mifosplatform.infrastructure.codes.data.CodeValueData;
/**
* Immutable data object for Collateral data.
*/
public class CollateralData {
private final Long id;
private final CodeValueData type;
private final BigDecimal value;
private final String description;
@SuppressWarnings("unused")
private final Collection<CodeValueData> allowedCollateralTypes;
public static CollateralData instance(final Long id, final CodeValueData type, final BigDecimal value, final String description) {
return new CollateralData(id, type, value, description);
}
public static CollateralData template(final Collection<CodeValueData> codeValues) {
return new CollateralData(null, null, null, null, codeValues);
}
private CollateralData(final Long id, final CodeValueData type, final BigDecimal value, final String description) {
this.id = id;
this.type = type;
this.value = value;
this.description = description;
this.allowedCollateralTypes = null;
}
private CollateralData(final Long id, final CodeValueData type, final BigDecimal value, final String description,
Collection<CodeValueData> allowedCollateralTypes) {
this.id = id;
this.type = type;
this.value = value;
this.description = description;
this.allowedCollateralTypes = allowedCollateralTypes;
}
public CollateralData template(CollateralData collateralData, Collection<CodeValueData> codeValues) {
return new CollateralData(collateralData.id, collateralData.type, collateralData.value, collateralData.description, codeValues);
}
}
@@ -3,8 +3,9 @@
* 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.loanaccount.domain;
package org.mifosplatform.portfolio.collateral.domain;
import java.math.BigDecimal;
import java.util.LinkedHashMap;
import java.util.Map;
@@ -20,7 +21,8 @@ import org.apache.commons.lang.builder.HashCodeBuilder;
import org.mifosplatform.infrastructure.codes.data.CodeValueData;
import org.mifosplatform.infrastructure.codes.domain.CodeValue;
import org.mifosplatform.infrastructure.core.api.JsonCommand;
import org.mifosplatform.portfolio.loanaccount.data.LoanCollateralData;
import org.mifosplatform.portfolio.collateral.data.CollateralData;
import org.mifosplatform.portfolio.loanaccount.domain.Loan;
import org.springframework.data.jpa.domain.AbstractPersistable;
@Entity
@@ -36,32 +38,43 @@ public class LoanCollateral extends AbstractPersistable<Long> {
@JoinColumn(name = "type_cv_id", nullable = false)
private CodeValue type;
@Column(name = "value", scale = 6, precision = 19)
private BigDecimal value;
@Column(name = "description", length = 500)
private String description;
public static LoanCollateral from(final CodeValue collateralType, final String description) {
return new LoanCollateral(null, collateralType, description);
public static LoanCollateral from(final CodeValue collateralType, final BigDecimal value, final String description) {
return new LoanCollateral(null, collateralType, value, description);
}
protected LoanCollateral() {
//
}
private LoanCollateral(final Loan loan, final CodeValue collateralType, final String description) {
private LoanCollateral(final Loan loan, final CodeValue collateralType, final BigDecimal value, final String description) {
this.loan = loan;
this.type = collateralType;
this.value = value;
this.description = StringUtils.defaultIfEmpty(description, null);
}
public void assembleFrom(final CodeValue collateralType, final String description) {
public void assembleFrom(final CodeValue collateralType, final BigDecimal value, final String description) {
this.type = collateralType;
this.description = description;
this.value = value;
}
public void associateWith(final Loan loan) {
this.loan = loan;
}
public static LoanCollateral fromJson(final Loan loan, final CodeValue collateralType, final JsonCommand command) {
final String description = command.stringValueOfParameterNamed("description");
final BigDecimal value = command.bigDecimalValueOfParameterNamed("value");
return new LoanCollateral(loan, collateralType, value, description);
}
public Map<String, Object> update(final JsonCommand command) {
final Map<String, Object> actualChanges = new LinkedHashMap<String, Object>(7);
@@ -79,12 +92,23 @@ public class LoanCollateral extends AbstractPersistable<Long> {
this.description = StringUtils.defaultIfEmpty(newValue, null);
}
final String valueParamName = "value";
if (command.isChangeInBigDecimalParameterNamed(valueParamName, this.value)) {
final BigDecimal newValue = command.bigDecimalValueOfParameterNamed(valueParamName);
actualChanges.put(valueParamName, newValue);
this.value = newValue;
}
return actualChanges;
}
public LoanCollateralData toData() {
public CollateralData toData() {
final CodeValueData typeData = this.type.toData();
return LoanCollateralData.instance(this.getId(), typeData, this.description);
return CollateralData.instance(this.getId(), typeData, this.value, this.description);
}
public void setCollateralType(CodeValue type) {
this.type = type;
}
@Override
@@ -97,6 +121,7 @@ public class LoanCollateral extends AbstractPersistable<Long> {
.append(this.getId(), rhs.getId()) //
.append(this.type.getId(), rhs.type.getId()) //
.append(this.description, rhs.description) //
.append(this.value, this.value)//
.isEquals();
}
@@ -106,6 +131,7 @@ public class LoanCollateral extends AbstractPersistable<Long> {
.append(this.getId()) //
.append(this.type.getId()) //
.append(this.description) //
.append(this.value)//
.toHashCode();
}
}
@@ -3,7 +3,7 @@
* 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.loanaccount.domain;
package org.mifosplatform.portfolio.collateral.domain;
import org.springframework.data.jpa.repository.JpaRepository;
import org.springframework.data.jpa.repository.JpaSpecificationExecutor;
@@ -0,0 +1,19 @@
/**
* 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.collateral.exception;
import org.mifosplatform.infrastructure.core.exception.AbstractPlatformResourceNotFoundException;
/**
* A {@link RuntimeException} thrown when guarantor resources are not found.
*/
public class CollateralNotFoundException extends AbstractPlatformResourceNotFoundException {
public CollateralNotFoundException(Long loanId, Long collateralId) {
super("error.msg.loan.collateral.", "Collateral with Id " + collateralId + " does not exist for loan with Id " + loanId, loanId,
collateralId);
}
}
@@ -0,0 +1,31 @@
/**
* 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.collateral.handler;
import org.mifosplatform.commands.handler.NewCommandSourceHandler;
import org.mifosplatform.infrastructure.core.api.JsonCommand;
import org.mifosplatform.infrastructure.core.data.CommandProcessingResult;
import org.mifosplatform.portfolio.collateral.service.CollateralWritePlatformService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
@Service
public class CreateCollateralCommandHandler implements NewCommandSourceHandler {
private final CollateralWritePlatformService writePlatformService;
@Autowired
public CreateCollateralCommandHandler(final CollateralWritePlatformService writePlatformService) {
this.writePlatformService = writePlatformService;
}
@Transactional
@Override
public CommandProcessingResult processCommand(final JsonCommand command) {
return this.writePlatformService.addCollateral(command.getLoanId(), command);
}
}
@@ -0,0 +1,31 @@
/**
* 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.collateral.handler;
import org.mifosplatform.commands.handler.NewCommandSourceHandler;
import org.mifosplatform.infrastructure.core.api.JsonCommand;
import org.mifosplatform.infrastructure.core.data.CommandProcessingResult;
import org.mifosplatform.portfolio.collateral.service.CollateralWritePlatformService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
@Service
public class DeleteCollateralCommandHandler implements NewCommandSourceHandler {
private final CollateralWritePlatformService collateralWritePlatformService;
@Autowired
public DeleteCollateralCommandHandler(final CollateralWritePlatformService guarantorWritePlatformService) {
this.collateralWritePlatformService = guarantorWritePlatformService;
}
@Transactional
@Override
public CommandProcessingResult processCommand(final JsonCommand command) {
return this.collateralWritePlatformService.deleteCollateral(command.getLoanId(), command.entityId(), command.commandId());
}
}
@@ -0,0 +1,31 @@
/**
* 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.collateral.handler;
import org.mifosplatform.commands.handler.NewCommandSourceHandler;
import org.mifosplatform.infrastructure.core.api.JsonCommand;
import org.mifosplatform.infrastructure.core.data.CommandProcessingResult;
import org.mifosplatform.portfolio.collateral.service.CollateralWritePlatformService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
@Service
public class UpdateCollateralCommandHandler implements NewCommandSourceHandler {
private final CollateralWritePlatformService writePlatformService;
@Autowired
public UpdateCollateralCommandHandler(final CollateralWritePlatformService writePlatformService) {
this.writePlatformService = writePlatformService;
}
@Transactional
@Override
public CommandProcessingResult processCommand(final JsonCommand command) {
return this.writePlatformService.updateCollateral(command.getLoanId(), command.entityId(), command);
}
}
@@ -0,0 +1,62 @@
/**
* 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.collateral.serialization;
import java.lang.reflect.Type;
import java.math.BigDecimal;
import java.util.Locale;
import java.util.Map;
import java.util.Set;
import org.apache.commons.lang.StringUtils;
import org.mifosplatform.infrastructure.core.exception.InvalidJsonException;
import org.mifosplatform.infrastructure.core.serialization.AbstractFromApiJsonDeserializer;
import org.mifosplatform.infrastructure.core.serialization.FromApiJsonDeserializer;
import org.mifosplatform.infrastructure.core.serialization.FromJsonHelper;
import org.mifosplatform.portfolio.collateral.api.CollateralApiConstants.COLLATERAL_JSON_INPUT_PARAMS;
import org.mifosplatform.portfolio.collateral.command.CollateralCommand;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;
import com.google.gson.JsonElement;
import com.google.gson.JsonObject;
import com.google.gson.reflect.TypeToken;
/**
* Implementation of {@link FromApiJsonDeserializer} for
* {@link CollateralCommand}'s.
*/
@Component
public final class CollateralCommandFromApiJsonDeserializer extends AbstractFromApiJsonDeserializer<CollateralCommand> {
private final FromJsonHelper fromApiJsonHelper;
@Autowired
public CollateralCommandFromApiJsonDeserializer(final FromJsonHelper fromApiJsonHelper) {
this.fromApiJsonHelper = fromApiJsonHelper;
}
@Override
public CollateralCommand commandFromApiJson(String json) {
if (StringUtils.isBlank(json)) { throw new InvalidJsonException(); }
final Type typeOfMap = new TypeToken<Map<String, Object>>() {}.getType();
Set<String> supportedParameters = COLLATERAL_JSON_INPUT_PARAMS.getAllValues();
supportedParameters.add("locale");
supportedParameters.add("dateFormat");
fromApiJsonHelper.checkForUnsupportedParameters(typeOfMap, json, supportedParameters);
final JsonElement element = fromApiJsonHelper.parse(json);
final JsonObject topLevelJsonElement = element.getAsJsonObject();
final Locale locale = fromApiJsonHelper.extractLocaleParameter(topLevelJsonElement);
Long collateralTypeId = fromApiJsonHelper.extractLongNamed(COLLATERAL_JSON_INPUT_PARAMS.COLLATERAL_TYPE_ID.getValue(), element);
String description = fromApiJsonHelper.extractStringNamed(COLLATERAL_JSON_INPUT_PARAMS.DESCRIPTION.getValue(), element);
BigDecimal value = fromApiJsonHelper.extractBigDecimalNamed(COLLATERAL_JSON_INPUT_PARAMS.VALUE.getValue(), element, locale);
return new CollateralCommand(collateralTypeId, value, description);
}
}
@@ -3,17 +3,19 @@
* 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.loanaccount.service;
package org.mifosplatform.portfolio.collateral.service;
import java.math.BigDecimal;
import java.util.HashSet;
import java.util.Locale;
import java.util.Set;
import org.mifosplatform.infrastructure.codes.domain.CodeValue;
import org.mifosplatform.infrastructure.codes.domain.CodeValueRepositoryWrapper;
import org.mifosplatform.infrastructure.core.serialization.FromJsonHelper;
import org.mifosplatform.portfolio.charge.exception.LoanCollateralNotFoundException;
import org.mifosplatform.portfolio.loanaccount.domain.LoanCollateral;
import org.mifosplatform.portfolio.loanaccount.domain.LoanCollateralRepository;
import org.mifosplatform.portfolio.collateral.domain.LoanCollateral;
import org.mifosplatform.portfolio.collateral.domain.LoanCollateralRepository;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
@@ -22,14 +24,14 @@ import com.google.gson.JsonElement;
import com.google.gson.JsonObject;
@Service
public class LoanCollateralAssembler {
public class CollateralAssembler {
private final FromJsonHelper fromApiJsonHelper;
private final CodeValueRepositoryWrapper codeValueRepository;
private final LoanCollateralRepository loanCollateralRepository;
@Autowired
public LoanCollateralAssembler(final FromJsonHelper fromApiJsonHelper, final CodeValueRepositoryWrapper codeValueRepository,
public CollateralAssembler(final FromJsonHelper fromApiJsonHelper, final CodeValueRepositoryWrapper codeValueRepository,
final LoanCollateralRepository loanCollateralRepository) {
this.fromApiJsonHelper = fromApiJsonHelper;
this.codeValueRepository = codeValueRepository;
@@ -45,6 +47,7 @@ public class LoanCollateralAssembler {
if (topLevelJsonElement.has("collateral") && topLevelJsonElement.get("collateral").isJsonArray()) {
final JsonArray array = topLevelJsonElement.get("collateral").getAsJsonArray();
final Locale locale = this.fromApiJsonHelper.extractLocaleParameter(topLevelJsonElement);
for (int i = 0; i < array.size(); i++) {
final JsonObject collateralItemElement = array.get(i).getAsJsonObject();
@@ -53,20 +56,21 @@ public class LoanCollateralAssembler {
final Long collateralTypeId = fromApiJsonHelper.extractLongNamed("type", collateralItemElement);
final CodeValue collateralType = this.codeValueRepository.findOneWithNotFoundDetection(collateralTypeId);
final String description = fromApiJsonHelper.extractStringNamed("description", collateralItemElement);
final BigDecimal value = fromApiJsonHelper.extractBigDecimalNamed("value", collateralItemElement, locale);
if (id == null) {
collateralItems.add(LoanCollateral.from(collateralType, description));
collateralItems.add(LoanCollateral.from(collateralType, value, description));
} else {
LoanCollateral loanCollateralItem = this.loanCollateralRepository.findOne(id);
if (loanCollateralItem == null) { throw new LoanCollateralNotFoundException(id); }
loanCollateralItem.assembleFrom(collateralType, description);
loanCollateralItem.assembleFrom(collateralType, value, description);
collateralItems.add(loanCollateralItem);
}
}
} else {
// no charges passed, use existing ones against loan
// no collaterals passed, use existing ones against loan
}
}
@@ -0,0 +1,27 @@
/**
* 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.collateral.service;
import java.util.List;
import org.mifosplatform.portfolio.collateral.data.CollateralData;
public interface CollateralReadPlatformService {
/**
* Validates the passed in loanId before retrieving Collaterals for the same
*
* @param loanId
* @return
*/
List<CollateralData> retrieveCollateralsForValidLoan(Long loanId);
List<CollateralData> retrieveCollaterals(Long loanId);
CollateralData retrieveCollateral(Long loanId, Long collateralId);
CollateralData retrieveNewCollateralDetails();
}
@@ -0,0 +1,106 @@
/**
* 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.collateral.service;
import java.math.BigDecimal;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.util.List;
import org.mifosplatform.infrastructure.codes.data.CodeValueData;
import org.mifosplatform.infrastructure.core.domain.JdbcSupport;
import org.mifosplatform.infrastructure.core.service.TenantAwareRoutingDataSource;
import org.mifosplatform.infrastructure.security.service.PlatformSecurityContext;
import org.mifosplatform.portfolio.collateral.data.CollateralData;
import org.mifosplatform.portfolio.collateral.exception.CollateralNotFoundException;
import org.mifosplatform.portfolio.loanaccount.domain.Loan;
import org.mifosplatform.portfolio.loanaccount.domain.LoanRepository;
import org.mifosplatform.portfolio.loanaccount.exception.LoanNotFoundException;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.dao.EmptyResultDataAccessException;
import org.springframework.jdbc.core.JdbcTemplate;
import org.springframework.jdbc.core.RowMapper;
import org.springframework.stereotype.Service;
@Service
public class CollateralReadPlatformServiceImpl implements CollateralReadPlatformService {
private final JdbcTemplate jdbcTemplate;
private final PlatformSecurityContext context;
private final LoanRepository loanRepository;
@Autowired
public CollateralReadPlatformServiceImpl(final PlatformSecurityContext context, final TenantAwareRoutingDataSource dataSource,
final LoanRepository loanRepository) {
this.context = context;
this.jdbcTemplate = new JdbcTemplate(dataSource);
this.loanRepository = loanRepository;
}
private static final class CollateralMapper implements RowMapper<CollateralData> {
private StringBuilder sqlBuilder = new StringBuilder(
"lc.id as id, lc.description as description, lc.value as value, cv.id as typeId, cv.code_value as typeName") //
.append(" FROM m_loan_collateral lc") //
.append(" JOIN m_code_value cv on lc.type_cv_id = cv.id");
public String schema() {
return sqlBuilder.toString();
}
@Override
public CollateralData mapRow(final ResultSet rs, @SuppressWarnings("unused") final int rowNum) throws SQLException {
final Long id = rs.getLong("id");
final String name = rs.getString("description");
final Long typeId = rs.getLong("typeId");
final BigDecimal value = JdbcSupport.getBigDecimalDefaultToNullIfZero(rs, "value");
final String typeName = rs.getString("typeName");
final CodeValueData type = CodeValueData.instance(typeId, typeName);
return CollateralData.instance(id, type, value, name);
}
}
@Override
public List<CollateralData> retrieveCollaterals(final Long loanId) {
this.context.authenticatedUser();
final CollateralMapper rm = new CollateralMapper();
final String sql = "select " + rm.schema() + " where lc.loan_id=? order by id ASC";
return this.jdbcTemplate.query(sql, rm, new Object[] { loanId });
}
@Override
public CollateralData retrieveCollateral(Long loanId, Long collateralId) {
try {
final CollateralMapper rm = new CollateralMapper();
String sql = "select " + rm.schema();
sql += " where lc.loan_id=? and lc.id = ?";
return this.jdbcTemplate.queryForObject(sql, rm, new Object[] { loanId, collateralId });
} catch (final EmptyResultDataAccessException e) {
throw new CollateralNotFoundException(loanId, collateralId);
}
}
@Override
public List<CollateralData> retrieveCollateralsForValidLoan(Long loanId) {
Loan loan = this.loanRepository.findOne(loanId);
if (loan == null) { throw new LoanNotFoundException(loanId); }
return retrieveCollaterals(loanId);
}
@Override
public CollateralData retrieveNewCollateralDetails() {
// TODO Auto-generated method stub
return null;
}
}
@@ -0,0 +1,18 @@
/**
* 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.collateral.service;
import org.mifosplatform.infrastructure.core.api.JsonCommand;
import org.mifosplatform.infrastructure.core.data.CommandProcessingResult;
public interface CollateralWritePlatformService {
CommandProcessingResult addCollateral(Long loanId, JsonCommand command);
CommandProcessingResult updateCollateral(Long loanId, Long collateralId, JsonCommand command);
CommandProcessingResult deleteCollateral(Long loanId, Long collateralId, Long commandId);
}
@@ -0,0 +1,155 @@
/**
* 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.collateral.service;
import java.util.Map;
import org.mifosplatform.infrastructure.codes.domain.CodeValue;
import org.mifosplatform.infrastructure.codes.domain.CodeValueRepositoryWrapper;
import org.mifosplatform.infrastructure.codes.exception.CodeValueNotFoundException;
import org.mifosplatform.infrastructure.core.api.JsonCommand;
import org.mifosplatform.infrastructure.core.data.CommandProcessingResult;
import org.mifosplatform.infrastructure.core.data.CommandProcessingResultBuilder;
import org.mifosplatform.infrastructure.core.exception.PlatformDataIntegrityException;
import org.mifosplatform.infrastructure.security.service.PlatformSecurityContext;
import org.mifosplatform.portfolio.collateral.command.CollateralCommand;
import org.mifosplatform.portfolio.collateral.domain.LoanCollateral;
import org.mifosplatform.portfolio.collateral.domain.LoanCollateralRepository;
import org.mifosplatform.portfolio.collateral.exception.CollateralNotFoundException;
import org.mifosplatform.portfolio.collateral.serialization.CollateralCommandFromApiJsonDeserializer;
import org.mifosplatform.portfolio.loanaccount.domain.Loan;
import org.mifosplatform.portfolio.loanaccount.domain.LoanRepository;
import org.mifosplatform.portfolio.loanaccount.exception.LoanNotFoundException;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.dao.DataIntegrityViolationException;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
@Service
public class CollateralWritePlatformServiceJpaRepositoryImpl implements CollateralWritePlatformService {
private final static Logger logger = LoggerFactory.getLogger(CollateralWritePlatformServiceJpaRepositoryImpl.class);
private final PlatformSecurityContext context;
private final LoanRepository loanRepository;
private final LoanCollateralRepository collateralRepository;
private final CodeValueRepositoryWrapper codeValueRepository;
private final CollateralCommandFromApiJsonDeserializer collateralCommandFromApiJsonDeserializer;
@Autowired
public CollateralWritePlatformServiceJpaRepositoryImpl(final PlatformSecurityContext context, final LoanRepository loanRepository,
final LoanCollateralRepository collateralRepository, final CodeValueRepositoryWrapper codeValueRepository,
final CollateralCommandFromApiJsonDeserializer collateralCommandFromApiJsonDeserializer) {
this.context = context;
this.loanRepository = loanRepository;
this.collateralRepository = collateralRepository;
this.codeValueRepository = codeValueRepository;
this.collateralCommandFromApiJsonDeserializer = collateralCommandFromApiJsonDeserializer;
}
@Transactional
@Override
public CommandProcessingResult addCollateral(final Long loanId, final JsonCommand command) {
this.context.authenticatedUser();
final CollateralCommand collateralCommand = this.collateralCommandFromApiJsonDeserializer.commandFromApiJson(command.json());
collateralCommand.validateForCreate();
try {
final Loan loan = this.loanRepository.findOne(loanId);
if (loan == null) { throw new LoanNotFoundException(loanId); }
// TODO Vishwas, need to check if the codevalue is of the right code
// (same fix needed in client Identifiers)
final CodeValue collateralType = this.codeValueRepository.findOneWithNotFoundDetection(collateralCommand.getCollateralTypeId());
final LoanCollateral collateral = LoanCollateral.fromJson(loan, collateralType, command);
this.collateralRepository.save(collateral);
return new CommandProcessingResultBuilder() //
.withCommandId(command.commandId()) //
.withLoanId(loan.getId())//
.withEntityId(collateral.getId()) //
.build();
} catch (final DataIntegrityViolationException dve) {
handleCollateralDataIntegrityViolation(dve);
return CommandProcessingResult.empty();
}
}
@Transactional
@Override
public CommandProcessingResult updateCollateral(final Long loanId, final Long collateralId, final JsonCommand command) {
this.context.authenticatedUser();
final CollateralCommand collateralCommand = this.collateralCommandFromApiJsonDeserializer.commandFromApiJson(command.json());
collateralCommand.validateForUpdate();
Long collateralTypeId = collateralCommand.getCollateralTypeId();
try {
final Loan loan = this.loanRepository.findOne(loanId);
if (loan == null) { throw new LoanNotFoundException(loanId); }
CodeValue collateralType = null;
final LoanCollateral collateralForUpdate = this.collateralRepository.findOne(collateralId);
if (collateralForUpdate == null) { throw new CollateralNotFoundException(loanId, collateralId); }
final Map<String, Object> changes = collateralForUpdate.update(command);
if (changes.containsKey("collateralTypeId")) {
// TODO Vishwas, need to check if the codevalue is of the right
// code
// (same fix needed in client Identifiers)
collateralType = this.codeValueRepository.findOneWithNotFoundDetection(collateralTypeId);
if (collateralType == null) { throw new CodeValueNotFoundException(collateralTypeId); }
collateralTypeId = collateralType.getId();
collateralForUpdate.setCollateralType(collateralType);
}
if (!changes.isEmpty()) {
this.collateralRepository.saveAndFlush(collateralForUpdate);
}
return new CommandProcessingResultBuilder() //
.withCommandId(command.commandId()) //
.withLoanId(command.getLoanId())//
.withEntityId(collateralId) //
.with(changes) //
.build();
} catch (final DataIntegrityViolationException dve) {
handleCollateralDataIntegrityViolation(dve);
return new CommandProcessingResult(Long.valueOf(-1));
}
}
@Transactional
@Override
public CommandProcessingResult deleteCollateral(final Long loanId, final Long collateralId, final Long commandId) {
// TODO vishwas fetch collateral by loan and collateral Id
final Loan loan = this.loanRepository.findOne(loanId);
if (loan == null) { throw new LoanNotFoundException(loanId); }
final LoanCollateral collateral = this.collateralRepository.findOne(collateralId);
if (collateral == null) { throw new CollateralNotFoundException(loanId, collateralId); }
loan.getCollateral().remove(collateral);
this.collateralRepository.delete(collateral);
return new CommandProcessingResultBuilder().withCommandId(commandId).withLoanId(loanId).withEntityId(collateralId).build();
}
private void handleCollateralDataIntegrityViolation(final DataIntegrityViolationException dve) {
logAsErrorUnexpectedDataIntegrityException(dve);
throw new PlatformDataIntegrityException("error.msg.collateral.unknown.data.integrity.issue",
"Unknown data integrity issue with resource.");
}
private void logAsErrorUnexpectedDataIntegrityException(final DataIntegrityViolationException dve) {
logger.error(dve.getMessage(), dve);
}
}
@@ -45,11 +45,12 @@ import org.mifosplatform.organisation.staff.data.StaffData;
import org.mifosplatform.organisation.staff.service.StaffReadPlatformService;
import org.mifosplatform.portfolio.charge.data.ChargeData;
import org.mifosplatform.portfolio.charge.service.ChargeReadPlatformService;
import org.mifosplatform.portfolio.collateral.data.CollateralData;
import org.mifosplatform.portfolio.collateral.service.CollateralReadPlatformService;
import org.mifosplatform.portfolio.fund.data.FundData;
import org.mifosplatform.portfolio.fund.service.FundReadPlatformService;
import org.mifosplatform.portfolio.loanaccount.data.LoanAccountData;
import org.mifosplatform.portfolio.loanaccount.data.LoanChargeData;
import org.mifosplatform.portfolio.loanaccount.data.LoanCollateralData;
import org.mifosplatform.portfolio.loanaccount.data.LoanTransactionData;
import org.mifosplatform.portfolio.loanaccount.data.RepaymentScheduleRelatedLoanData;
import org.mifosplatform.portfolio.loanaccount.guarantor.data.GuarantorData;
@@ -57,7 +58,6 @@ import org.mifosplatform.portfolio.loanaccount.guarantor.service.GuarantorReadPl
import org.mifosplatform.portfolio.loanaccount.loanschedule.data.LoanScheduleData;
import org.mifosplatform.portfolio.loanaccount.loanschedule.service.LoanScheduleCalculationPlatformService;
import org.mifosplatform.portfolio.loanaccount.service.LoanChargeReadPlatformService;
import org.mifosplatform.portfolio.loanaccount.service.LoanCollateralReadPlatformService;
import org.mifosplatform.portfolio.loanaccount.service.LoanReadPlatformService;
import org.mifosplatform.portfolio.loanproduct.data.LoanProductData;
import org.mifosplatform.portfolio.loanproduct.data.TransactionProcessingStrategyData;
@@ -96,7 +96,7 @@ public class LoansApiResource {
private final FundReadPlatformService fundReadPlatformService;
private final ChargeReadPlatformService chargeReadPlatformService;
private final LoanChargeReadPlatformService loanChargeReadPlatformService;
private final LoanCollateralReadPlatformService loanCollateralReadPlatformService;
private final CollateralReadPlatformService loanCollateralReadPlatformService;
private final LoanScheduleCalculationPlatformService calculationPlatformService;
private final StaffReadPlatformService staffReadPlatformService;
private final GuarantorReadPlatformService guarantorReadPlatformService;
@@ -113,7 +113,7 @@ public class LoansApiResource {
final LoanProductReadPlatformService loanProductReadPlatformService,
final LoanDropdownReadPlatformService dropdownReadPlatformService, final FundReadPlatformService fundReadPlatformService,
final ChargeReadPlatformService chargeReadPlatformService, final LoanChargeReadPlatformService loanChargeReadPlatformService,
final LoanCollateralReadPlatformService loanCollateralReadPlatformService,
final CollateralReadPlatformService loanCollateralReadPlatformService,
final LoanScheduleCalculationPlatformService calculationPlatformService,
final StaffReadPlatformService staffReadPlatformService, final GuarantorReadPlatformService guarantorReadPlatformService,
final CodeValueReadPlatformService codeValueReadPlatformService,
@@ -157,7 +157,7 @@ public class LoansApiResource {
// associations
final LoanScheduleData repaymentSchedule = null;
final Collection<LoanTransactionData> loanRepayments = null;
final Collection<LoanCollateralData> collateral = null;
final Collection<CollateralData> collateral = null;
final Collection<GuarantorData> guarantors = null;
// options
@@ -245,7 +245,7 @@ public class LoansApiResource {
LoanScheduleData repaymentSchedule = null;
Collection<LoanChargeData> charges = null;
Collection<GuarantorData> guarantors = null;
Collection<LoanCollateralData> collateral = null;
Collection<CollateralData> collateral = null;
final Set<String> mandatoryResponseParameters = new HashSet<String>();
final Set<String> associationParameters = ApiParameterHelper.extractAssociationsForResponseIfProvided(uriInfo.getQueryParameters());
@@ -288,7 +288,7 @@ public class LoansApiResource {
if (associationParameters.contains("collateral")) {
mandatoryResponseParameters.add("collateral");
collateral = this.loanCollateralReadPlatformService.retrieveLoanCollateral(loanId);
collateral = this.loanCollateralReadPlatformService.retrieveCollaterals(loanId);
if (CollectionUtils.isEmpty(collateral)) {
collateral = null;
}
@@ -17,6 +17,7 @@ import org.mifosplatform.infrastructure.core.data.EnumOptionData;
import org.mifosplatform.organisation.monetary.data.CurrencyData;
import org.mifosplatform.organisation.staff.data.StaffData;
import org.mifosplatform.portfolio.charge.data.ChargeData;
import org.mifosplatform.portfolio.collateral.data.CollateralData;
import org.mifosplatform.portfolio.fund.data.FundData;
import org.mifosplatform.portfolio.loanaccount.guarantor.data.GuarantorData;
import org.mifosplatform.portfolio.loanaccount.loanschedule.data.LoanScheduleData;
@@ -88,7 +89,7 @@ public class LoanAccountData {
private final LoanScheduleData repaymentSchedule;
private final Collection<LoanTransactionData> transactions;
private final Collection<LoanChargeData> charges;
private final Collection<LoanCollateralData> collateral;
private final Collection<CollateralData> collateral;
private final Collection<GuarantorData> guarantors;
// template
@@ -157,7 +158,7 @@ public class LoanAccountData {
final LoanScheduleData repaymentSchedule = null;
final Collection<LoanTransactionData> transactions = null;
final Collection<LoanChargeData> charges = null;
final Collection<LoanCollateralData> collateral = null;
final Collection<CollateralData> collateral = null;
final Collection<GuarantorData> guarantors = null;
final Collection<LoanProductData> productOptions = null;
final Collection<EnumOptionData> termFrequencyTypeOptions = null;
@@ -231,7 +232,7 @@ public class LoanAccountData {
final LoanScheduleData repaymentSchedule = null;
final Collection<LoanTransactionData> transactions = null;
final Collection<LoanChargeData> charges = null;
final Collection<LoanCollateralData> collateral = null;
final Collection<CollateralData> collateral = null;
final Collection<GuarantorData> guarantors = null;
final Collection<LoanProductData> productOptions = null;
final Collection<EnumOptionData> termFrequencyTypeOptions = null;
@@ -307,7 +308,7 @@ public class LoanAccountData {
final LoanScheduleData repaymentSchedule = null;
final Collection<LoanTransactionData> transactions = null;
final Collection<LoanChargeData> charges = null;
final Collection<LoanCollateralData> collateral = null;
final Collection<CollateralData> collateral = null;
final Collection<GuarantorData> guarantors = null;
final Collection<LoanProductData> productOptions = null;
final Collection<EnumOptionData> termFrequencyTypeOptions = null;
@@ -340,7 +341,7 @@ public class LoanAccountData {
final LoanScheduleData repaymentSchedule = null;
final Collection<LoanTransactionData> transactions = null;
final Collection<LoanCollateralData> collateral = null;
final Collection<CollateralData> collateral = null;
final Collection<GuarantorData> guarantors = null;
final Collection<LoanProductData> productOptions = null;
final Collection<EnumOptionData> termFrequencyTypeOptions = null;
@@ -400,7 +401,7 @@ public class LoanAccountData {
final LoanScheduleData repaymentSchedule = null;
final Collection<LoanTransactionData> transactions = null;
final Collection<LoanChargeData> charges = null;
final Collection<LoanCollateralData> collateral = null;
final Collection<CollateralData> collateral = null;
final Collection<GuarantorData> guarantors = null;
final Collection<LoanProductData> productOptions = null;
final Collection<EnumOptionData> termFrequencyTypeOptions = null;
@@ -435,7 +436,7 @@ public class LoanAccountData {
*/
public static LoanAccountData associationsAndTemplate(final LoanAccountData acc, final LoanScheduleData repaymentSchedule,
final Collection<LoanTransactionData> transactions, final Collection<LoanChargeData> charges,
final Collection<LoanCollateralData> collateral, final Collection<GuarantorData> guarantors,
final Collection<CollateralData> collateral, final Collection<GuarantorData> guarantors,
final Collection<LoanProductData> productOptions, final Collection<EnumOptionData> termFrequencyTypeOptions,
final Collection<EnumOptionData> repaymentFrequencyTypeOptions,
final Collection<TransactionProcessingStrategyData> transactionProcessingStrategyOptions,
@@ -491,7 +492,7 @@ public class LoanAccountData {
final LocalDate interestChargedFromDate, final LoanApplicationTimelineData timeline, final LoanSummaryData summary,
final BigDecimal feeChargesDueAtDisbursementCharged, final LoanScheduleData repaymentSchedule,
final Collection<LoanTransactionData> transactions, final Collection<LoanChargeData> charges,
final Collection<LoanCollateralData> collateral, final Collection<GuarantorData> guarantors,
final Collection<CollateralData> collateral, final Collection<GuarantorData> guarantors,
final Collection<LoanProductData> productOptions, final Collection<EnumOptionData> termFrequencyTypeOptions,
final Collection<EnumOptionData> repaymentFrequencyTypeOptions,
final Collection<TransactionProcessingStrategyData> transactionProcessingStrategyOptions,
@@ -1,31 +0,0 @@
/**
* 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.loanaccount.data;
import org.mifosplatform.infrastructure.codes.data.CodeValueData;
/**
* Immutable data object for loan collateral data.
*/
public class LoanCollateralData {
@SuppressWarnings("unused")
private final Long id;
@SuppressWarnings("unused")
private final CodeValueData type;
@SuppressWarnings("unused")
private final String description;
public static LoanCollateralData instance(final Long id, final CodeValueData type, final String description) {
return new LoanCollateralData(id, type, description);
}
private LoanCollateralData(final Long id, final CodeValueData type, final String description) {
this.id = id;
this.type = type;
this.description = description;
}
}
@@ -51,10 +51,11 @@ import org.mifosplatform.organisation.monetary.domain.Money;
import org.mifosplatform.organisation.staff.domain.Staff;
import org.mifosplatform.portfolio.charge.exception.LoanChargeCannotBeAddedException;
import org.mifosplatform.portfolio.client.domain.Client;
import org.mifosplatform.portfolio.collateral.data.CollateralData;
import org.mifosplatform.portfolio.collateral.domain.LoanCollateral;
import org.mifosplatform.portfolio.fund.domain.Fund;
import org.mifosplatform.portfolio.group.domain.Group;
import org.mifosplatform.portfolio.loanaccount.command.LoanChargeCommand;
import org.mifosplatform.portfolio.loanaccount.data.LoanCollateralData;
import org.mifosplatform.portfolio.loanaccount.exception.InvalidLoanStateTransitionException;
import org.mifosplatform.portfolio.loanaccount.exception.InvalidLoanTransactionTypeException;
import org.mifosplatform.portfolio.loanaccount.exception.LoanOfficerAssignmentDateException;
@@ -962,19 +963,19 @@ public class Loan extends AbstractPersistable<Long> {
return loanCharges;
}
private LoanCollateralData[] listOfLoanCollateralData(final Set<LoanCollateral> setOfLoanCollateral) {
private CollateralData[] listOfLoanCollateralData(final Set<LoanCollateral> setOfLoanCollateral) {
LoanCollateralData[] existingLoanCollateral = null;
CollateralData[] existingLoanCollateral = null;
List<LoanCollateralData> loanCollateralList = new ArrayList<LoanCollateralData>();
List<CollateralData> loanCollateralList = new ArrayList<CollateralData>();
for (LoanCollateral loanCollateral : setOfLoanCollateral) {
LoanCollateralData data = loanCollateral.toData();
CollateralData data = loanCollateral.toData();
loanCollateralList.add(data);
}
existingLoanCollateral = loanCollateralList.toArray(new LoanCollateralData[loanCollateralList.size()]);
existingLoanCollateral = loanCollateralList.toArray(new CollateralData[loanCollateralList.size()]);
return existingLoanCollateral;
}
@@ -2248,6 +2249,10 @@ public class Loan extends AbstractPersistable<Long> {
return this.summary;
}
public Set<LoanCollateral> getCollateral() {
return this.collateral;
}
public Map<String, Object> deriveAccountingBridgeData(final CurrencyData currencyData, final List<Long> existingTransactionIds,
final List<Long> existingReversedTransactionIds) {
@@ -12,7 +12,7 @@ import org.mifosplatform.portfolio.loanaccount.guarantor.data.GuarantorData;
public interface GuarantorReadPlatformService {
/**
* Validates the passed in loanId before retrieving Loans for the same
* Validates the passed in loanId before retrieving Guarantors for the same
*
* @param loanId
* @return
@@ -34,11 +34,12 @@ import org.mifosplatform.portfolio.client.domain.AccountNumberGeneratorFactory;
import org.mifosplatform.portfolio.client.domain.Client;
import org.mifosplatform.portfolio.client.domain.ClientRepository;
import org.mifosplatform.portfolio.client.exception.ClientNotFoundException;
import org.mifosplatform.portfolio.collateral.domain.LoanCollateral;
import org.mifosplatform.portfolio.collateral.service.CollateralAssembler;
import org.mifosplatform.portfolio.fund.domain.Fund;
import org.mifosplatform.portfolio.loanaccount.domain.DefaultLoanLifecycleStateMachine;
import org.mifosplatform.portfolio.loanaccount.domain.Loan;
import org.mifosplatform.portfolio.loanaccount.domain.LoanCharge;
import org.mifosplatform.portfolio.loanaccount.domain.LoanCollateral;
import org.mifosplatform.portfolio.loanaccount.domain.LoanLifecycleStateMachine;
import org.mifosplatform.portfolio.loanaccount.domain.LoanRepaymentScheduleTransactionProcessorFactory;
import org.mifosplatform.portfolio.loanaccount.domain.LoanRepository;
@@ -84,7 +85,7 @@ public class LoanApplicationWritePlatformServiceJpaRepositoryImpl implements Loa
private final ClientRepository clientRepository;
private final LoanProductRepository loanProductRepository;
private final LoanChargeAssembler loanChargeAssembler;
private final LoanCollateralAssembler loanCollateralAssembler;
private final CollateralAssembler loanCollateralAssembler;
private final AprCalculator aprCalculator;
private final AccountNumberGeneratorFactory accountIdentifierGeneratorFactory;
private final LoanSummaryWrapper loanSummaryWrapper;
@@ -97,7 +98,7 @@ public class LoanApplicationWritePlatformServiceJpaRepositoryImpl implements Loa
final LoanApplicationTransitionApiJsonValidator loanApplicationTransitionApiJsonValidator,
final LoanApplicationCommandFromApiJsonHelper fromApiJsonDeserializer, final AprCalculator aprCalculator,
final LoanAssembler loanAssembler, final LoanChargeAssembler loanChargeAssembler,
final LoanCollateralAssembler loanCollateralAssembler, final LoanRepository loanRepository,
final CollateralAssembler loanCollateralAssembler, final LoanRepository loanRepository,
final NoteRepository noteRepository, final LoanScheduleCalculationPlatformService calculationPlatformService,
final ClientRepository clientRepository, final LoanProductRepository loanProductRepository,
final AccountNumberGeneratorFactory accountIdentifierGeneratorFactory, final LoanSummaryWrapper loanSummaryWrapper,
@@ -22,6 +22,8 @@ import org.mifosplatform.organisation.staff.exception.StaffRoleException;
import org.mifosplatform.portfolio.client.domain.Client;
import org.mifosplatform.portfolio.client.domain.ClientRepository;
import org.mifosplatform.portfolio.client.exception.ClientNotFoundException;
import org.mifosplatform.portfolio.collateral.domain.LoanCollateral;
import org.mifosplatform.portfolio.collateral.service.CollateralAssembler;
import org.mifosplatform.portfolio.fund.domain.Fund;
import org.mifosplatform.portfolio.fund.domain.FundRepository;
import org.mifosplatform.portfolio.fund.exception.FundNotFoundException;
@@ -32,7 +34,6 @@ import org.mifosplatform.portfolio.group.exception.GroupNotFoundException;
import org.mifosplatform.portfolio.loanaccount.domain.DefaultLoanLifecycleStateMachine;
import org.mifosplatform.portfolio.loanaccount.domain.Loan;
import org.mifosplatform.portfolio.loanaccount.domain.LoanCharge;
import org.mifosplatform.portfolio.loanaccount.domain.LoanCollateral;
import org.mifosplatform.portfolio.loanaccount.domain.LoanLifecycleStateMachine;
import org.mifosplatform.portfolio.loanaccount.domain.LoanRepaymentScheduleTransactionProcessorFactory;
import org.mifosplatform.portfolio.loanaccount.domain.LoanStatus;
@@ -63,7 +64,7 @@ public class LoanAssembler {
private final CodeValueRepositoryWrapper codeValueRepository;
private final LoanScheduleAssembler loanScheduleAssembler;
private final LoanChargeAssembler loanChargeAssembler;
private final LoanCollateralAssembler loanCollateralAssembler;
private final CollateralAssembler loanCollateralAssembler;
private final FromJsonHelper fromApiJsonHelper;
private final LoanSummaryWrapper loanSummaryWrapper;
private final LoanRepaymentScheduleTransactionProcessorFactory loanRepaymentScheduleTransactionProcessorFactory;
@@ -74,7 +75,7 @@ public class LoanAssembler {
final LoanTransactionProcessingStrategyRepository loanTransactionProcessingStrategyRepository,
final StaffRepository staffRepository, final CodeValueRepositoryWrapper codeValueRepository,
final LoanScheduleAssembler loanScheduleAssembler, final LoanChargeAssembler loanChargeAssembler,
final LoanCollateralAssembler loanCollateralAssembler, final LoanSummaryWrapper loanSummaryWrapper,
final CollateralAssembler loanCollateralAssembler, final LoanSummaryWrapper loanSummaryWrapper,
final LoanRepaymentScheduleTransactionProcessorFactory loanRepaymentScheduleTransactionProcessorFactory) {
this.fromApiJsonHelper = fromApiJsonHelper;
this.loanProductRepository = loanProductRepository;
@@ -1,15 +0,0 @@
/**
* 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.loanaccount.service;
import java.util.Collection;
import org.mifosplatform.portfolio.loanaccount.data.LoanCollateralData;
public interface LoanCollateralReadPlatformService {
Collection<LoanCollateralData> retrieveLoanCollateral(Long loanId);
}
@@ -1,68 +0,0 @@
/**
* 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.loanaccount.service;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.util.Collection;
import org.mifosplatform.infrastructure.codes.data.CodeValueData;
import org.mifosplatform.infrastructure.core.service.TenantAwareRoutingDataSource;
import org.mifosplatform.infrastructure.security.service.PlatformSecurityContext;
import org.mifosplatform.portfolio.loanaccount.data.LoanCollateralData;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.jdbc.core.JdbcTemplate;
import org.springframework.jdbc.core.RowMapper;
import org.springframework.stereotype.Service;
@Service
public class LoanCollateralReadPlatformServiceImpl implements LoanCollateralReadPlatformService {
private final JdbcTemplate jdbcTemplate;
private final PlatformSecurityContext context;
@Autowired
public LoanCollateralReadPlatformServiceImpl(final PlatformSecurityContext context, final TenantAwareRoutingDataSource dataSource) {
this.context = context;
this.jdbcTemplate = new JdbcTemplate(dataSource);
}
private static final class LoanCollateralMapper implements RowMapper<LoanCollateralData> {
private StringBuilder sqlBuilder = new StringBuilder(
"lc.id as id, lc.description as description, cv.id as typeId, cv.code_value as typeName") //
.append(" FROM m_loan_collateral lc") //
.append(" JOIN m_code_value cv on lc.type_cv_id = cv.id");
public String schema() {
return sqlBuilder.toString();
}
@Override
public LoanCollateralData mapRow(final ResultSet rs, @SuppressWarnings("unused") final int rowNum) throws SQLException {
final Long id = rs.getLong("id");
final String name = rs.getString("description");
final Long typeId = rs.getLong("typeId");
final String typeName = rs.getString("typeName");
final CodeValueData type = CodeValueData.instance(typeId, typeName);
return LoanCollateralData.instance(id, type, name);
}
}
@Override
public Collection<LoanCollateralData> retrieveLoanCollateral(final Long loanId) {
this.context.authenticatedUser();
final LoanCollateralMapper rm = new LoanCollateralMapper();
final String sql = "select " + rm.schema() + " where lc.loan_id=? order by id ASC";
return this.jdbcTemplate.query(sql, rm, new Object[] { loanId });
}
}