MIFOSX-97: inital pass at support for maker-checker and audit around loancharges.

This commit is contained in:
Keith Woodlock
2012-12-20 00:28:39 +00:00
parent e694355f8c
commit a43490102d
23 changed files with 515 additions and 540 deletions
@@ -215,4 +215,20 @@ public class CommandWrapper {
public boolean isCloseLoanAsRescheduled() {
return this.actionName.equalsIgnoreCase("CLOSEASRESCHEDULED") && this.entityName.equalsIgnoreCase("LOAN");
}
public boolean isAddLoanCharge() {
return this.actionName.equalsIgnoreCase("CREATE") && this.entityName.equalsIgnoreCase("LOANCHARGE");
}
public boolean isDeleteLoanCharge() {
return this.actionName.equalsIgnoreCase("DELETE") && this.entityName.equalsIgnoreCase("LOANCHARGE");
}
public boolean isUpdateLoanCharge() {
return this.actionName.equalsIgnoreCase("UPDATE") && this.entityName.equalsIgnoreCase("LOANCHARGE");
}
public boolean isWaiveLoanCharge() {
return this.actionName.equalsIgnoreCase("WAIVE") && this.entityName.equalsIgnoreCase("LOANCHARGE");
}
}
@@ -236,6 +236,14 @@ public class SynchronousCommandProcessingService implements CommandProcessingSer
handler = applicationContext.getBean("closeLoanCommandHandler", NewCommandSourceHandler.class);
} else if (wrapper.isCloseLoanAsRescheduled()) {
handler = applicationContext.getBean("closeLoanAsRescheduledCommandHandler", NewCommandSourceHandler.class);
} else if (wrapper.isAddLoanCharge()) {
handler = applicationContext.getBean("addLoanChargeCommandHandler", NewCommandSourceHandler.class);
} else if (wrapper.isDeleteLoanCharge()) {
handler = applicationContext.getBean("deleteLoanChargeCommandHandler", NewCommandSourceHandler.class);
} else if (wrapper.isUpdateLoanCharge()) {
handler = applicationContext.getBean("updateLoanChargeCommandHandler", NewCommandSourceHandler.class);
} else if (wrapper.isWaiveLoanCharge()) {
handler = applicationContext.getBean("waiveLoanChargeCommandHandler", NewCommandSourceHandler.class);
} else if (wrapper.isCreate()) {
handler = applicationContext.getBean("createLoanApplicationCommandHandler", NewCommandSourceHandler.class);
} else if (wrapper.isUpdate()) {
@@ -15,7 +15,6 @@ import org.mifosplatform.organisation.staff.data.StaffData;
import org.mifosplatform.portfolio.client.data.ClientAccountSummaryCollectionData;
import org.mifosplatform.portfolio.group.data.GroupAccountSummaryCollectionData;
import org.mifosplatform.portfolio.group.data.GroupData;
import org.mifosplatform.portfolio.loanaccount.data.LoanChargeData;
import org.mifosplatform.portfolio.loanaccount.gaurantor.data.GuarantorData;
import org.mifosplatform.portfolio.savingsaccount.data.SavingAccountData;
import org.mifosplatform.portfolio.savingsaccount.data.SavingScheduleData;
@@ -80,8 +79,6 @@ public class GoogleGsonPortfolioApiJsonSerializerService implements PortfolioApi
private static final Set<String> LOAN_REASSIGNMENT_DATA_PARAMETERS = new HashSet<String>(Arrays.asList("officeId", "fromLoanOfficerId",
"assignmentDate", "officeOptions", "loanOfficerOptions", "accountSummaryCollection"));
private static final Set<String> LOAN_CHARGES_DATA_PARAMETERS = new HashSet<String>(Arrays.asList("chargeOptions"));
private static final Set<String> SAVINGS_ACCOUNTS_DATA_PARAMETERS = new HashSet<String>(Arrays.asList("id", "status", "externalId",
"clientId", "clientName", "productId", "productName", "productType", "currencyData", "savingsDepostiAmountPerPeriod",
"savingsFrequencyType", "totalDepositAmount", "reccuringInterestRate", "savingInterestRate", "interestType",
@@ -210,13 +207,6 @@ public class GoogleGsonPortfolioApiJsonSerializerService implements PortfolioApi
return helper.serializedJsonFrom(gsonDeserializer, loanReassignmentData);
}
@Override
public String serializeLoanChargeDataToJson(boolean prettyPrint, Set<String> responseParameters, LoanChargeData charge) {
final Gson gsonDeserializer = helper.createGsonBuilderWithParameterExclusionSerializationStrategy(LOAN_CHARGES_DATA_PARAMETERS,
prettyPrint, responseParameters);
return helper.serializedJsonFrom(gsonDeserializer, charge);
}
@Override
public String serializeStaffDataToJson(boolean prettyPrint, Set<String> responseParameters, StaffData staff) {
final Gson gsonDeserializer = helper.createGsonBuilderWithParameterExclusionSerializationStrategy(STAFF_DATA_PARAMETERS,
@@ -4,7 +4,6 @@ import org.mifosplatform.organisation.staff.command.BulkTransferLoanOfficerComma
import org.mifosplatform.portfolio.client.command.NoteCommand;
import org.mifosplatform.portfolio.client.data.ClientData;
import org.mifosplatform.portfolio.group.command.GroupCommand;
import org.mifosplatform.portfolio.loanaccount.command.LoanChargeCommand;
import org.mifosplatform.portfolio.loanaccount.gaurantor.command.GuarantorCommand;
import org.mifosplatform.portfolio.savingsaccount.command.SavingAccountCommand;
import org.mifosplatform.portfolio.savingsaccountproduct.command.SavingProductCommand;
@@ -25,8 +24,6 @@ public interface PortfolioApiDataConversionService {
GroupCommand convertJsonToGroupCommand(Long resourceIdentifier, String json);
LoanChargeCommand convertJsonToLoanChargeCommand(Long loanChargeId, Long loanId, String json);
NoteCommand convertJsonToNoteCommand(Long resourceIdentifier, Long clientId, String json);
DepositAccountCommand convertJsonToDepositAccountCommand(Long resourceIdentifier, String json);
@@ -27,7 +27,6 @@ import org.mifosplatform.portfolio.client.command.NoteCommand;
import org.mifosplatform.portfolio.client.data.ClientData;
import org.mifosplatform.portfolio.client.serialization.ClientCommandFromApiJsonDeserializer;
import org.mifosplatform.portfolio.group.command.GroupCommand;
import org.mifosplatform.portfolio.loanaccount.command.LoanChargeCommand;
import org.mifosplatform.portfolio.loanaccount.gaurantor.command.GuarantorCommand;
import org.mifosplatform.portfolio.savingsaccount.command.SavingAccountCommand;
import org.mifosplatform.portfolio.savingsaccountproduct.command.SavingProductCommand;
@@ -173,34 +172,6 @@ public class PortfolioApiDataConversionServiceImpl implements PortfolioApiDataCo
return new GroupCommand(modifiedParameters, resourceIdentifier, externalId, name, officeId, clientMembers);
}
/**
* @deprecated - to be removed soon
*/
@Deprecated
@Override
public LoanChargeCommand convertJsonToLoanChargeCommand(final Long loanChargeId, final Long loanId, final String json) {
if (StringUtils.isBlank(json)) { throw new InvalidJsonException(); }
Type typeOfMap = new TypeToken<Map<String, String>>() {}.getType();
Map<String, String> requestMap = gsonConverter.fromJson(json, typeOfMap);
final Set<String> supportedParams = new HashSet<String>(Arrays.asList("chargeId", "amount", "chargeTimeType",
"chargeCalculationType", "specifiedDueDate", "locale", "dateFormat"));
checkForUnsupportedParameters(requestMap, supportedParams);
Set<String> modifiedParameters = new HashSet<String>();
Long chargeId = extractLongParameter("chargeId", requestMap, modifiedParameters);
BigDecimal amount = extractBigDecimalParameter("amount", requestMap, modifiedParameters);
Integer chargeTimeType = extractIntegerParameter("chargeTimeType", requestMap, modifiedParameters);
Integer chargeCalculationType = extractIntegerParameter("chargeCalculationType", requestMap, modifiedParameters);
final LocalDate submittedOnDate = extractLocalDateParameter("specifiedDueDate", requestMap, modifiedParameters);
return new LoanChargeCommand(modifiedParameters, loanChargeId, loanId, chargeId, amount, chargeTimeType, chargeCalculationType,
submittedOnDate);
}
@Override
public NoteCommand convertJsonToNoteCommand(final Long noteId, final Long clientId, final String json) {
if (StringUtils.isBlank(json)) { throw new InvalidJsonException(); }
@@ -12,7 +12,6 @@ import org.mifosplatform.organisation.staff.data.StaffData;
import org.mifosplatform.portfolio.client.data.ClientAccountSummaryCollectionData;
import org.mifosplatform.portfolio.group.data.GroupAccountSummaryCollectionData;
import org.mifosplatform.portfolio.group.data.GroupData;
import org.mifosplatform.portfolio.loanaccount.data.LoanChargeData;
import org.mifosplatform.portfolio.loanaccount.gaurantor.data.GuarantorData;
import org.mifosplatform.portfolio.savingsaccount.data.SavingAccountData;
import org.mifosplatform.portfolio.savingsaccount.data.SavingScheduleData;
@@ -53,8 +52,6 @@ public interface PortfolioApiJsonSerializerService {
String serializeLoanReassignmentDataToJson(boolean prettyPrint, Set<String> responseParameters,
BulkTransferLoanOfficerData loanReassignmentData);
String serializeLoanChargeDataToJson(boolean prettyPrint, Set<String> responseParameters, LoanChargeData charge);
String serializeStaffDataToJson(boolean prettyPrint, Set<String> responseParameters, StaffData staff);
String serializeStaffDataToJson(boolean prettyPrint, Set<String> responseParameters, Collection<StaffData> staff);
@@ -1,6 +1,8 @@
package org.mifosplatform.portfolio.loanaccount.api;
import java.util.Arrays;
import java.util.Collection;
import java.util.HashSet;
import java.util.Set;
import javax.ws.rs.Consumes;
@@ -14,23 +16,19 @@ import javax.ws.rs.Produces;
import javax.ws.rs.QueryParam;
import javax.ws.rs.core.Context;
import javax.ws.rs.core.MediaType;
import javax.ws.rs.core.Response;
import javax.ws.rs.core.UriInfo;
import org.apache.commons.lang.StringUtils;
import org.mifosplatform.infrastructure.core.api.ApiParameterHelper;
import org.mifosplatform.infrastructure.core.api.PortfolioApiDataConversionService;
import org.mifosplatform.infrastructure.core.api.PortfolioApiJsonSerializerService;
import org.mifosplatform.commands.service.PortfolioCommandSourceWritePlatformService;
import org.mifosplatform.infrastructure.core.api.ApiRequestParameterHelper;
import org.mifosplatform.infrastructure.core.data.EntityIdentifier;
import org.mifosplatform.infrastructure.core.exception.UnrecognizedQueryParamException;
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.charge.data.ChargeData;
import org.mifosplatform.portfolio.charge.service.ChargeReadPlatformService;
import org.mifosplatform.portfolio.loanaccount.command.LoanChargeCommand;
import org.mifosplatform.portfolio.loanaccount.data.LoanAccountData;
import org.mifosplatform.portfolio.loanaccount.data.LoanChargeData;
import org.mifosplatform.portfolio.loanaccount.service.LoanWritePlatformService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Scope;
import org.springframework.stereotype.Component;
@@ -40,102 +38,87 @@ import org.springframework.stereotype.Component;
@Scope("singleton")
public class LoanChargesApiResource {
private final Set<String> RESPONSE_DATA_PARAMETERS = new HashSet<String>(Arrays.asList("id", "chargeId", "name", "penalty",
"chargeTimeType", "dueAsOfDate", "chargeCalculationType", "percentage", "amountPercentageAppliedTo", "currency",
"amountWaived", "amountWrittenOff", "amountOutstanding", "amountOrPercentage", "amount", "amountPaid", "chargeOptions"));
private final String resourceNameForPermissions = "LOAN";
private final PlatformSecurityContext context;
private final LoanWritePlatformService loanWritePlatformService;
private final ChargeReadPlatformService chargeReadPlatformService;
private final PortfolioApiJsonSerializerService apiJsonSerializerService;
private final PortfolioApiDataConversionService apiDataConversionService;
private final DefaultToApiJsonSerializer<LoanAccountData> toApiJsonSerializer;
// private final ApiRequestParameterHelper apiRequestParameterHelper;
// private final FromJsonHelper fromJsonHelper;
// private final PortfolioCommandSourceWritePlatformService commandsSourceWritePlatformService;
private final DefaultToApiJsonSerializer<LoanChargeData> toApiJsonSerializer;
private final ApiRequestParameterHelper apiRequestParameterHelper;
private final PortfolioCommandSourceWritePlatformService commandsSourceWritePlatformService;
@Autowired
public LoanChargesApiResource(final PlatformSecurityContext context, final LoanWritePlatformService loanWritePlatformService,
final ChargeReadPlatformService chargeReadPlatformService,
final DefaultToApiJsonSerializer<LoanAccountData> toApiJsonSerializer,
// final ApiRequestParameterHelper apiRequestParameterHelper,
final PortfolioApiJsonSerializerService apiJsonSerializerService,
final PortfolioApiDataConversionService apiDataConversionService
// , final FromJsonHelper fromJsonHelper,
// final PortfolioCommandSourceWritePlatformService
// commandsSourceWritePlatformService
) {
public LoanChargesApiResource(final PlatformSecurityContext context, final ChargeReadPlatformService chargeReadPlatformService,
final DefaultToApiJsonSerializer<LoanChargeData> toApiJsonSerializer,
final ApiRequestParameterHelper apiRequestParameterHelper,
final PortfolioCommandSourceWritePlatformService commandsSourceWritePlatformService) {
this.context = context;
this.loanWritePlatformService = loanWritePlatformService;
this.chargeReadPlatformService = chargeReadPlatformService;
this.toApiJsonSerializer = toApiJsonSerializer;
// this.apiRequestParameterHelper = apiRequestParameterHelper;
this.apiJsonSerializerService = apiJsonSerializerService;
this.apiDataConversionService = apiDataConversionService;
// this.fromJsonHelper = fromJsonHelper;
// this.commandsSourceWritePlatformService = commandsSourceWritePlatformService;
this.apiRequestParameterHelper = apiRequestParameterHelper;
this.commandsSourceWritePlatformService = commandsSourceWritePlatformService;
}
private boolean is(final String commandParam, final String commandValue) {
return StringUtils.isNotBlank(commandParam) && commandParam.trim().equalsIgnoreCase(commandValue);
}
@POST
@Consumes({ MediaType.APPLICATION_JSON })
@Produces({ MediaType.APPLICATION_JSON })
public Response addLoanCharge(@PathParam("loanId") final Long loanId, final String jsonRequestBody) {
final LoanChargeCommand command = this.apiDataConversionService.convertJsonToLoanChargeCommand(null, loanId, jsonRequestBody);
final EntityIdentifier identifier = this.loanWritePlatformService.addLoanCharge(command);
return Response.ok().entity(identifier).build();
}
@GET
@Path("template")
@Consumes({ MediaType.APPLICATION_JSON })
@Produces({ MediaType.APPLICATION_JSON })
public String retrieveNewLoanChargeDetails(@Context final UriInfo uriInfo) {
context.authenticatedUser().validateHasReadPermission("LOAN");
final Set<String> responseParameters = ApiParameterHelper.extractFieldsForResponseIfProvided(uriInfo.getQueryParameters());
final boolean prettyPrint = ApiParameterHelper.prettyPrint(uriInfo.getQueryParameters());
context.authenticatedUser().validateHasReadPermission(resourceNameForPermissions);
final boolean feeChargesOnly = false;
final Collection<ChargeData> chargeOptions = this.chargeReadPlatformService.retrieveLoanApplicableCharges(feeChargesOnly);
final LoanChargeData loanChargeTemplate = LoanChargeData.template(chargeOptions);
return this.apiJsonSerializerService.serializeLoanChargeDataToJson(prettyPrint, responseParameters, loanChargeTemplate);
final ApiRequestJsonSerializationSettings settings = apiRequestParameterHelper.process(uriInfo.getQueryParameters());
return this.toApiJsonSerializer.serialize(settings, loanChargeTemplate, RESPONSE_DATA_PARAMETERS);
}
@GET
@Path("{chargeId}")
@Path("{loanChargeId}")
@Consumes({ MediaType.APPLICATION_JSON })
@Produces({ MediaType.APPLICATION_JSON })
public String retrieveLoanCharge(@PathParam("loanId") final Long loanId, @PathParam("chargeId") final Long loanChargeId,
public String retrieveLoanCharge(@PathParam("loanId") final Long loanId, @PathParam("loanChargeId") final Long loanChargeId,
@Context final UriInfo uriInfo) {
context.authenticatedUser().validateHasReadPermission("LOAN");
final Set<String> responseParameters = ApiParameterHelper.extractFieldsForResponseIfProvided(uriInfo.getQueryParameters());
final boolean prettyPrint = ApiParameterHelper.prettyPrint(uriInfo.getQueryParameters());
context.authenticatedUser().validateHasReadPermission(resourceNameForPermissions);
final LoanChargeData loanCharge = this.chargeReadPlatformService.retrieveLoanChargeDetails(loanChargeId, loanId);
return this.apiJsonSerializerService.serializeLoanChargeDataToJson(prettyPrint, responseParameters, loanCharge);
final ApiRequestJsonSerializationSettings settings = apiRequestParameterHelper.process(uriInfo.getQueryParameters());
return this.toApiJsonSerializer.serialize(settings, loanCharge, RESPONSE_DATA_PARAMETERS);
}
@POST
@Consumes({ MediaType.APPLICATION_JSON })
@Produces({ MediaType.APPLICATION_JSON })
public String addLoanCharge(@PathParam("loanId") final Long loanId, final String apiRequestBodyAsJson) {
final EntityIdentifier result = this.commandsSourceWritePlatformService.logCommandSource("CREATE", "LOANCHARGE", "N/A", "loans",
loanId, "charges", null, apiRequestBodyAsJson);
return this.toApiJsonSerializer.serialize(result);
}
@PUT
@Path("{chargeId}")
@Path("{loanChargeId}")
@Consumes({ MediaType.APPLICATION_JSON })
@Produces({ MediaType.APPLICATION_JSON })
public String updateLoanCharge(@PathParam("loanId") final Long loanId, @PathParam("chargeId") final Long loanChargeId,
final String jsonRequestBody) {
public String updateLoanCharge(@PathParam("loanId") final Long loanId, @PathParam("loanChargeId") final Long loanChargeId,
final String apiRequestBodyAsJson) {
final LoanChargeCommand command = this.apiDataConversionService.convertJsonToLoanChargeCommand(loanChargeId, loanId,
jsonRequestBody);
final EntityIdentifier result = this.commandsSourceWritePlatformService.logCommandSource("UPDATE", "LOANCHARGE", "N/A", "loans",
loanId, "charges", loanChargeId, apiRequestBodyAsJson);
final EntityIdentifier identifier = this.loanWritePlatformService.updateLoanCharge(command);
return this.toApiJsonSerializer.serialize(identifier);
return this.toApiJsonSerializer.serialize(result);
}
@POST
@@ -145,12 +128,12 @@ public class LoanChargesApiResource {
public String waiveLoanCharge(@PathParam("loanId") final Long loanId, @PathParam("chargeId") final Long loanChargeId,
@QueryParam("command") final String commandParam) {
final LoanChargeCommand command = LoanChargeCommand.forWaiver(loanChargeId, loanId);
String json = "";
if (is(commandParam, "waive")) {
final EntityIdentifier identifier = this.loanWritePlatformService.waiveLoanCharge(command);
json = this.toApiJsonSerializer.serialize(identifier);
final EntityIdentifier result = this.commandsSourceWritePlatformService.logCommandSource("WAIVE", "LOANCHARGE", "N/A", "loans",
loanId, "charges", loanChargeId, "{}");
json = this.toApiJsonSerializer.serialize(result);
} else {
throw new UnrecognizedQueryParamException("command", commandParam);
}
@@ -164,7 +147,9 @@ public class LoanChargesApiResource {
@Produces({ MediaType.APPLICATION_JSON })
public String deleteLoanCharge(@PathParam("loanId") final Long loanId, @PathParam("chargeId") final Long loanChargeId) {
final EntityIdentifier identifier = this.loanWritePlatformService.deleteLoanCharge(loanId, loanChargeId);
return this.toApiJsonSerializer.serialize(identifier);
final EntityIdentifier result = this.commandsSourceWritePlatformService.logCommandSource("DELETE", "LOANCHARGE", "N/A", "loans",
loanId, "charges", loanChargeId, "{}");
return this.toApiJsonSerializer.serialize(result);
}
}
@@ -30,8 +30,11 @@ import org.springframework.context.annotation.Scope;
import org.springframework.stereotype.Component;
// FIXME: - undo disbursal fails when transactions have notes against them
// FIXME: - repayments before disbursement date allowed
// FIXME: - modifying loan after disbursement
// FIXME: - does not take into account 'actual disbursement' date being different to 'expected'
// FIXME: - the schedule is 'generated' rather than been read from current loan schedule
// FIXME: - should not allow modify loan after disbursal (should be only restructure/reschedule)
// FIXME: - ui problem with default date for disburse dialog on some screens
@Path("/loans/{loanId}/transactions")
@Component
@Scope("singleton")
@@ -289,8 +289,7 @@ public class LoanApplicationCommand {
if (this.charges != null) {
for (LoanChargeCommand loanChargeCommand : this.charges) {
try {
LoanChargeCommandValidator validator = new LoanChargeCommandValidator(loanChargeCommand);
validator.validateForCreate();
loanChargeCommand.validateForCreate();
} catch (PlatformApiDataValidationException e) {
dataValidationErrors.addAll(e.getErrors());
}
@@ -1,49 +1,34 @@
package org.mifosplatform.portfolio.loanaccount.command;
import java.math.BigDecimal;
import java.util.HashSet;
import java.util.Set;
import java.util.ArrayList;
import java.util.List;
import org.joda.time.LocalDate;
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 and updating loan charges.
*/
public class LoanChargeCommand implements Comparable<LoanChargeCommand> {
private final Long id;
private final Long chargeId;
private final Long loanId;
private final BigDecimal amount;
private final Integer chargeTimeType;
private final LocalDate specifiedDueDate;
private final Integer chargeCalculationType;
/**
* Used to capture what parameters were passed in the json api request. It
* does not indicate that these values are modified from their original
* values when tyring to update.
*/
private final Set<String> requestParameters;
public static LoanChargeCommand forWaiver(final Long id, final Long loanId) {
final Set<String> parametersPassedInCommand = new HashSet<String>();
return new LoanChargeCommand(parametersPassedInCommand, id, loanId, null, null, null, null, null);
}
public LoanChargeCommand(final Set<String> parametersPassedInCommand, final Long id, final Long loanId, final Long chargeId,
final BigDecimal amount, final Integer chargeTimeType, final Integer chargeCalculationType, final LocalDate specifiedDueDate) {
this.requestParameters = parametersPassedInCommand;
this.id = id;
public LoanChargeCommand(final Long chargeId, final BigDecimal amount, final Integer chargeTimeType,
final Integer chargeCalculationType, final LocalDate specifiedDueDate) {
this.chargeId = chargeId;
this.loanId = loanId;
this.amount = amount;
this.chargeTimeType = chargeTimeType;
this.chargeCalculationType = chargeCalculationType;
this.specifiedDueDate = specifiedDueDate;
}
@Override
public int compareTo(final LoanChargeCommand o) {
int comparison = this.chargeId.compareTo(o.chargeId);
@@ -53,47 +38,38 @@ public class LoanChargeCommand implements Comparable<LoanChargeCommand> {
return comparison;
}
public Long getId() {
return id;
public void validateForCreate() {
List<ApiParameterError> dataValidationErrors = new ArrayList<ApiParameterError>();
DataValidatorBuilder baseDataValidator = new DataValidatorBuilder(dataValidationErrors).resource("charge");
baseDataValidator.reset().parameter("chargeId").value(this.chargeId).notNull().longGreaterThanZero();
baseDataValidator.reset().parameter("amount").value(this.amount).notNull().positiveAmount();
// baseDataValidator.reset().parameter("chargeTimeType").value(command.getChargeTimeType()).ignoreIfNull().inMinMaxRange(1,
// 2);
//
// if (command.getChargeTimeType().equals(Integer.valueOf(2))) {
// // date must be provided
// baseDataValidator.reset().parameter("specifiedDueDate").value(command.getSpecifiedDueDate()).notNull();
// }
//
// baseDataValidator.reset().parameter("chargeCalculationType").value(command.getChargeCalculationType()).ignoreIfNull().inMinMaxRange(1,
// 4);
if (!dataValidationErrors.isEmpty()) { throw new PlatformApiDataValidationException("validation.msg.validation.errors.exist",
"Validation errors exist.", dataValidationErrors); }
}
public Long getChargeId() {
return chargeId;
}
public void validateForUpdate() {
List<ApiParameterError> dataValidationErrors = new ArrayList<ApiParameterError>();
public Long getLoanId() {
return loanId;
}
DataValidatorBuilder baseDataValidator = new DataValidatorBuilder(dataValidationErrors).resource("charge");
public BigDecimal getAmount() {
return amount;
}
baseDataValidator.reset().parameter("amount").value(this.amount).ignoreIfNull().positiveAmount();
baseDataValidator.reset().parameter("chargeTimeType").value(this.chargeTimeType).ignoreIfNull().inMinMaxRange(1, 2);
baseDataValidator.reset().parameter("chargeCalculationType").value(this.chargeCalculationType).ignoreIfNull().inMinMaxRange(1, 4);
public Integer getChargeTimeType() {
return chargeTimeType;
}
public LocalDate getSpecifiedDueDate() {
return specifiedDueDate;
}
public Integer getChargeCalculationType() {
return chargeCalculationType;
}
public boolean isAmountChanged() {
return this.requestParameters.contains("amount");
}
public boolean isChargeTimeTypeChanged() {
return this.requestParameters.contains("chargeTimeType");
}
public boolean isSpecifiedDueDateChanged() {
return this.requestParameters.contains("specifiedDueDate");
}
public boolean isChargeCalculationTypeChanged() {
return this.requestParameters.contains("chargeCalculationType");
if (!dataValidationErrors.isEmpty()) { throw new PlatformApiDataValidationException("validation.msg.validation.errors.exist",
"Validation errors exist.", dataValidationErrors); }
}
}
@@ -1,52 +0,0 @@
package org.mifosplatform.portfolio.loanaccount.command;
import org.mifosplatform.infrastructure.core.data.ApiParameterError;
import org.mifosplatform.infrastructure.core.data.DataValidatorBuilder;
import org.mifosplatform.infrastructure.core.exception.PlatformApiDataValidationException;
import java.util.ArrayList;
import java.util.List;
public class LoanChargeCommandValidator {
private final LoanChargeCommand command;
public LoanChargeCommandValidator(final LoanChargeCommand command) {
this.command = command;
}
public void validateForCreate() {
List<ApiParameterError> dataValidationErrors = new ArrayList<ApiParameterError>();
DataValidatorBuilder baseDataValidator = new DataValidatorBuilder(dataValidationErrors).resource("charge");
baseDataValidator.reset().parameter("chargeId").value(command.getChargeId()).notNull().longGreaterThanZero();
baseDataValidator.reset().parameter("amount").value(command.getAmount()).notNull().positiveAmount();
// baseDataValidator.reset().parameter("chargeTimeType").value(command.getChargeTimeType()).ignoreIfNull().inMinMaxRange(1, 2);
//
// if (command.getChargeTimeType().equals(Integer.valueOf(2))) {
// // date must be provided
// baseDataValidator.reset().parameter("specifiedDueDate").value(command.getSpecifiedDueDate()).notNull();
// }
//
// baseDataValidator.reset().parameter("chargeCalculationType").value(command.getChargeCalculationType()).ignoreIfNull().inMinMaxRange(1, 4);
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("charge");
baseDataValidator.reset().parameter("amount").value(command.getAmount()).ignoreIfNull().positiveAmount();
baseDataValidator.reset().parameter("chargeTimeType").value(command.getChargeTimeType()).ignoreIfNull().inMinMaxRange(1, 2);
baseDataValidator.reset().parameter("chargeCalculationType").value(command.getChargeCalculationType()).ignoreIfNull().inMinMaxRange(1, 4);
if (!dataValidationErrors.isEmpty()) {
throw new PlatformApiDataValidationException("validation.msg.validation.errors.exist", "Validation errors exist.", dataValidationErrors);
}
}
}
@@ -13,122 +13,99 @@ import org.mifosplatform.portfolio.charge.data.ChargeData;
*/
public class LoanChargeData {
@SuppressWarnings("unused")
@SuppressWarnings("unused")
private final Long id;
@SuppressWarnings("unused")
@SuppressWarnings("unused")
private final Long chargeId;
@SuppressWarnings("unused")
@SuppressWarnings("unused")
private final String name;
@SuppressWarnings("unused")
@SuppressWarnings("unused")
private final EnumOptionData chargeTimeType;
@SuppressWarnings("unused")
private final LocalDate dueAsOfDate;
@SuppressWarnings("unused")
@SuppressWarnings("unused")
private final LocalDate dueAsOfDate;
@SuppressWarnings("unused")
private final EnumOptionData chargeCalculationType;
private final BigDecimal percentage;
@SuppressWarnings("unused")
private final BigDecimal amountPercentageAppliedTo;
@SuppressWarnings("unused")
private final BigDecimal percentage;
@SuppressWarnings("unused")
private final BigDecimal amountPercentageAppliedTo;
@SuppressWarnings("unused")
private final CurrencyData currency;
@SuppressWarnings("unused")
@SuppressWarnings("unused")
private final BigDecimal amount;
@SuppressWarnings("unused")
private final BigDecimal amountPaid;
@SuppressWarnings("unused")
private final BigDecimal amountWaived;
@SuppressWarnings("unused")
private final BigDecimal amountWrittenOff;
@SuppressWarnings("unused")
private final BigDecimal amountOutstanding;
@SuppressWarnings("unused")
private final BigDecimal amountOrPercentage;
@SuppressWarnings("unused")
private final Collection<ChargeData> chargeOptions;
@SuppressWarnings("unused")
private final boolean penalty;
private final BigDecimal amountPaid;
@SuppressWarnings("unused")
private final BigDecimal amountWaived;
@SuppressWarnings("unused")
private final BigDecimal amountWrittenOff;
public static LoanChargeData template(final Collection<ChargeData> chargeOptions){
return new LoanChargeData(null,null,null,null,null,null,null, chargeOptions, false);
@SuppressWarnings("unused")
private final BigDecimal amountOutstanding;
@SuppressWarnings("unused")
private final BigDecimal amountOrPercentage;
@SuppressWarnings("unused")
private final Collection<ChargeData> chargeOptions;
@SuppressWarnings("unused")
private final boolean penalty;
public static LoanChargeData template(final Collection<ChargeData> chargeOptions) {
return new LoanChargeData(null, null, null, null, null, null, null, chargeOptions, false);
}
/**
* used when populating with details from charge definition (for crud on charges)
*/
public static LoanChargeData newLoanChargeDetails(
final Long chargeId,
final String name,
final CurrencyData currency,
final BigDecimal value,
final EnumOptionData chargeTimeType,
final EnumOptionData chargeCalculationType,
final boolean penalty) {
return new LoanChargeData(null, chargeId, name, currency, value, chargeTimeType, chargeCalculationType, null, penalty);
}
public LoanChargeData(
final Long id,
final Long chargeId,
final String name,
final CurrencyData currency,
final BigDecimal amount,
final BigDecimal amountPaid,
final BigDecimal amountWaived,
final BigDecimal amountWrittenOff,
final BigDecimal amountOutstanding,
final EnumOptionData chargeTimeType,
final LocalDate dueAsOfDate,
final EnumOptionData chargeCalculationType,
final BigDecimal percentage,
final BigDecimal amountPercentageAppliedTo,
final boolean penalty) {
/**
* used when populating with details from charge definition (for crud on
* charges)
*/
public static LoanChargeData newLoanChargeDetails(final Long chargeId, final String name, final CurrencyData currency,
final BigDecimal value, final EnumOptionData chargeTimeType, final EnumOptionData chargeCalculationType, final boolean penalty) {
return new LoanChargeData(null, chargeId, name, currency, value, chargeTimeType, chargeCalculationType, null, penalty);
}
public LoanChargeData(final Long id, final Long chargeId, final String name, final CurrencyData currency, final BigDecimal amount,
final BigDecimal amountPaid, final BigDecimal amountWaived, final BigDecimal amountWrittenOff,
final BigDecimal amountOutstanding, final EnumOptionData chargeTimeType, final LocalDate dueAsOfDate,
final EnumOptionData chargeCalculationType, final BigDecimal percentage, final BigDecimal amountPercentageAppliedTo,
final boolean penalty) {
this.id = id;
this.chargeId = chargeId;
this.name = name;
this.currency = currency;
this.amount = amount;
this.amountPaid = amountPaid;
this.amountWaived = amountWaived;
this.amountWrittenOff = amountWrittenOff;
this.amountOutstanding = amountOutstanding;
this.amountPaid = amountPaid;
this.amountWaived = amountWaived;
this.amountWrittenOff = amountWrittenOff;
this.amountOutstanding = amountOutstanding;
this.chargeTimeType = chargeTimeType;
this.dueAsOfDate = dueAsOfDate;
this.dueAsOfDate = dueAsOfDate;
this.chargeCalculationType = chargeCalculationType;
this.percentage = percentage;
this.amountPercentageAppliedTo = amountPercentageAppliedTo;
this.penalty = penalty;
this.percentage = percentage;
this.amountPercentageAppliedTo = amountPercentageAppliedTo;
this.penalty = penalty;
if (chargeCalculationType != null && chargeCalculationType.getId().intValue() > 1) {
this.amountOrPercentage = this.percentage;
} else {
this.amountOrPercentage = amount;
}
if (chargeCalculationType != null && chargeCalculationType.getId().intValue() > 1) {
this.amountOrPercentage = this.percentage;
} else {
this.amountOrPercentage = amount;
}
this.chargeOptions = null;
}
private LoanChargeData(
final Long id,
final Long chargeId,
final String name,
final CurrencyData currency,
final BigDecimal amount,
final EnumOptionData chargeTimeType,
final EnumOptionData chargeCalculationType,
final Collection<ChargeData> chargeOptions,
private LoanChargeData(final Long id, final Long chargeId, final String name, final CurrencyData currency, final BigDecimal amount,
final EnumOptionData chargeTimeType, final EnumOptionData chargeCalculationType, final Collection<ChargeData> chargeOptions,
final boolean penalty) {
this.id = id;
this.chargeId = chargeId;
@@ -137,21 +114,21 @@ public class LoanChargeData {
this.amount = amount;
this.amountPaid = BigDecimal.ZERO;
this.amountWaived = BigDecimal.ZERO;
this.amountWrittenOff = BigDecimal.ZERO;
this.amountOutstanding = amount;
this.amountWrittenOff = BigDecimal.ZERO;
this.amountOutstanding = amount;
this.chargeTimeType = chargeTimeType;
this.dueAsOfDate = null;
this.chargeCalculationType = chargeCalculationType;
this.percentage = null;
this.amountPercentageAppliedTo = null;
this.penalty = penalty;
if (chargeCalculationType != null && chargeCalculationType.getId().intValue() > 1) {
this.amountOrPercentage = this.percentage;
} else {
this.amountOrPercentage = amount;
}
this.amountPercentageAppliedTo = null;
this.penalty = penalty;
if (chargeCalculationType != null && chargeCalculationType.getId().intValue() > 1) {
this.amountOrPercentage = this.percentage;
} else {
this.amountOrPercentage = amount;
}
this.chargeOptions = chargeOptions;
}
}
@@ -421,12 +421,15 @@ public class Loan extends AbstractAuditableCustom<AppUser, Long> {
}
}
public void updateLoanCharge(final LoanCharge loanCharge, final LoanChargeCommand command) {
public Map<String, Object> updateLoanCharge(final LoanCharge loanCharge, final JsonCommand command) {
final Map<String, Object> actualChanges = new LinkedHashMap<String, Object>(3);
validateLoanIsNotClosed(loanCharge);
if (this.charges.contains(loanCharge)) {
loanCharge.update(command, getPrincpal().getAmount());
final Map<String, Object> loanChargeChanges = loanCharge.update(command, getPrincpal().getAmount());
actualChanges.putAll(loanChargeChanges);
updateTotalChargesDueAtDisbursement();
}
@@ -441,13 +444,17 @@ public class Loan extends AbstractAuditableCustom<AppUser, Long> {
LoanScheduleWrapper wrapper = new LoanScheduleWrapper();
wrapper.reprocess(getCurrency(), getDisbursementDate(), this.repaymentScheduleInstallments, this.charges);
}
return actualChanges;
}
public LoanTransaction waiveLoanCharge(final LoanCharge loanCharge, final LoanLifecycleStateMachine loanLifecycleStateMachine) {
public LoanTransaction waiveLoanCharge(final LoanCharge loanCharge, final LoanLifecycleStateMachine loanLifecycleStateMachine, final Map<String, Object> changes) {
validateLoanIsNotClosed(loanCharge);
final Money amountWaived = loanCharge.waive(loanCurrency());
changes.put("amount", amountWaived.getAmount());
Money feeChargesWaived = Money.of(loanCurrency(), loanCharge.amount());
Money penaltyChargesWaived = Money.zero(loanCurrency());
@@ -1368,9 +1375,11 @@ public class Loan extends AbstractAuditableCustom<AppUser, Long> {
return this.loanRepaymentScheduleDetail.getCurrency();
}
public LoanTransaction closeAsWrittenOff(final JsonCommand command, final LoanLifecycleStateMachine loanLifecycleStateMachine, final Map<String, Object> changes) {
public LoanTransaction closeAsWrittenOff(final JsonCommand command, final LoanLifecycleStateMachine loanLifecycleStateMachine,
final Map<String, Object> changes) {
final LoanStatus statusEnum = loanLifecycleStateMachine.transition(LoanEvent.WRITE_OFF_OUTSTANDING, LoanStatus.fromInt(this.loanStatus));
final LoanStatus statusEnum = loanLifecycleStateMachine.transition(LoanEvent.WRITE_OFF_OUTSTANDING,
LoanStatus.fromInt(this.loanStatus));
if (!statusEnum.hasStateOf(LoanStatus.fromInt(this.loanStatus))) {
this.loanStatus = statusEnum.getValue();
changes.put("status", LoanEnumerations.status(this.loanStatus));
@@ -1382,7 +1391,7 @@ public class Loan extends AbstractAuditableCustom<AppUser, Long> {
this.writtenOffOnDate = writtenOffOnLocalDate.toDate();
changes.put("closedOnDate", command.stringValueOfParameterNamed("transactionDate"));
changes.put("writtenOffOnDate", command.stringValueOfParameterNamed("transactionDate"));
if (writtenOffOnLocalDate.isBefore(this.getDisbursementDate())) {
final String errorMessage = "The date on which a loan is written off cannot be before the loan disbursement date: "
+ getDisbursementDate().toString();
@@ -1412,7 +1421,8 @@ public class Loan extends AbstractAuditableCustom<AppUser, Long> {
return loanTransaction;
}
public LoanTransaction close(final JsonCommand command, final LoanLifecycleStateMachine loanLifecycleStateMachine, final Map<String, Object> changes) {
public LoanTransaction close(final JsonCommand command, final LoanLifecycleStateMachine loanLifecycleStateMachine,
final Map<String, Object> changes) {
final LocalDate closureDate = command.localDateValueOfParameterNamed("transactionDate");
@@ -1487,8 +1497,9 @@ public class Loan extends AbstractAuditableCustom<AppUser, Long> {
return totalOutstanding;
}
private void updateLoanForClosure(final LocalDate closureDate, final LoanLifecycleStateMachine loanLifecycleStateMachine, final Map<String, Object> changes) {
private void updateLoanForClosure(final LocalDate closureDate, final LoanLifecycleStateMachine loanLifecycleStateMachine,
final Map<String, Object> changes) {
final LoanStatus statusEnum = loanLifecycleStateMachine.transition(LoanEvent.REPAID_IN_FULL, LoanStatus.fromInt(this.loanStatus));
if (!statusEnum.hasStateOf(LoanStatus.fromInt(this.loanStatus))) {
this.loanStatus = statusEnum.getValue();
@@ -1500,12 +1511,14 @@ public class Loan extends AbstractAuditableCustom<AppUser, Long> {
/**
* Behaviour added to comply with capability of previous mifos product to
* support easier transition to mifosx platform.
* @param changes
*
* @param changes
*/
public void closeAsMarkedForReschedule(final JsonCommand command, final LoanLifecycleStateMachine loanLifecycleStateMachine, final Map<String, Object> changes) {
public void closeAsMarkedForReschedule(final JsonCommand command, final LoanLifecycleStateMachine loanLifecycleStateMachine,
final Map<String, Object> changes) {
final LocalDate rescheduledOn = command.localDateValueOfParameterNamed("transactionDate");
final LoanStatus statusEnum = loanLifecycleStateMachine.transition(LoanEvent.LOAN_RESCHEDULE, LoanStatus.fromInt(this.loanStatus));
if (!statusEnum.hasStateOf(LoanStatus.fromInt(this.loanStatus))) {
this.loanStatus = statusEnum.getValue();
@@ -4,8 +4,8 @@ import java.math.BigDecimal;
import java.math.MathContext;
import java.math.RoundingMode;
import java.util.Date;
import java.util.HashSet;
import java.util.Set;
import java.util.LinkedHashMap;
import java.util.Map;
import javax.persistence.Column;
import javax.persistence.Entity;
@@ -16,6 +16,7 @@ import javax.persistence.Temporal;
import javax.persistence.TemporalType;
import org.joda.time.LocalDate;
import org.mifosplatform.infrastructure.core.api.JsonCommand;
import org.mifosplatform.organisation.monetary.domain.MonetaryCurrency;
import org.mifosplatform.organisation.monetary.domain.Money;
import org.mifosplatform.portfolio.charge.domain.Charge;
@@ -74,16 +75,24 @@ public class LoanCharge extends AbstractPersistable<Long> {
@Column(name = "is_paid_derived", nullable = false)
private boolean paid = false;
public static LoanCharge createNew(final Loan loan, final Charge chargeDefinition, final LoanChargeCommand command) {
return new LoanCharge(loan, chargeDefinition, command);
}
public static LoanCharge createNewFromJson(final Loan loan, final Charge chargeDefinition, final JsonCommand command) {
/*
* loanPrincipal is required for charges that are percentage based
*/
public static LoanCharge createNewWithoutLoan(final Charge chargeDefinition, final LoanChargeCommand command,
final BigDecimal loanPrincipal) {
return new LoanCharge(chargeDefinition, command, loanPrincipal);
final BigDecimal amount = command.bigDecimalValueOfParameterNamed("amount");
final Integer chargeTimeType = command.integerValueOfParameterNamed("chargeTimeType");
final Integer chargeCalculationType = command.integerValueOfParameterNamed("chargeCalculationType");
final LocalDate specifiedDueDate = command.localDateValueOfParameterNamed("specifiedDueDate");
ChargeTimeType chargeTime = null;
if (chargeTimeType != null) {
chargeTime = ChargeTimeType.fromInt(chargeTimeType);
}
ChargeCalculationType chargeCalculation = null;
if (chargeCalculationType != null) {
chargeCalculation = ChargeCalculationType.fromInt(chargeCalculationType);
}
return new LoanCharge(loan, chargeDefinition, loan.getPrincpal().getAmount(), amount, chargeTime, chargeCalculation,
specifiedDueDate);
}
/*
@@ -91,20 +100,16 @@ public class LoanCharge extends AbstractPersistable<Long> {
*/
public static LoanCharge createNewWithoutLoan(final Charge chargeDefinition, final BigDecimal loanPrincipal, final BigDecimal amount,
final ChargeTimeType chargeTime, final ChargeCalculationType chargeCalculation, final LocalDate specifiedDueDate) {
return new LoanCharge(chargeDefinition, loanPrincipal, amount, chargeTime, chargeCalculation, specifiedDueDate);
}
public static LoanCharge createNew(final Charge chargeDefinition) {
return new LoanCharge(null, chargeDefinition);
return new LoanCharge(null, chargeDefinition, loanPrincipal, amount, chargeTime, chargeCalculation, specifiedDueDate);
}
protected LoanCharge() {
//
}
public LoanCharge(final Charge chargeDefinition, final BigDecimal loanPrincipal, final BigDecimal amount,
public LoanCharge(final Loan loan, final Charge chargeDefinition, final BigDecimal loanPrincipal, final BigDecimal amount,
final ChargeTimeType chargeTime, final ChargeCalculationType chargeCalculation, final LocalDate specifiedDueDate) {
this.loan = null;
this.loan = loan;
this.charge = chargeDefinition;
this.penaltyCharge = chargeDefinition.isPenalty();
@@ -140,85 +145,6 @@ public class LoanCharge extends AbstractPersistable<Long> {
this.paid = determineIfFullyPaid();
}
@Deprecated
public LoanCharge(final Charge chargeDefinition, final LoanChargeCommand command, final BigDecimal loanPrincipal) {
this.loan = null;
this.charge = chargeDefinition;
this.penaltyCharge = chargeDefinition.isPenalty();
if (command.isChargeTimeTypeChanged()) {
this.chargeTime = command.getChargeTimeType();
} else {
this.chargeTime = chargeDefinition.getChargeTime();
}
if (ChargeTimeType.fromInt(this.chargeTime).equals(ChargeTimeType.SPECIFIED_DUE_DATE)) {
if (command.getSpecifiedDueDate() == null) {
final String defaultUserMessage = "Loan charge is missing specified due date";
throw new LoanChargeWithoutMandatoryFieldException("loancharge", "specifiedDueDate", defaultUserMessage, command.getId(),
chargeDefinition.getName());
}
this.dueForCollectionAsOfDate = command.getSpecifiedDueDate().toDate();
} else {
this.dueForCollectionAsOfDate = null;
}
if (command.isChargeCalculationTypeChanged()) {
this.chargeCalculation = command.getChargeCalculationType();
} else {
this.chargeCalculation = chargeDefinition.getChargeCalculation();
}
BigDecimal chargeAmount = chargeDefinition.getAmount();
if (command.isAmountChanged()) {
chargeAmount = command.getAmount();
}
populateDerivedFields(loanPrincipal, chargeAmount);
this.paid = determineIfFullyPaid();
}
@Deprecated
private LoanCharge(final Loan loan, final Charge chargeDefinition, final LoanChargeCommand command) {
this.loan = loan;
this.charge = chargeDefinition;
this.penaltyCharge = chargeDefinition.isPenalty();
if (command.isChargeTimeTypeChanged()) {
this.chargeTime = command.getChargeTimeType();
} else {
this.chargeTime = chargeDefinition.getChargeTime();
}
if (ChargeTimeType.fromInt(this.chargeTime).equals(ChargeTimeType.SPECIFIED_DUE_DATE)) {
if (command.getSpecifiedDueDate() == null) {
final String defaultUserMessage = "Loan charge is missing specified due date";
throw new LoanChargeWithoutMandatoryFieldException("loancharge", "specifiedDueDate", defaultUserMessage, command.getId(),
chargeDefinition.getName());
}
this.dueForCollectionAsOfDate = command.getSpecifiedDueDate().toDate();
} else {
this.dueForCollectionAsOfDate = null;
}
if (command.isChargeCalculationTypeChanged()) {
this.chargeCalculation = command.getChargeCalculationType();
} else {
this.chargeCalculation = chargeDefinition.getChargeCalculation();
}
BigDecimal chargeAmount = chargeDefinition.getAmount();
if (command.isAmountChanged()) {
chargeAmount = command.getAmount();
}
populateDerivedFields(loan.getPrincpal().getAmount(), chargeAmount);
this.paid = determineIfFullyPaid();
}
private void populateDerivedFields(final BigDecimal loanPrincipal, final BigDecimal chargeAmount) {
switch (ChargeCalculationType.fromInt(this.chargeCalculation)) {
@@ -270,20 +196,6 @@ public class LoanCharge extends AbstractPersistable<Long> {
}
}
private LoanCharge(final Loan loan, final Charge chargeDefinition) {
this(loan, chargeDefinition, chargeDefinition.getAmount(), chargeDefinition.getChargeTime(), chargeDefinition
.getChargeCalculation());
}
private LoanCharge(final Loan loan, final Charge charge, final BigDecimal amount, final Integer chargeTime,
final Integer chargeCalculation) {
this.loan = loan;
this.charge = charge;
this.amount = amount;
this.chargeTime = chargeTime;
this.chargeCalculation = chargeCalculation;
}
public void markAsFullyPaid() {
this.amountPaid = this.amount;
this.amountOutstanding = BigDecimal.ZERO;
@@ -318,7 +230,7 @@ public class LoanCharge extends AbstractPersistable<Long> {
public void update(final Loan loan) {
this.loan = loan;
}
public void update(final BigDecimal amount, final LocalDate specifiedDueDate, final BigDecimal loanPrincipal) {
if (specifiedDueDate != null) {
this.dueForCollectionAsOfDate = specifiedDueDate.toDate();
@@ -353,47 +265,73 @@ public class LoanCharge extends AbstractPersistable<Long> {
}
}
public void update(final LoanChargeCommand command, final BigDecimal loanPrincipal) {
public Map<String, Object> update(final JsonCommand command, final BigDecimal loanPrincipal) {
if (command.isChargeTimeTypeChanged()) {
this.chargeTime = ChargeTimeType.fromInt(command.getChargeTimeType()).getValue();
final Map<String, Object> actualChanges = new LinkedHashMap<String, Object>(7);
final String dateFormatAsInput = command.dateFormat();
final String localeAsInput = command.locale();
final String chargeTimeParamName = "chargeTime";
if (command.isChangeInIntegerParameterNamed(chargeTimeParamName, this.chargeTime)) {
final Integer newValue = command.integerValueOfParameterNamed(chargeTimeParamName);
actualChanges.put(chargeTimeParamName, newValue);
actualChanges.put("locale", localeAsInput);
this.chargeTime = ChargeTimeType.fromInt(newValue).getValue();
}
if (command.isChargeCalculationTypeChanged()) {
this.chargeCalculation = ChargeCalculationType.fromInt(command.getChargeCalculationType()).getValue();
final String chargeCalculationParamName = "chargeCalculation";
if (command.isChangeInIntegerParameterNamed(chargeCalculationParamName, this.chargeCalculation)) {
final Integer newValue = command.integerValueOfParameterNamed(chargeCalculationParamName);
actualChanges.put(chargeCalculationParamName, newValue);
actualChanges.put("locale", localeAsInput);
this.chargeCalculation = ChargeCalculationType.fromInt(newValue).getValue();
}
if (command.isSpecifiedDueDateChanged()) {
this.dueForCollectionAsOfDate = command.getSpecifiedDueDate().toDate();
final String specifiedDueDateParamName = "specifiedDueDate";
if (command.isChangeInLocalDateParameterNamed(specifiedDueDateParamName, getDueForCollectionAsOfLocalDate())) {
final String valueAsInput = command.stringValueOfParameterNamed(specifiedDueDateParamName);
actualChanges.put(specifiedDueDateParamName, valueAsInput);
actualChanges.put("dateFormat", dateFormatAsInput);
actualChanges.put("locale", localeAsInput);
final LocalDate newValue = command.localDateValueOfParameterNamed(specifiedDueDateParamName);
this.dueForCollectionAsOfDate = newValue.toDate();
}
if (command.isAmountChanged()) {
final String amountParamName = "amount";
if (command.isChangeInBigDecimalParameterNamed(amountParamName, this.amount)) {
final BigDecimal newValue = command.bigDecimalValueOfParameterNamed(amountParamName);
actualChanges.put(amountParamName, newValue);
actualChanges.put("locale", localeAsInput);
switch (ChargeCalculationType.fromInt(this.chargeCalculation)) {
case INVALID:
break;
case FLAT:
this.amount = command.getAmount();
this.amount = newValue;
break;
case PERCENT_OF_AMOUNT:
this.percentage = command.getAmount();
this.percentage = newValue;
this.amountPercentageAppliedTo = loanPrincipal;
this.amount = percentageOf(this.amountPercentageAppliedTo, this.percentage);
this.amountOutstanding = calculateOutstanding();
break;
case PERCENT_OF_AMOUNT_AND_INTEREST:
this.percentage = command.getAmount();
this.percentage = newValue;
this.amount = null;
this.amountPercentageAppliedTo = null;
this.amountOutstanding = null;
break;
case PERCENT_OF_INTEREST:
this.percentage = command.getAmount();
this.percentage = newValue;
this.amount = null;
this.amountPercentageAppliedTo = null;
this.amountOutstanding = null;
break;
}
}
return actualChanges;
}
public boolean isDueAtDisbursement() {
@@ -411,9 +349,7 @@ public class LoanCharge extends AbstractPersistable<Long> {
public LoanChargeCommand toCommand() {
final LocalDate specifiedDueDate = getDueForCollectionAsOfLocalDate();
final Set<String> modifiedParameters = new HashSet<String>();
return new LoanChargeCommand(modifiedParameters, this.getId(), this.loan.getId(), this.charge.getId(), this.amount,
this.chargeTime, this.chargeCalculation, specifiedDueDate);
return new LoanChargeCommand(this.charge.getId(), this.amount, this.chargeTime, this.chargeCalculation, specifiedDueDate);
}
public LocalDate getDueForCollectionAsOfLocalDate() {
@@ -0,0 +1,27 @@
package org.mifosplatform.portfolio.loanaccount.handler;
import org.mifosplatform.commands.handler.NewCommandSourceHandler;
import org.mifosplatform.infrastructure.core.api.JsonCommand;
import org.mifosplatform.infrastructure.core.data.EntityIdentifier;
import org.mifosplatform.portfolio.loanaccount.service.LoanWritePlatformService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
@Service
public class AddLoanChargeCommandHandler implements NewCommandSourceHandler {
private final LoanWritePlatformService writePlatformService;
@Autowired
public AddLoanChargeCommandHandler(final LoanWritePlatformService writePlatformService) {
this.writePlatformService = writePlatformService;
}
@Transactional
@Override
public EntityIdentifier processCommand(final JsonCommand command) {
return this.writePlatformService.addLoanCharge(command.resourceId(), command);
}
}
@@ -0,0 +1,27 @@
package org.mifosplatform.portfolio.loanaccount.handler;
import org.mifosplatform.commands.handler.NewCommandSourceHandler;
import org.mifosplatform.infrastructure.core.api.JsonCommand;
import org.mifosplatform.infrastructure.core.data.EntityIdentifier;
import org.mifosplatform.portfolio.loanaccount.service.LoanWritePlatformService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
@Service
public class DeleteLoanChargeCommandHandler implements NewCommandSourceHandler {
private final LoanWritePlatformService writePlatformService;
@Autowired
public DeleteLoanChargeCommandHandler(final LoanWritePlatformService writePlatformService) {
this.writePlatformService = writePlatformService;
}
@Transactional
@Override
public EntityIdentifier processCommand(final JsonCommand command) {
return this.writePlatformService.deleteLoanCharge(command.resourceId(), command.subResourceId(), command);
}
}
@@ -0,0 +1,27 @@
package org.mifosplatform.portfolio.loanaccount.handler;
import org.mifosplatform.commands.handler.NewCommandSourceHandler;
import org.mifosplatform.infrastructure.core.api.JsonCommand;
import org.mifosplatform.infrastructure.core.data.EntityIdentifier;
import org.mifosplatform.portfolio.loanaccount.service.LoanWritePlatformService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
@Service
public class UpdateLoanChargeCommandHandler implements NewCommandSourceHandler {
private final LoanWritePlatformService writePlatformService;
@Autowired
public UpdateLoanChargeCommandHandler(final LoanWritePlatformService writePlatformService) {
this.writePlatformService = writePlatformService;
}
@Transactional
@Override
public EntityIdentifier processCommand(final JsonCommand command) {
return this.writePlatformService.updateLoanCharge(command.resourceId(), command.subResourceId(), command);
}
}
@@ -0,0 +1,27 @@
package org.mifosplatform.portfolio.loanaccount.handler;
import org.mifosplatform.commands.handler.NewCommandSourceHandler;
import org.mifosplatform.infrastructure.core.api.JsonCommand;
import org.mifosplatform.infrastructure.core.data.EntityIdentifier;
import org.mifosplatform.portfolio.loanaccount.service.LoanWritePlatformService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
@Service
public class WaiveLoanChargeCommandHandler implements NewCommandSourceHandler {
private final LoanWritePlatformService writePlatformService;
@Autowired
public WaiveLoanChargeCommandHandler(final LoanWritePlatformService writePlatformService) {
this.writePlatformService = writePlatformService;
}
@Transactional
@Override
public EntityIdentifier processCommand(final JsonCommand command) {
return this.writePlatformService.waiveLoanCharge(command.resourceId(), command.subResourceId(), command);
}
}
@@ -88,9 +88,9 @@ public final class CalculateLoanScheduleQueryFromApiJsonDeserializer extends Abs
for (int i = 0; i < array.size(); i++) {
final JsonObject loanChargeElement = array.get(i).getAsJsonObject();
final Set<String> parametersPassedInForChargesCommand = new HashSet<String>();
final Long id = fromApiJsonHelper.extractLongNamed("id", loanChargeElement);
// final Long id = fromApiJsonHelper.extractLongNamed("id",
// loanChargeElement);
final Long chargeId = fromApiJsonHelper.extractLongNamed("chargeId", loanChargeElement);
final BigDecimal amount = fromApiJsonHelper.extractBigDecimalNamed("amount", loanChargeElement, locale);
final Integer chargeTimeType = fromApiJsonHelper.extractIntegerNamed("chargeTimeType", loanChargeElement, locale);
@@ -99,8 +99,7 @@ public final class CalculateLoanScheduleQueryFromApiJsonDeserializer extends Abs
final LocalDate specifiedDueDate = fromApiJsonHelper.extractLocalDateNamed("specifiedDueDate", loanChargeElement,
dateFormat, locale);
charges[i] = new LoanChargeCommand(parametersPassedInForChargesCommand, id, null, chargeId, amount, chargeTimeType,
chargeCalculationType, specifiedDueDate);
charges[i] = new LoanChargeCommand(chargeId, amount, chargeTimeType, chargeCalculationType, specifiedDueDate);
}
}
}
@@ -116,9 +116,9 @@ public final class LoanApplicationCommandFromApiJsonDeserializer extends Abstrac
for (int i = 0; i < array.size(); i++) {
final JsonObject loanChargeElement = array.get(i).getAsJsonObject();
final Set<String> parametersPassedInForChargesCommand = new HashSet<String>();
final Long id = fromApiJsonHelper.extractLongNamed("id", loanChargeElement);
// final Long id = fromApiJsonHelper.extractLongNamed("id",
// loanChargeElement);
final Long chargeId = fromApiJsonHelper.extractLongNamed("chargeId", loanChargeElement);
final BigDecimal amount = fromApiJsonHelper.extractBigDecimalNamed("amount", loanChargeElement, locale);
final Integer chargeTimeType = fromApiJsonHelper.extractIntegerNamed("chargeTimeType", loanChargeElement, locale);
@@ -127,8 +127,7 @@ public final class LoanApplicationCommandFromApiJsonDeserializer extends Abstrac
final LocalDate specifiedDueDate = fromApiJsonHelper.extractLocalDateNamed("specifiedDueDate", loanChargeElement,
dateFormat, locale);
charges[i] = new LoanChargeCommand(parametersPassedInForChargesCommand, id, null, chargeId, amount, chargeTimeType,
chargeCalculationType, specifiedDueDate);
charges[i] = new LoanChargeCommand(chargeId, amount, chargeTimeType, chargeCalculationType, specifiedDueDate);
}
}
}
@@ -0,0 +1,60 @@
package org.mifosplatform.portfolio.loanaccount.serialization;
import java.lang.reflect.Type;
import java.math.BigDecimal;
import java.util.Arrays;
import java.util.HashSet;
import java.util.Map;
import java.util.Set;
import org.apache.commons.lang.StringUtils;
import org.joda.time.LocalDate;
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.loanaccount.command.LoanChargeCommand;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;
import com.google.gson.JsonElement;
import com.google.gson.reflect.TypeToken;
/**
* Implementation of {@link FromApiJsonDeserializer} for
* {@link LoanChargeCommand}'s.
*/
@Component
public final class LoanChargeCommandFromApiJsonDeserializer extends AbstractFromApiJsonDeserializer<LoanChargeCommand> {
/**
* The parameters supported for this command.
*/
final Set<String> supportedParameters = new HashSet<String>(Arrays.asList("chargeId", "amount", "chargeTimeType",
"chargeCalculationType", "specifiedDueDate", "locale", "dateFormat"));
private final FromJsonHelper fromApiJsonHelper;
@Autowired
public LoanChargeCommandFromApiJsonDeserializer(final FromJsonHelper fromApiJsonHelper) {
this.fromApiJsonHelper = fromApiJsonHelper;
}
@Override
public LoanChargeCommand commandFromApiJson(final String json) {
if (StringUtils.isBlank(json)) { throw new InvalidJsonException(); }
final Type typeOfMap = new TypeToken<Map<String, Object>>() {}.getType();
fromApiJsonHelper.checkForUnsupportedParameters(typeOfMap, json, supportedParameters);
final JsonElement element = fromApiJsonHelper.parse(json);
final Long chargeId = fromApiJsonHelper.extractLongNamed("chargeId", element);
final BigDecimal amount = fromApiJsonHelper.extractBigDecimalWithLocaleNamed("amount", element);
final Integer chargeTimeType = fromApiJsonHelper.extractIntegerWithLocaleNamed("chargeTimeType", element);
final Integer chargeCalculationType = fromApiJsonHelper.extractIntegerWithLocaleNamed("chargeCalculationType", element);
final LocalDate specifiedDueDate = fromApiJsonHelper.extractLocalDateNamed("specifiedDueDate", element);
return new LoanChargeCommand(chargeId, amount, chargeTimeType, chargeCalculationType, specifiedDueDate);
}
}
@@ -3,7 +3,6 @@ package org.mifosplatform.portfolio.loanaccount.service;
import org.mifosplatform.infrastructure.core.api.JsonCommand;
import org.mifosplatform.infrastructure.core.data.EntityIdentifier;
import org.mifosplatform.organisation.staff.command.BulkTransferLoanOfficerCommand;
import org.mifosplatform.portfolio.loanaccount.command.LoanChargeCommand;
import org.springframework.security.access.prepost.PreAuthorize;
public interface LoanWritePlatformService {
@@ -38,17 +37,13 @@ public interface LoanWritePlatformService {
EntityIdentifier closeAsRescheduled(Long loanId, JsonCommand command);
@PreAuthorize(value = "hasAnyRole('ALL_FUNCTIONS', 'PORTFOLIO_MANAGEMENT_SUPER_USER', 'CREATE_LOANCHARGE')")
EntityIdentifier addLoanCharge(LoanChargeCommand command);
EntityIdentifier addLoanCharge(Long loanId, JsonCommand command);
@PreAuthorize(value = "hasAnyRole('ALL_FUNCTIONS', 'PORTFOLIO_MANAGEMENT_SUPER_USER', 'UPDATE_LOANCHARGE')")
EntityIdentifier updateLoanCharge(LoanChargeCommand command);
EntityIdentifier updateLoanCharge(Long loanId, Long loanChargeId, JsonCommand command);
@PreAuthorize(value = "hasAnyRole('ALL_FUNCTIONS', 'PORTFOLIO_MANAGEMENT_SUPER_USER', 'DELETE_LOANCHARGE')")
EntityIdentifier deleteLoanCharge(final Long loanId, final Long loanChargeId);
EntityIdentifier deleteLoanCharge(Long loanId, Long loanChargeId, JsonCommand command);
@PreAuthorize(value = "hasAnyRole('ALL_FUNCTIONS', 'PORTFOLIO_MANAGEMENT_SUPER_USER', 'WAIVE_LOANCHARGE')")
EntityIdentifier waiveLoanCharge(LoanChargeCommand command);
EntityIdentifier waiveLoanCharge(Long loanId, Long loanChargeId, JsonCommand command);
@PreAuthorize(value = "hasAnyRole('ALL_FUNCTIONS', 'PORTFOLIO_MANAGEMENT_SUPER_USER', 'BULKREASSIGN_LOAN')")
EntityIdentifier bulkLoanReassignment(final BulkTransferLoanOfficerCommand command);
@@ -33,7 +33,6 @@ import org.mifosplatform.portfolio.client.exception.ClientNotFoundException;
import org.mifosplatform.portfolio.fund.domain.Fund;
import org.mifosplatform.portfolio.loanaccount.command.LoanApplicationCommand;
import org.mifosplatform.portfolio.loanaccount.command.LoanChargeCommand;
import org.mifosplatform.portfolio.loanaccount.command.LoanChargeCommandValidator;
import org.mifosplatform.portfolio.loanaccount.command.LoanStateTransitionCommand;
import org.mifosplatform.portfolio.loanaccount.command.LoanTransactionCommand;
import org.mifosplatform.portfolio.loanaccount.domain.DefaultLoanLifecycleStateMachine;
@@ -55,6 +54,7 @@ import org.mifosplatform.portfolio.loanaccount.loanschedule.query.CalculateLoanS
import org.mifosplatform.portfolio.loanaccount.loanschedule.service.LoanScheduleCalculationPlatformService;
import org.mifosplatform.portfolio.loanaccount.serialization.CalculateLoanScheduleQueryFromApiJsonDeserializer;
import org.mifosplatform.portfolio.loanaccount.serialization.LoanApplicationCommandFromApiJsonDeserializer;
import org.mifosplatform.portfolio.loanaccount.serialization.LoanChargeCommandFromApiJsonDeserializer;
import org.mifosplatform.portfolio.loanaccount.serialization.LoanStateTransitionCommandFromApiJsonDeserializer;
import org.mifosplatform.portfolio.loanaccount.serialization.LoanTransactionCommandFromApiJsonDeserializer;
import org.mifosplatform.portfolio.loanproduct.domain.LoanProduct;
@@ -78,6 +78,7 @@ public class LoanWritePlatformServiceJpaRepositoryImpl implements LoanWritePlatf
private final CalculateLoanScheduleQueryFromApiJsonDeserializer calculateLoanScheduleQueryFromApiJsonDeserializer;
private final LoanStateTransitionCommandFromApiJsonDeserializer loanStateTransitionCommandFromApiJsonDeserializer;
private final LoanTransactionCommandFromApiJsonDeserializer loanTransactionCommandFromApiJsonDeserializer;
private final LoanChargeCommandFromApiJsonDeserializer loanChargeCommandFromApiJsonDeserializer;
private final LoanRepository loanRepository;
private final NoteRepository noteRepository;
private final LoanScheduleCalculationPlatformService calculationPlatformService;
@@ -96,6 +97,7 @@ public class LoanWritePlatformServiceJpaRepositoryImpl implements LoanWritePlatf
final LoanApplicationCommandFromApiJsonDeserializer fromApiJsonDeserializer,
final LoanStateTransitionCommandFromApiJsonDeserializer loanStateTransitionCommandFromApiJsonDeserializer,
final LoanTransactionCommandFromApiJsonDeserializer loanTransactionCommandFromApiJsonDeserializer,
final LoanChargeCommandFromApiJsonDeserializer loanChargeCommandFromApiJsonDeserializer,
final CalculateLoanScheduleQueryFromApiJsonDeserializer calculateLoanScheduleQueryFromApiJsonDeserializer,
final AprCalculator aprCalculator, final LoanAssembler loanAssembler, final LoanChargeAssembler loanChargeAssembler,
final LoanRepository loanRepository, final LoanTransactionRepository loanTransactionRepository,
@@ -108,6 +110,7 @@ public class LoanWritePlatformServiceJpaRepositoryImpl implements LoanWritePlatf
this.fromApiJsonDeserializer = fromApiJsonDeserializer;
this.loanStateTransitionCommandFromApiJsonDeserializer = loanStateTransitionCommandFromApiJsonDeserializer;
this.loanTransactionCommandFromApiJsonDeserializer = loanTransactionCommandFromApiJsonDeserializer;
this.loanChargeCommandFromApiJsonDeserializer = loanChargeCommandFromApiJsonDeserializer;
this.calculateLoanScheduleQueryFromApiJsonDeserializer = calculateLoanScheduleQueryFromApiJsonDeserializer;
this.aprCalculator = aprCalculator;
this.loanAssembler = loanAssembler;
@@ -420,14 +423,14 @@ public class LoanWritePlatformServiceJpaRepositoryImpl implements LoanWritePlatf
final LoanTransactionCommand loanTransactionCommand = this.loanTransactionCommandFromApiJsonDeserializer.commandFromApiJson(command
.json());
loanTransactionCommand.validate();
final LocalDate transactionDate = command.localDateValueOfParameterNamed("transactionDate");
final BigDecimal transactionAmount = command.bigDecimalValueOfParameterNamed("transactionAmount");
final Map<String, Object> changes = new LinkedHashMap<String, Object>();
changes.put("transactionDate", command.stringValueOfParameterNamed("transactionDate"));
changes.put("transactionAmount", command.stringValueOfParameterNamed("transactionAmount"));
final Loan loan = retrieveLoanBy(loanId);
if (this.isBeforeToday(transactionDate) && currentUser.canNotMakeRepaymentOnLoanInPast()) { throw new NoAuthorizationException(
@@ -443,7 +446,7 @@ public class LoanWritePlatformServiceJpaRepositoryImpl implements LoanWritePlatf
Note note = Note.loanTransactionNote(loan, loanRepayment, noteText);
this.noteRepository.save(note);
}
changes.put("locale", command.locale());
changes.put("dateFormat", command.dateFormat());
@@ -459,7 +462,7 @@ public class LoanWritePlatformServiceJpaRepositoryImpl implements LoanWritePlatf
final LoanTransactionCommand loanTransactionCommand = this.loanTransactionCommandFromApiJsonDeserializer.commandFromApiJson(command
.json());
loanTransactionCommand.validate();
final Loan loan = retrieveLoanBy(loanId);
final LoanTransaction transactionToAdjust = this.loanTransactionRepository.findOne(transactionId);
@@ -467,13 +470,13 @@ public class LoanWritePlatformServiceJpaRepositoryImpl implements LoanWritePlatf
final LocalDate transactionDate = command.localDateValueOfParameterNamed("transactionDate");
final BigDecimal transactionAmount = command.bigDecimalValueOfParameterNamed("transactionAmount");
final Map<String, Object> changes = new LinkedHashMap<String, Object>();
changes.put("transactionDate", command.stringValueOfParameterNamed("transactionDate"));
changes.put("transactionAmount", command.stringValueOfParameterNamed("transactionAmount"));
final LoanTransaction newTransactionDetail = loan.adjustExistingTransaction(transactionDate, transactionAmount, defaultLoanLifecycleStateMachine(),
transactionToAdjust);
final LoanTransaction newTransactionDetail = loan.adjustExistingTransaction(transactionDate, transactionAmount,
defaultLoanLifecycleStateMachine(), transactionToAdjust);
if (newTransactionDetail.isGreaterThanZero(loan.getPrincpal().getCurrency())) {
this.loanTransactionRepository.save(newTransactionDetail);
}
@@ -489,7 +492,7 @@ public class LoanWritePlatformServiceJpaRepositoryImpl implements LoanWritePlatf
changes.put("locale", command.locale());
changes.put("dateFormat", command.dateFormat());
return EntityIdentifier.subResourceResult(loanId, transactionId, command.commandId(), changes);
}
@@ -502,7 +505,7 @@ public class LoanWritePlatformServiceJpaRepositoryImpl implements LoanWritePlatf
final LoanTransactionCommand loanTransactionCommand = this.loanTransactionCommandFromApiJsonDeserializer.commandFromApiJson(command
.json());
loanTransactionCommand.validate();
final Map<String, Object> changes = new LinkedHashMap<String, Object>();
changes.put("transactionDate", command.stringValueOfParameterNamed("transactionDate"));
changes.put("transactionAmount", command.stringValueOfParameterNamed("transactionAmount"));
@@ -520,7 +523,7 @@ public class LoanWritePlatformServiceJpaRepositoryImpl implements LoanWritePlatf
final Note note = Note.loanTransactionNote(loan, waiveTransaction, noteText);
this.noteRepository.save(note);
}
changes.put("locale", command.locale());
changes.put("dateFormat", command.dateFormat());
@@ -535,7 +538,7 @@ public class LoanWritePlatformServiceJpaRepositoryImpl implements LoanWritePlatf
final LoanTransactionCommand loanTransactionCommand = this.loanTransactionCommandFromApiJsonDeserializer.commandFromApiJson(command
.json());
loanTransactionCommand.validateNonMonetaryTransaction();
final Map<String, Object> changes = new LinkedHashMap<String, Object>();
changes.put("transactionDate", command.stringValueOfParameterNamed("transactionDate"));
@@ -570,7 +573,7 @@ public class LoanWritePlatformServiceJpaRepositoryImpl implements LoanWritePlatf
loanTransactionCommand.validateNonMonetaryTransaction();
final Loan loan = retrieveLoanBy(loanId);
final Map<String, Object> changes = new LinkedHashMap<String, Object>();
changes.put("transactionDate", command.stringValueOfParameterNamed("transactionDate"));
@@ -586,17 +589,17 @@ public class LoanWritePlatformServiceJpaRepositoryImpl implements LoanWritePlatf
final Note note = Note.loanNote(loan, noteText);
this.noteRepository.save(note);
}
changes.put("locale", command.locale());
changes.put("dateFormat", command.dateFormat());
EntityIdentifier result = null;
if (possibleClosingTransaction != null) {
result = EntityIdentifier.subResourceResult(loanId, possibleClosingTransaction.getId(), command.commandId(), changes);
} else {
result = EntityIdentifier.resourceResult(loanId, command.commandId(), changes);
}
return result;
}
@@ -610,7 +613,7 @@ public class LoanWritePlatformServiceJpaRepositoryImpl implements LoanWritePlatf
loanTransactionCommand.validateNonMonetaryTransaction();
final Loan loan = retrieveLoanBy(loanId);
final Map<String, Object> changes = new LinkedHashMap<String, Object>();
changes.put("transactionDate", command.stringValueOfParameterNamed("transactionDate"));
@@ -624,7 +627,7 @@ public class LoanWritePlatformServiceJpaRepositoryImpl implements LoanWritePlatf
final Note note = Note.loanNote(loan, noteText);
this.noteRepository.save(note);
}
changes.put("locale", command.locale());
changes.put("dateFormat", command.dateFormat());
@@ -633,72 +636,68 @@ public class LoanWritePlatformServiceJpaRepositoryImpl implements LoanWritePlatf
@Transactional
@Override
public EntityIdentifier addLoanCharge(final LoanChargeCommand command) {
public EntityIdentifier addLoanCharge(final Long loanId, final JsonCommand command) {
this.context.authenticatedUser();
LoanChargeCommandValidator validator = new LoanChargeCommandValidator(command);
validator.validateForCreate();
final LoanChargeCommand loanChargeCommand = this.loanChargeCommandFromApiJsonDeserializer.commandFromApiJson(command.json());
loanChargeCommand.validateForCreate();
final Loan loan = this.loanRepository.findOne(command.getLoanId());
if (loan == null) { throw new LoanNotFoundException(command.getLoanId()); }
final Charge chargeDefinition = this.chargeRepository.findOne(command.getChargeId());
if (chargeDefinition == null || chargeDefinition.isDeleted()) { throw new ChargeNotFoundException(command.getChargeId()); }
final Loan loan = retrieveLoanBy(loanId);
final Long chargeDefinitionId = command.longValueOfParameterNamed("chargeId");
final Charge chargeDefinition = this.chargeRepository.findOne(chargeDefinitionId);
if (chargeDefinition == null || chargeDefinition.isDeleted()) { throw new ChargeNotFoundException(chargeDefinitionId); }
if (!chargeDefinition.isActive()) { throw new ChargeIsNotActiveException(chargeDefinition.getId(), chargeDefinition.getName()); }
final LoanCharge loanCharge = LoanCharge.createNew(loan, chargeDefinition, command);
final LoanCharge loanCharge = LoanCharge.createNewFromJson(loan, chargeDefinition, command);
if (!loan.hasCurrencyCodeOf(chargeDefinition.getCurrencyCode())) {
String errorMessage = "Charge and Loan must have the same currency.";
throw new InvalidCurrencyException("charge", "attach.to.loan", errorMessage);
}
this.loanChargeRepository.save(loanCharge);
loan.addLoanCharge(loanCharge);
this.loanRepository.saveAndFlush(loan);
this.loanRepository.save(loan);
return new EntityIdentifier(loanCharge.getId());
return EntityIdentifier.subResourceResult(loanId, loanCharge.getId(), command.commandId());
}
@Transactional
@Override
public EntityIdentifier updateLoanCharge(final LoanChargeCommand command) {
public EntityIdentifier updateLoanCharge(final Long loanId, final Long loanChargeId, final JsonCommand command) {
this.context.authenticatedUser();
LoanChargeCommandValidator validator = new LoanChargeCommandValidator(command);
validator.validateForUpdate();
final LoanChargeCommand loanChargeCommand = this.loanChargeCommandFromApiJsonDeserializer.commandFromApiJson(command.json());
loanChargeCommand.validateForUpdate();
final Long loanId = command.getLoanId();
final Loan loan = retrieveLoanBy(loanId);
final Long loanChargeId = command.getId();
final LoanCharge loanCharge = retrieveLoanChargeBy(loanId, loanChargeId);
loan.updateLoanCharge(loanCharge, command);
final Map<String, Object> changes = loan.updateLoanCharge(loanCharge, command);
this.loanRepository.save(loan);
return new EntityIdentifier(loanCharge.getId());
return EntityIdentifier.subResourceResult(loanId, loanChargeId, command.commandId(), changes);
}
@Transactional
@Override
public EntityIdentifier waiveLoanCharge(final LoanChargeCommand command) {
public EntityIdentifier waiveLoanCharge(final Long loanId, final Long loanChargeId, final JsonCommand command) {
this.context.authenticatedUser();
// LoanChargeCommandValidator validator = new
// LoanChargeCommandValidator(command);
// validator.validateForUpdate();
final LoanChargeCommand loanChargeCommand = this.loanChargeCommandFromApiJsonDeserializer.commandFromApiJson(command.json());
loanChargeCommand.validateForUpdate();
final Long loanId = command.getLoanId();
final Loan loan = retrieveLoanBy(loanId);
final Long loanChargeId = command.getId();
final LoanCharge loanCharge = retrieveLoanChargeBy(loanId, loanChargeId);
final Map<String, Object> changes = new LinkedHashMap<String, Object>(3);
final LoanTransaction waiveTransaction = loan.waiveLoanCharge(loanCharge, defaultLoanLifecycleStateMachine());
final LoanTransaction waiveTransaction = loan.waiveLoanCharge(loanCharge, defaultLoanLifecycleStateMachine(), changes);
this.loanTransactionRepository.save(waiveTransaction);
this.loanRepository.save(loan);
@@ -709,23 +708,22 @@ public class LoanWritePlatformServiceJpaRepositoryImpl implements LoanWritePlatf
this.noteRepository.save(note);
}
return new EntityIdentifier(loanCharge.getId());
return EntityIdentifier.subResourceResult(loanId, loanChargeId, command.commandId(), changes);
}
@Transactional
@Override
public EntityIdentifier deleteLoanCharge(final Long loanId, final Long loanChargeId) {
public EntityIdentifier deleteLoanCharge(final Long loanId, final Long loanChargeId, final JsonCommand command) {
this.context.authenticatedUser();
final Loan loan = retrieveLoanBy(loanId);
final LoanCharge loanCharge = retrieveLoanChargeBy(loanId, loanChargeId);
loan.removeLoanCharge(loanCharge);
this.loanRepository.save(loan);
return new EntityIdentifier(loanCharge.getId());
return EntityIdentifier.subResourceResult(loanId, loanChargeId, command.commandId());
}
private Loan retrieveLoanBy(final Long loanId) {