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() { public boolean isCloseLoanAsRescheduled() {
return this.actionName.equalsIgnoreCase("CLOSEASRESCHEDULED") && this.entityName.equalsIgnoreCase("LOAN"); 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); handler = applicationContext.getBean("closeLoanCommandHandler", NewCommandSourceHandler.class);
} else if (wrapper.isCloseLoanAsRescheduled()) { } else if (wrapper.isCloseLoanAsRescheduled()) {
handler = applicationContext.getBean("closeLoanAsRescheduledCommandHandler", NewCommandSourceHandler.class); 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()) { } else if (wrapper.isCreate()) {
handler = applicationContext.getBean("createLoanApplicationCommandHandler", NewCommandSourceHandler.class); handler = applicationContext.getBean("createLoanApplicationCommandHandler", NewCommandSourceHandler.class);
} else if (wrapper.isUpdate()) { } 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.client.data.ClientAccountSummaryCollectionData;
import org.mifosplatform.portfolio.group.data.GroupAccountSummaryCollectionData; import org.mifosplatform.portfolio.group.data.GroupAccountSummaryCollectionData;
import org.mifosplatform.portfolio.group.data.GroupData; 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.loanaccount.gaurantor.data.GuarantorData;
import org.mifosplatform.portfolio.savingsaccount.data.SavingAccountData; import org.mifosplatform.portfolio.savingsaccount.data.SavingAccountData;
import org.mifosplatform.portfolio.savingsaccount.data.SavingScheduleData; 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", private static final Set<String> LOAN_REASSIGNMENT_DATA_PARAMETERS = new HashSet<String>(Arrays.asList("officeId", "fromLoanOfficerId",
"assignmentDate", "officeOptions", "loanOfficerOptions", "accountSummaryCollection")); "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", private static final Set<String> SAVINGS_ACCOUNTS_DATA_PARAMETERS = new HashSet<String>(Arrays.asList("id", "status", "externalId",
"clientId", "clientName", "productId", "productName", "productType", "currencyData", "savingsDepostiAmountPerPeriod", "clientId", "clientName", "productId", "productName", "productType", "currencyData", "savingsDepostiAmountPerPeriod",
"savingsFrequencyType", "totalDepositAmount", "reccuringInterestRate", "savingInterestRate", "interestType", "savingsFrequencyType", "totalDepositAmount", "reccuringInterestRate", "savingInterestRate", "interestType",
@@ -210,13 +207,6 @@ public class GoogleGsonPortfolioApiJsonSerializerService implements PortfolioApi
return helper.serializedJsonFrom(gsonDeserializer, loanReassignmentData); 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 @Override
public String serializeStaffDataToJson(boolean prettyPrint, Set<String> responseParameters, StaffData staff) { public String serializeStaffDataToJson(boolean prettyPrint, Set<String> responseParameters, StaffData staff) {
final Gson gsonDeserializer = helper.createGsonBuilderWithParameterExclusionSerializationStrategy(STAFF_DATA_PARAMETERS, 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.command.NoteCommand;
import org.mifosplatform.portfolio.client.data.ClientData; import org.mifosplatform.portfolio.client.data.ClientData;
import org.mifosplatform.portfolio.group.command.GroupCommand; 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.loanaccount.gaurantor.command.GuarantorCommand;
import org.mifosplatform.portfolio.savingsaccount.command.SavingAccountCommand; import org.mifosplatform.portfolio.savingsaccount.command.SavingAccountCommand;
import org.mifosplatform.portfolio.savingsaccountproduct.command.SavingProductCommand; import org.mifosplatform.portfolio.savingsaccountproduct.command.SavingProductCommand;
@@ -25,8 +24,6 @@ public interface PortfolioApiDataConversionService {
GroupCommand convertJsonToGroupCommand(Long resourceIdentifier, String json); GroupCommand convertJsonToGroupCommand(Long resourceIdentifier, String json);
LoanChargeCommand convertJsonToLoanChargeCommand(Long loanChargeId, Long loanId, String json);
NoteCommand convertJsonToNoteCommand(Long resourceIdentifier, Long clientId, String json); NoteCommand convertJsonToNoteCommand(Long resourceIdentifier, Long clientId, String json);
DepositAccountCommand convertJsonToDepositAccountCommand(Long resourceIdentifier, 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.data.ClientData;
import org.mifosplatform.portfolio.client.serialization.ClientCommandFromApiJsonDeserializer; import org.mifosplatform.portfolio.client.serialization.ClientCommandFromApiJsonDeserializer;
import org.mifosplatform.portfolio.group.command.GroupCommand; 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.loanaccount.gaurantor.command.GuarantorCommand;
import org.mifosplatform.portfolio.savingsaccount.command.SavingAccountCommand; import org.mifosplatform.portfolio.savingsaccount.command.SavingAccountCommand;
import org.mifosplatform.portfolio.savingsaccountproduct.command.SavingProductCommand; 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); 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 @Override
public NoteCommand convertJsonToNoteCommand(final Long noteId, final Long clientId, final String json) { public NoteCommand convertJsonToNoteCommand(final Long noteId, final Long clientId, final String json) {
if (StringUtils.isBlank(json)) { throw new InvalidJsonException(); } 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.client.data.ClientAccountSummaryCollectionData;
import org.mifosplatform.portfolio.group.data.GroupAccountSummaryCollectionData; import org.mifosplatform.portfolio.group.data.GroupAccountSummaryCollectionData;
import org.mifosplatform.portfolio.group.data.GroupData; 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.loanaccount.gaurantor.data.GuarantorData;
import org.mifosplatform.portfolio.savingsaccount.data.SavingAccountData; import org.mifosplatform.portfolio.savingsaccount.data.SavingAccountData;
import org.mifosplatform.portfolio.savingsaccount.data.SavingScheduleData; import org.mifosplatform.portfolio.savingsaccount.data.SavingScheduleData;
@@ -53,8 +52,6 @@ public interface PortfolioApiJsonSerializerService {
String serializeLoanReassignmentDataToJson(boolean prettyPrint, Set<String> responseParameters, String serializeLoanReassignmentDataToJson(boolean prettyPrint, Set<String> responseParameters,
BulkTransferLoanOfficerData loanReassignmentData); 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, StaffData staff);
String serializeStaffDataToJson(boolean prettyPrint, Set<String> responseParameters, Collection<StaffData> staff); String serializeStaffDataToJson(boolean prettyPrint, Set<String> responseParameters, Collection<StaffData> staff);
@@ -1,6 +1,8 @@
package org.mifosplatform.portfolio.loanaccount.api; package org.mifosplatform.portfolio.loanaccount.api;
import java.util.Arrays;
import java.util.Collection; import java.util.Collection;
import java.util.HashSet;
import java.util.Set; import java.util.Set;
import javax.ws.rs.Consumes; import javax.ws.rs.Consumes;
@@ -14,23 +16,19 @@ import javax.ws.rs.Produces;
import javax.ws.rs.QueryParam; import javax.ws.rs.QueryParam;
import javax.ws.rs.core.Context; import javax.ws.rs.core.Context;
import javax.ws.rs.core.MediaType; import javax.ws.rs.core.MediaType;
import javax.ws.rs.core.Response;
import javax.ws.rs.core.UriInfo; import javax.ws.rs.core.UriInfo;
import org.apache.commons.lang.StringUtils; import org.apache.commons.lang.StringUtils;
import org.mifosplatform.infrastructure.core.api.ApiParameterHelper; import org.mifosplatform.commands.service.PortfolioCommandSourceWritePlatformService;
import org.mifosplatform.infrastructure.core.api.PortfolioApiDataConversionService; import org.mifosplatform.infrastructure.core.api.ApiRequestParameterHelper;
import org.mifosplatform.infrastructure.core.api.PortfolioApiJsonSerializerService;
import org.mifosplatform.infrastructure.core.data.EntityIdentifier; import org.mifosplatform.infrastructure.core.data.EntityIdentifier;
import org.mifosplatform.infrastructure.core.exception.UnrecognizedQueryParamException; 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.core.serialization.DefaultToApiJsonSerializer;
import org.mifosplatform.infrastructure.security.service.PlatformSecurityContext; import org.mifosplatform.infrastructure.security.service.PlatformSecurityContext;
import org.mifosplatform.portfolio.charge.data.ChargeData; import org.mifosplatform.portfolio.charge.data.ChargeData;
import org.mifosplatform.portfolio.charge.service.ChargeReadPlatformService; 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.data.LoanChargeData;
import org.mifosplatform.portfolio.loanaccount.service.LoanWritePlatformService;
import org.springframework.beans.factory.annotation.Autowired; import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Scope; import org.springframework.context.annotation.Scope;
import org.springframework.stereotype.Component; import org.springframework.stereotype.Component;
@@ -40,102 +38,87 @@ import org.springframework.stereotype.Component;
@Scope("singleton") @Scope("singleton")
public class LoanChargesApiResource { 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 PlatformSecurityContext context;
private final LoanWritePlatformService loanWritePlatformService;
private final ChargeReadPlatformService chargeReadPlatformService; private final ChargeReadPlatformService chargeReadPlatformService;
private final PortfolioApiJsonSerializerService apiJsonSerializerService; private final DefaultToApiJsonSerializer<LoanChargeData> toApiJsonSerializer;
private final PortfolioApiDataConversionService apiDataConversionService; private final ApiRequestParameterHelper apiRequestParameterHelper;
private final DefaultToApiJsonSerializer<LoanAccountData> toApiJsonSerializer; private final PortfolioCommandSourceWritePlatformService commandsSourceWritePlatformService;
// private final ApiRequestParameterHelper apiRequestParameterHelper;
// private final FromJsonHelper fromJsonHelper;
// private final PortfolioCommandSourceWritePlatformService commandsSourceWritePlatformService;
@Autowired @Autowired
public LoanChargesApiResource(final PlatformSecurityContext context, final LoanWritePlatformService loanWritePlatformService, public LoanChargesApiResource(final PlatformSecurityContext context, final ChargeReadPlatformService chargeReadPlatformService,
final ChargeReadPlatformService chargeReadPlatformService, final DefaultToApiJsonSerializer<LoanChargeData> toApiJsonSerializer,
final DefaultToApiJsonSerializer<LoanAccountData> toApiJsonSerializer, final ApiRequestParameterHelper apiRequestParameterHelper,
// final ApiRequestParameterHelper apiRequestParameterHelper, final PortfolioCommandSourceWritePlatformService commandsSourceWritePlatformService) {
final PortfolioApiJsonSerializerService apiJsonSerializerService,
final PortfolioApiDataConversionService apiDataConversionService
// , final FromJsonHelper fromJsonHelper,
// final PortfolioCommandSourceWritePlatformService
// commandsSourceWritePlatformService
) {
this.context = context; this.context = context;
this.loanWritePlatformService = loanWritePlatformService;
this.chargeReadPlatformService = chargeReadPlatformService; this.chargeReadPlatformService = chargeReadPlatformService;
this.toApiJsonSerializer = toApiJsonSerializer; this.toApiJsonSerializer = toApiJsonSerializer;
// this.apiRequestParameterHelper = apiRequestParameterHelper; this.apiRequestParameterHelper = apiRequestParameterHelper;
this.apiJsonSerializerService = apiJsonSerializerService; this.commandsSourceWritePlatformService = commandsSourceWritePlatformService;
this.apiDataConversionService = apiDataConversionService;
// this.fromJsonHelper = fromJsonHelper;
// this.commandsSourceWritePlatformService = commandsSourceWritePlatformService;
} }
private boolean is(final String commandParam, final String commandValue) { private boolean is(final String commandParam, final String commandValue) {
return StringUtils.isNotBlank(commandParam) && commandParam.trim().equalsIgnoreCase(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 @GET
@Path("template") @Path("template")
@Consumes({ MediaType.APPLICATION_JSON }) @Consumes({ MediaType.APPLICATION_JSON })
@Produces({ MediaType.APPLICATION_JSON }) @Produces({ MediaType.APPLICATION_JSON })
public String retrieveNewLoanChargeDetails(@Context final UriInfo uriInfo) { public String retrieveNewLoanChargeDetails(@Context final UriInfo uriInfo) {
context.authenticatedUser().validateHasReadPermission("LOAN"); context.authenticatedUser().validateHasReadPermission(resourceNameForPermissions);
final Set<String> responseParameters = ApiParameterHelper.extractFieldsForResponseIfProvided(uriInfo.getQueryParameters());
final boolean prettyPrint = ApiParameterHelper.prettyPrint(uriInfo.getQueryParameters());
final boolean feeChargesOnly = false; final boolean feeChargesOnly = false;
final Collection<ChargeData> chargeOptions = this.chargeReadPlatformService.retrieveLoanApplicableCharges(feeChargesOnly); final Collection<ChargeData> chargeOptions = this.chargeReadPlatformService.retrieveLoanApplicableCharges(feeChargesOnly);
final LoanChargeData loanChargeTemplate = LoanChargeData.template(chargeOptions); 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 @GET
@Path("{chargeId}") @Path("{loanChargeId}")
@Consumes({ MediaType.APPLICATION_JSON }) @Consumes({ MediaType.APPLICATION_JSON })
@Produces({ 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 final UriInfo uriInfo) {
context.authenticatedUser().validateHasReadPermission("LOAN"); context.authenticatedUser().validateHasReadPermission(resourceNameForPermissions);
final Set<String> responseParameters = ApiParameterHelper.extractFieldsForResponseIfProvided(uriInfo.getQueryParameters());
final boolean prettyPrint = ApiParameterHelper.prettyPrint(uriInfo.getQueryParameters());
final LoanChargeData loanCharge = this.chargeReadPlatformService.retrieveLoanChargeDetails(loanChargeId, loanId); 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 @PUT
@Path("{chargeId}") @Path("{loanChargeId}")
@Consumes({ MediaType.APPLICATION_JSON }) @Consumes({ MediaType.APPLICATION_JSON })
@Produces({ MediaType.APPLICATION_JSON }) @Produces({ MediaType.APPLICATION_JSON })
public String updateLoanCharge(@PathParam("loanId") final Long loanId, @PathParam("chargeId") final Long loanChargeId, public String updateLoanCharge(@PathParam("loanId") final Long loanId, @PathParam("loanChargeId") final Long loanChargeId,
final String jsonRequestBody) { final String apiRequestBodyAsJson) {
final LoanChargeCommand command = this.apiDataConversionService.convertJsonToLoanChargeCommand(loanChargeId, loanId, final EntityIdentifier result = this.commandsSourceWritePlatformService.logCommandSource("UPDATE", "LOANCHARGE", "N/A", "loans",
jsonRequestBody); loanId, "charges", loanChargeId, apiRequestBodyAsJson);
final EntityIdentifier identifier = this.loanWritePlatformService.updateLoanCharge(command); return this.toApiJsonSerializer.serialize(result);
return this.toApiJsonSerializer.serialize(identifier);
} }
@POST @POST
@@ -145,12 +128,12 @@ public class LoanChargesApiResource {
public String waiveLoanCharge(@PathParam("loanId") final Long loanId, @PathParam("chargeId") final Long loanChargeId, public String waiveLoanCharge(@PathParam("loanId") final Long loanId, @PathParam("chargeId") final Long loanChargeId,
@QueryParam("command") final String commandParam) { @QueryParam("command") final String commandParam) {
final LoanChargeCommand command = LoanChargeCommand.forWaiver(loanChargeId, loanId);
String json = ""; String json = "";
if (is(commandParam, "waive")) { if (is(commandParam, "waive")) {
final EntityIdentifier identifier = this.loanWritePlatformService.waiveLoanCharge(command); final EntityIdentifier result = this.commandsSourceWritePlatformService.logCommandSource("WAIVE", "LOANCHARGE", "N/A", "loans",
json = this.toApiJsonSerializer.serialize(identifier); loanId, "charges", loanChargeId, "{}");
json = this.toApiJsonSerializer.serialize(result);
} else { } else {
throw new UnrecognizedQueryParamException("command", commandParam); throw new UnrecognizedQueryParamException("command", commandParam);
} }
@@ -164,7 +147,9 @@ public class LoanChargesApiResource {
@Produces({ MediaType.APPLICATION_JSON }) @Produces({ MediaType.APPLICATION_JSON })
public String deleteLoanCharge(@PathParam("loanId") final Long loanId, @PathParam("chargeId") final Long loanChargeId) { public String deleteLoanCharge(@PathParam("loanId") final Long loanId, @PathParam("chargeId") final Long loanChargeId) {
final EntityIdentifier identifier = this.loanWritePlatformService.deleteLoanCharge(loanId, loanChargeId); final EntityIdentifier result = this.commandsSourceWritePlatformService.logCommandSource("DELETE", "LOANCHARGE", "N/A", "loans",
return this.toApiJsonSerializer.serialize(identifier); loanId, "charges", loanChargeId, "{}");
return this.toApiJsonSerializer.serialize(result);
} }
} }
@@ -30,8 +30,11 @@ import org.springframework.context.annotation.Scope;
import org.springframework.stereotype.Component; import org.springframework.stereotype.Component;
// FIXME: - undo disbursal fails when transactions have notes against them // 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") @Path("/loans/{loanId}/transactions")
@Component @Component
@Scope("singleton") @Scope("singleton")
@@ -289,8 +289,7 @@ public class LoanApplicationCommand {
if (this.charges != null) { if (this.charges != null) {
for (LoanChargeCommand loanChargeCommand : this.charges) { for (LoanChargeCommand loanChargeCommand : this.charges) {
try { try {
LoanChargeCommandValidator validator = new LoanChargeCommandValidator(loanChargeCommand); loanChargeCommand.validateForCreate();
validator.validateForCreate();
} catch (PlatformApiDataValidationException e) { } catch (PlatformApiDataValidationException e) {
dataValidationErrors.addAll(e.getErrors()); dataValidationErrors.addAll(e.getErrors());
} }
@@ -1,49 +1,34 @@
package org.mifosplatform.portfolio.loanaccount.command; package org.mifosplatform.portfolio.loanaccount.command;
import java.math.BigDecimal; import java.math.BigDecimal;
import java.util.HashSet; import java.util.ArrayList;
import java.util.Set; import java.util.List;
import org.joda.time.LocalDate; 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. * Immutable command for creating and updating loan charges.
*/ */
public class LoanChargeCommand implements Comparable<LoanChargeCommand> { public class LoanChargeCommand implements Comparable<LoanChargeCommand> {
private final Long id;
private final Long chargeId; private final Long chargeId;
private final Long loanId;
private final BigDecimal amount; private final BigDecimal amount;
private final Integer chargeTimeType; private final Integer chargeTimeType;
private final LocalDate specifiedDueDate; private final LocalDate specifiedDueDate;
private final Integer chargeCalculationType; private final Integer chargeCalculationType;
/** public LoanChargeCommand(final Long chargeId, final BigDecimal amount, final Integer chargeTimeType,
* Used to capture what parameters were passed in the json api request. It final Integer chargeCalculationType, final LocalDate specifiedDueDate) {
* 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;
this.chargeId = chargeId; this.chargeId = chargeId;
this.loanId = loanId;
this.amount = amount; this.amount = amount;
this.chargeTimeType = chargeTimeType; this.chargeTimeType = chargeTimeType;
this.chargeCalculationType = chargeCalculationType; this.chargeCalculationType = chargeCalculationType;
this.specifiedDueDate = specifiedDueDate; this.specifiedDueDate = specifiedDueDate;
} }
@Override @Override
public int compareTo(final LoanChargeCommand o) { public int compareTo(final LoanChargeCommand o) {
int comparison = this.chargeId.compareTo(o.chargeId); int comparison = this.chargeId.compareTo(o.chargeId);
@@ -53,47 +38,38 @@ public class LoanChargeCommand implements Comparable<LoanChargeCommand> {
return comparison; return comparison;
} }
public Long getId() { public void validateForCreate() {
return id; 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() { public void validateForUpdate() {
return chargeId; List<ApiParameterError> dataValidationErrors = new ArrayList<ApiParameterError>();
}
public Long getLoanId() { DataValidatorBuilder baseDataValidator = new DataValidatorBuilder(dataValidationErrors).resource("charge");
return loanId;
}
public BigDecimal getAmount() { baseDataValidator.reset().parameter("amount").value(this.amount).ignoreIfNull().positiveAmount();
return amount; 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() { if (!dataValidationErrors.isEmpty()) { throw new PlatformApiDataValidationException("validation.msg.validation.errors.exist",
return chargeTimeType; "Validation errors exist.", dataValidationErrors); }
}
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");
} }
} }
@@ -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 { public class LoanChargeData {
@SuppressWarnings("unused") @SuppressWarnings("unused")
private final Long id; private final Long id;
@SuppressWarnings("unused") @SuppressWarnings("unused")
private final Long chargeId; private final Long chargeId;
@SuppressWarnings("unused") @SuppressWarnings("unused")
private final String name; private final String name;
@SuppressWarnings("unused") @SuppressWarnings("unused")
private final EnumOptionData chargeTimeType; private final EnumOptionData chargeTimeType;
@SuppressWarnings("unused") @SuppressWarnings("unused")
private final LocalDate dueAsOfDate; private final LocalDate dueAsOfDate;
@SuppressWarnings("unused") @SuppressWarnings("unused")
private final EnumOptionData chargeCalculationType; private final EnumOptionData chargeCalculationType;
private final BigDecimal percentage; private final BigDecimal percentage;
@SuppressWarnings("unused") @SuppressWarnings("unused")
private final BigDecimal amountPercentageAppliedTo; private final BigDecimal amountPercentageAppliedTo;
@SuppressWarnings("unused") @SuppressWarnings("unused")
private final CurrencyData currency; private final CurrencyData currency;
@SuppressWarnings("unused") @SuppressWarnings("unused")
private final BigDecimal amount; 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") @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){ @SuppressWarnings("unused")
return new LoanChargeData(null,null,null,null,null,null,null, chargeOptions, false); 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, * used when populating with details from charge definition (for crud on
final Long chargeId, * charges)
final String name, */
final CurrencyData currency, public static LoanChargeData newLoanChargeDetails(final Long chargeId, final String name, final CurrencyData currency,
final BigDecimal amount, final BigDecimal value, final EnumOptionData chargeTimeType, final EnumOptionData chargeCalculationType, final boolean penalty) {
final BigDecimal amountPaid, return new LoanChargeData(null, chargeId, name, currency, value, chargeTimeType, chargeCalculationType, null, penalty);
final BigDecimal amountWaived, }
final BigDecimal amountWrittenOff,
final BigDecimal amountOutstanding, public LoanChargeData(final Long id, final Long chargeId, final String name, final CurrencyData currency, final BigDecimal amount,
final EnumOptionData chargeTimeType, final BigDecimal amountPaid, final BigDecimal amountWaived, final BigDecimal amountWrittenOff,
final LocalDate dueAsOfDate, final BigDecimal amountOutstanding, final EnumOptionData chargeTimeType, final LocalDate dueAsOfDate,
final EnumOptionData chargeCalculationType, final EnumOptionData chargeCalculationType, final BigDecimal percentage, final BigDecimal amountPercentageAppliedTo,
final BigDecimal percentage, final boolean penalty) {
final BigDecimal amountPercentageAppliedTo,
final boolean penalty) {
this.id = id; this.id = id;
this.chargeId = chargeId; this.chargeId = chargeId;
this.name = name; this.name = name;
this.currency = currency; this.currency = currency;
this.amount = amount; this.amount = amount;
this.amountPaid = amountPaid; this.amountPaid = amountPaid;
this.amountWaived = amountWaived; this.amountWaived = amountWaived;
this.amountWrittenOff = amountWrittenOff; this.amountWrittenOff = amountWrittenOff;
this.amountOutstanding = amountOutstanding; this.amountOutstanding = amountOutstanding;
this.chargeTimeType = chargeTimeType; this.chargeTimeType = chargeTimeType;
this.dueAsOfDate = dueAsOfDate; this.dueAsOfDate = dueAsOfDate;
this.chargeCalculationType = chargeCalculationType; this.chargeCalculationType = chargeCalculationType;
this.percentage = percentage; this.percentage = percentage;
this.amountPercentageAppliedTo = amountPercentageAppliedTo; this.amountPercentageAppliedTo = amountPercentageAppliedTo;
this.penalty = penalty; 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; this.chargeOptions = null;
} }
private LoanChargeData( private LoanChargeData(final Long id, final Long chargeId, final String name, final CurrencyData currency, final BigDecimal amount,
final Long id, final EnumOptionData chargeTimeType, final EnumOptionData chargeCalculationType, final Collection<ChargeData> chargeOptions,
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) { final boolean penalty) {
this.id = id; this.id = id;
this.chargeId = chargeId; this.chargeId = chargeId;
@@ -137,21 +114,21 @@ public class LoanChargeData {
this.amount = amount; this.amount = amount;
this.amountPaid = BigDecimal.ZERO; this.amountPaid = BigDecimal.ZERO;
this.amountWaived = BigDecimal.ZERO; this.amountWaived = BigDecimal.ZERO;
this.amountWrittenOff = BigDecimal.ZERO; this.amountWrittenOff = BigDecimal.ZERO;
this.amountOutstanding = amount; this.amountOutstanding = amount;
this.chargeTimeType = chargeTimeType; this.chargeTimeType = chargeTimeType;
this.dueAsOfDate = null; this.dueAsOfDate = null;
this.chargeCalculationType = chargeCalculationType; this.chargeCalculationType = chargeCalculationType;
this.percentage = null; this.percentage = null;
this.amountPercentageAppliedTo = null; this.amountPercentageAppliedTo = null;
this.penalty = penalty; this.penalty = penalty;
if (chargeCalculationType != null && chargeCalculationType.getId().intValue() > 1) { if (chargeCalculationType != null && chargeCalculationType.getId().intValue() > 1) {
this.amountOrPercentage = this.percentage; this.amountOrPercentage = this.percentage;
} else { } else {
this.amountOrPercentage = amount; this.amountOrPercentage = amount;
} }
this.chargeOptions = chargeOptions; 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); validateLoanIsNotClosed(loanCharge);
if (this.charges.contains(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(); updateTotalChargesDueAtDisbursement();
} }
@@ -441,13 +444,17 @@ public class Loan extends AbstractAuditableCustom<AppUser, Long> {
LoanScheduleWrapper wrapper = new LoanScheduleWrapper(); LoanScheduleWrapper wrapper = new LoanScheduleWrapper();
wrapper.reprocess(getCurrency(), getDisbursementDate(), this.repaymentScheduleInstallments, this.charges); 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); validateLoanIsNotClosed(loanCharge);
final Money amountWaived = loanCharge.waive(loanCurrency()); final Money amountWaived = loanCharge.waive(loanCurrency());
changes.put("amount", amountWaived.getAmount());
Money feeChargesWaived = Money.of(loanCurrency(), loanCharge.amount()); Money feeChargesWaived = Money.of(loanCurrency(), loanCharge.amount());
Money penaltyChargesWaived = Money.zero(loanCurrency()); Money penaltyChargesWaived = Money.zero(loanCurrency());
@@ -1368,9 +1375,11 @@ public class Loan extends AbstractAuditableCustom<AppUser, Long> {
return this.loanRepaymentScheduleDetail.getCurrency(); 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))) { if (!statusEnum.hasStateOf(LoanStatus.fromInt(this.loanStatus))) {
this.loanStatus = statusEnum.getValue(); this.loanStatus = statusEnum.getValue();
changes.put("status", LoanEnumerations.status(this.loanStatus)); changes.put("status", LoanEnumerations.status(this.loanStatus));
@@ -1382,7 +1391,7 @@ public class Loan extends AbstractAuditableCustom<AppUser, Long> {
this.writtenOffOnDate = writtenOffOnLocalDate.toDate(); this.writtenOffOnDate = writtenOffOnLocalDate.toDate();
changes.put("closedOnDate", command.stringValueOfParameterNamed("transactionDate")); changes.put("closedOnDate", command.stringValueOfParameterNamed("transactionDate"));
changes.put("writtenOffOnDate", command.stringValueOfParameterNamed("transactionDate")); changes.put("writtenOffOnDate", command.stringValueOfParameterNamed("transactionDate"));
if (writtenOffOnLocalDate.isBefore(this.getDisbursementDate())) { if (writtenOffOnLocalDate.isBefore(this.getDisbursementDate())) {
final String errorMessage = "The date on which a loan is written off cannot be before the loan disbursement date: " final String errorMessage = "The date on which a loan is written off cannot be before the loan disbursement date: "
+ getDisbursementDate().toString(); + getDisbursementDate().toString();
@@ -1412,7 +1421,8 @@ public class Loan extends AbstractAuditableCustom<AppUser, Long> {
return loanTransaction; 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"); final LocalDate closureDate = command.localDateValueOfParameterNamed("transactionDate");
@@ -1487,8 +1497,9 @@ public class Loan extends AbstractAuditableCustom<AppUser, Long> {
return totalOutstanding; 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)); final LoanStatus statusEnum = loanLifecycleStateMachine.transition(LoanEvent.REPAID_IN_FULL, LoanStatus.fromInt(this.loanStatus));
if (!statusEnum.hasStateOf(LoanStatus.fromInt(this.loanStatus))) { if (!statusEnum.hasStateOf(LoanStatus.fromInt(this.loanStatus))) {
this.loanStatus = statusEnum.getValue(); 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 * Behaviour added to comply with capability of previous mifos product to
* support easier transition to mifosx platform. * 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 LocalDate rescheduledOn = command.localDateValueOfParameterNamed("transactionDate");
final LoanStatus statusEnum = loanLifecycleStateMachine.transition(LoanEvent.LOAN_RESCHEDULE, LoanStatus.fromInt(this.loanStatus)); final LoanStatus statusEnum = loanLifecycleStateMachine.transition(LoanEvent.LOAN_RESCHEDULE, LoanStatus.fromInt(this.loanStatus));
if (!statusEnum.hasStateOf(LoanStatus.fromInt(this.loanStatus))) { if (!statusEnum.hasStateOf(LoanStatus.fromInt(this.loanStatus))) {
this.loanStatus = statusEnum.getValue(); this.loanStatus = statusEnum.getValue();
@@ -4,8 +4,8 @@ import java.math.BigDecimal;
import java.math.MathContext; import java.math.MathContext;
import java.math.RoundingMode; import java.math.RoundingMode;
import java.util.Date; import java.util.Date;
import java.util.HashSet; import java.util.LinkedHashMap;
import java.util.Set; import java.util.Map;
import javax.persistence.Column; import javax.persistence.Column;
import javax.persistence.Entity; import javax.persistence.Entity;
@@ -16,6 +16,7 @@ import javax.persistence.Temporal;
import javax.persistence.TemporalType; import javax.persistence.TemporalType;
import org.joda.time.LocalDate; 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.MonetaryCurrency;
import org.mifosplatform.organisation.monetary.domain.Money; import org.mifosplatform.organisation.monetary.domain.Money;
import org.mifosplatform.portfolio.charge.domain.Charge; import org.mifosplatform.portfolio.charge.domain.Charge;
@@ -74,16 +75,24 @@ public class LoanCharge extends AbstractPersistable<Long> {
@Column(name = "is_paid_derived", nullable = false) @Column(name = "is_paid_derived", nullable = false)
private boolean paid = false; private boolean paid = false;
public static LoanCharge createNew(final Loan loan, final Charge chargeDefinition, final LoanChargeCommand command) { public static LoanCharge createNewFromJson(final Loan loan, final Charge chargeDefinition, final JsonCommand command) {
return new LoanCharge(loan, chargeDefinition, command);
}
/* final BigDecimal amount = command.bigDecimalValueOfParameterNamed("amount");
* loanPrincipal is required for charges that are percentage based final Integer chargeTimeType = command.integerValueOfParameterNamed("chargeTimeType");
*/ final Integer chargeCalculationType = command.integerValueOfParameterNamed("chargeCalculationType");
public static LoanCharge createNewWithoutLoan(final Charge chargeDefinition, final LoanChargeCommand command, final LocalDate specifiedDueDate = command.localDateValueOfParameterNamed("specifiedDueDate");
final BigDecimal loanPrincipal) {
return new LoanCharge(chargeDefinition, command, loanPrincipal); 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, public static LoanCharge createNewWithoutLoan(final Charge chargeDefinition, final BigDecimal loanPrincipal, final BigDecimal amount,
final ChargeTimeType chargeTime, final ChargeCalculationType chargeCalculation, final LocalDate specifiedDueDate) { final ChargeTimeType chargeTime, final ChargeCalculationType chargeCalculation, final LocalDate specifiedDueDate) {
return new LoanCharge(chargeDefinition, loanPrincipal, amount, chargeTime, chargeCalculation, specifiedDueDate); return new LoanCharge(null, chargeDefinition, loanPrincipal, amount, chargeTime, chargeCalculation, specifiedDueDate);
}
public static LoanCharge createNew(final Charge chargeDefinition) {
return new LoanCharge(null, chargeDefinition);
} }
protected LoanCharge() { 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) { final ChargeTimeType chargeTime, final ChargeCalculationType chargeCalculation, final LocalDate specifiedDueDate) {
this.loan = null; this.loan = loan;
this.charge = chargeDefinition; this.charge = chargeDefinition;
this.penaltyCharge = chargeDefinition.isPenalty(); this.penaltyCharge = chargeDefinition.isPenalty();
@@ -140,85 +145,6 @@ public class LoanCharge extends AbstractPersistable<Long> {
this.paid = determineIfFullyPaid(); 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) { private void populateDerivedFields(final BigDecimal loanPrincipal, final BigDecimal chargeAmount) {
switch (ChargeCalculationType.fromInt(this.chargeCalculation)) { 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() { public void markAsFullyPaid() {
this.amountPaid = this.amount; this.amountPaid = this.amount;
this.amountOutstanding = BigDecimal.ZERO; this.amountOutstanding = BigDecimal.ZERO;
@@ -318,7 +230,7 @@ public class LoanCharge extends AbstractPersistable<Long> {
public void update(final Loan loan) { public void update(final Loan loan) {
this.loan = loan; this.loan = loan;
} }
public void update(final BigDecimal amount, final LocalDate specifiedDueDate, final BigDecimal loanPrincipal) { public void update(final BigDecimal amount, final LocalDate specifiedDueDate, final BigDecimal loanPrincipal) {
if (specifiedDueDate != null) { if (specifiedDueDate != null) {
this.dueForCollectionAsOfDate = specifiedDueDate.toDate(); 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()) { final Map<String, Object> actualChanges = new LinkedHashMap<String, Object>(7);
this.chargeTime = ChargeTimeType.fromInt(command.getChargeTimeType()).getValue();
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()) { final String chargeCalculationParamName = "chargeCalculation";
this.chargeCalculation = ChargeCalculationType.fromInt(command.getChargeCalculationType()).getValue(); 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()) { final String specifiedDueDateParamName = "specifiedDueDate";
this.dueForCollectionAsOfDate = command.getSpecifiedDueDate().toDate(); 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)) { switch (ChargeCalculationType.fromInt(this.chargeCalculation)) {
case INVALID: case INVALID:
break; break;
case FLAT: case FLAT:
this.amount = command.getAmount(); this.amount = newValue;
break; break;
case PERCENT_OF_AMOUNT: case PERCENT_OF_AMOUNT:
this.percentage = command.getAmount(); this.percentage = newValue;
this.amountPercentageAppliedTo = loanPrincipal; this.amountPercentageAppliedTo = loanPrincipal;
this.amount = percentageOf(this.amountPercentageAppliedTo, this.percentage); this.amount = percentageOf(this.amountPercentageAppliedTo, this.percentage);
this.amountOutstanding = calculateOutstanding(); this.amountOutstanding = calculateOutstanding();
break; break;
case PERCENT_OF_AMOUNT_AND_INTEREST: case PERCENT_OF_AMOUNT_AND_INTEREST:
this.percentage = command.getAmount(); this.percentage = newValue;
this.amount = null; this.amount = null;
this.amountPercentageAppliedTo = null; this.amountPercentageAppliedTo = null;
this.amountOutstanding = null; this.amountOutstanding = null;
break; break;
case PERCENT_OF_INTEREST: case PERCENT_OF_INTEREST:
this.percentage = command.getAmount(); this.percentage = newValue;
this.amount = null; this.amount = null;
this.amountPercentageAppliedTo = null; this.amountPercentageAppliedTo = null;
this.amountOutstanding = null; this.amountOutstanding = null;
break; break;
} }
} }
return actualChanges;
} }
public boolean isDueAtDisbursement() { public boolean isDueAtDisbursement() {
@@ -411,9 +349,7 @@ public class LoanCharge extends AbstractPersistable<Long> {
public LoanChargeCommand toCommand() { public LoanChargeCommand toCommand() {
final LocalDate specifiedDueDate = getDueForCollectionAsOfLocalDate(); final LocalDate specifiedDueDate = getDueForCollectionAsOfLocalDate();
final Set<String> modifiedParameters = new HashSet<String>(); return new LoanChargeCommand(this.charge.getId(), this.amount, this.chargeTime, this.chargeCalculation, specifiedDueDate);
return new LoanChargeCommand(modifiedParameters, this.getId(), this.loan.getId(), this.charge.getId(), this.amount,
this.chargeTime, this.chargeCalculation, specifiedDueDate);
} }
public LocalDate getDueForCollectionAsOfLocalDate() { 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++) { for (int i = 0; i < array.size(); i++) {
final JsonObject loanChargeElement = array.get(i).getAsJsonObject(); 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 Long chargeId = fromApiJsonHelper.extractLongNamed("chargeId", loanChargeElement);
final BigDecimal amount = fromApiJsonHelper.extractBigDecimalNamed("amount", loanChargeElement, locale); final BigDecimal amount = fromApiJsonHelper.extractBigDecimalNamed("amount", loanChargeElement, locale);
final Integer chargeTimeType = fromApiJsonHelper.extractIntegerNamed("chargeTimeType", 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, final LocalDate specifiedDueDate = fromApiJsonHelper.extractLocalDateNamed("specifiedDueDate", loanChargeElement,
dateFormat, locale); dateFormat, locale);
charges[i] = new LoanChargeCommand(parametersPassedInForChargesCommand, id, null, chargeId, amount, chargeTimeType, charges[i] = new LoanChargeCommand(chargeId, amount, chargeTimeType, chargeCalculationType, specifiedDueDate);
chargeCalculationType, specifiedDueDate);
} }
} }
} }
@@ -116,9 +116,9 @@ public final class LoanApplicationCommandFromApiJsonDeserializer extends Abstrac
for (int i = 0; i < array.size(); i++) { for (int i = 0; i < array.size(); i++) {
final JsonObject loanChargeElement = array.get(i).getAsJsonObject(); 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 Long chargeId = fromApiJsonHelper.extractLongNamed("chargeId", loanChargeElement);
final BigDecimal amount = fromApiJsonHelper.extractBigDecimalNamed("amount", loanChargeElement, locale); final BigDecimal amount = fromApiJsonHelper.extractBigDecimalNamed("amount", loanChargeElement, locale);
final Integer chargeTimeType = fromApiJsonHelper.extractIntegerNamed("chargeTimeType", 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, final LocalDate specifiedDueDate = fromApiJsonHelper.extractLocalDateNamed("specifiedDueDate", loanChargeElement,
dateFormat, locale); dateFormat, locale);
charges[i] = new LoanChargeCommand(parametersPassedInForChargesCommand, id, null, chargeId, amount, chargeTimeType, charges[i] = new LoanChargeCommand(chargeId, amount, chargeTimeType, chargeCalculationType, specifiedDueDate);
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.api.JsonCommand;
import org.mifosplatform.infrastructure.core.data.EntityIdentifier; import org.mifosplatform.infrastructure.core.data.EntityIdentifier;
import org.mifosplatform.organisation.staff.command.BulkTransferLoanOfficerCommand; import org.mifosplatform.organisation.staff.command.BulkTransferLoanOfficerCommand;
import org.mifosplatform.portfolio.loanaccount.command.LoanChargeCommand;
import org.springframework.security.access.prepost.PreAuthorize; import org.springframework.security.access.prepost.PreAuthorize;
public interface LoanWritePlatformService { public interface LoanWritePlatformService {
@@ -38,17 +37,13 @@ public interface LoanWritePlatformService {
EntityIdentifier closeAsRescheduled(Long loanId, JsonCommand command); EntityIdentifier closeAsRescheduled(Long loanId, JsonCommand command);
@PreAuthorize(value = "hasAnyRole('ALL_FUNCTIONS', 'PORTFOLIO_MANAGEMENT_SUPER_USER', 'CREATE_LOANCHARGE')") EntityIdentifier addLoanCharge(Long loanId, JsonCommand command);
EntityIdentifier addLoanCharge(LoanChargeCommand command);
@PreAuthorize(value = "hasAnyRole('ALL_FUNCTIONS', 'PORTFOLIO_MANAGEMENT_SUPER_USER', 'UPDATE_LOANCHARGE')") EntityIdentifier updateLoanCharge(Long loanId, Long loanChargeId, JsonCommand command);
EntityIdentifier updateLoanCharge(LoanChargeCommand command);
@PreAuthorize(value = "hasAnyRole('ALL_FUNCTIONS', 'PORTFOLIO_MANAGEMENT_SUPER_USER', 'DELETE_LOANCHARGE')") EntityIdentifier deleteLoanCharge(Long loanId, Long loanChargeId, JsonCommand command);
EntityIdentifier deleteLoanCharge(final Long loanId, final Long loanChargeId);
@PreAuthorize(value = "hasAnyRole('ALL_FUNCTIONS', 'PORTFOLIO_MANAGEMENT_SUPER_USER', 'WAIVE_LOANCHARGE')") EntityIdentifier waiveLoanCharge(Long loanId, Long loanChargeId, JsonCommand command);
EntityIdentifier waiveLoanCharge(LoanChargeCommand command);
@PreAuthorize(value = "hasAnyRole('ALL_FUNCTIONS', 'PORTFOLIO_MANAGEMENT_SUPER_USER', 'BULKREASSIGN_LOAN')") @PreAuthorize(value = "hasAnyRole('ALL_FUNCTIONS', 'PORTFOLIO_MANAGEMENT_SUPER_USER', 'BULKREASSIGN_LOAN')")
EntityIdentifier bulkLoanReassignment(final BulkTransferLoanOfficerCommand command); 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.fund.domain.Fund;
import org.mifosplatform.portfolio.loanaccount.command.LoanApplicationCommand; import org.mifosplatform.portfolio.loanaccount.command.LoanApplicationCommand;
import org.mifosplatform.portfolio.loanaccount.command.LoanChargeCommand; 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.LoanStateTransitionCommand;
import org.mifosplatform.portfolio.loanaccount.command.LoanTransactionCommand; import org.mifosplatform.portfolio.loanaccount.command.LoanTransactionCommand;
import org.mifosplatform.portfolio.loanaccount.domain.DefaultLoanLifecycleStateMachine; 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.loanschedule.service.LoanScheduleCalculationPlatformService;
import org.mifosplatform.portfolio.loanaccount.serialization.CalculateLoanScheduleQueryFromApiJsonDeserializer; import org.mifosplatform.portfolio.loanaccount.serialization.CalculateLoanScheduleQueryFromApiJsonDeserializer;
import org.mifosplatform.portfolio.loanaccount.serialization.LoanApplicationCommandFromApiJsonDeserializer; 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.LoanStateTransitionCommandFromApiJsonDeserializer;
import org.mifosplatform.portfolio.loanaccount.serialization.LoanTransactionCommandFromApiJsonDeserializer; import org.mifosplatform.portfolio.loanaccount.serialization.LoanTransactionCommandFromApiJsonDeserializer;
import org.mifosplatform.portfolio.loanproduct.domain.LoanProduct; import org.mifosplatform.portfolio.loanproduct.domain.LoanProduct;
@@ -78,6 +78,7 @@ public class LoanWritePlatformServiceJpaRepositoryImpl implements LoanWritePlatf
private final CalculateLoanScheduleQueryFromApiJsonDeserializer calculateLoanScheduleQueryFromApiJsonDeserializer; private final CalculateLoanScheduleQueryFromApiJsonDeserializer calculateLoanScheduleQueryFromApiJsonDeserializer;
private final LoanStateTransitionCommandFromApiJsonDeserializer loanStateTransitionCommandFromApiJsonDeserializer; private final LoanStateTransitionCommandFromApiJsonDeserializer loanStateTransitionCommandFromApiJsonDeserializer;
private final LoanTransactionCommandFromApiJsonDeserializer loanTransactionCommandFromApiJsonDeserializer; private final LoanTransactionCommandFromApiJsonDeserializer loanTransactionCommandFromApiJsonDeserializer;
private final LoanChargeCommandFromApiJsonDeserializer loanChargeCommandFromApiJsonDeserializer;
private final LoanRepository loanRepository; private final LoanRepository loanRepository;
private final NoteRepository noteRepository; private final NoteRepository noteRepository;
private final LoanScheduleCalculationPlatformService calculationPlatformService; private final LoanScheduleCalculationPlatformService calculationPlatformService;
@@ -96,6 +97,7 @@ public class LoanWritePlatformServiceJpaRepositoryImpl implements LoanWritePlatf
final LoanApplicationCommandFromApiJsonDeserializer fromApiJsonDeserializer, final LoanApplicationCommandFromApiJsonDeserializer fromApiJsonDeserializer,
final LoanStateTransitionCommandFromApiJsonDeserializer loanStateTransitionCommandFromApiJsonDeserializer, final LoanStateTransitionCommandFromApiJsonDeserializer loanStateTransitionCommandFromApiJsonDeserializer,
final LoanTransactionCommandFromApiJsonDeserializer loanTransactionCommandFromApiJsonDeserializer, final LoanTransactionCommandFromApiJsonDeserializer loanTransactionCommandFromApiJsonDeserializer,
final LoanChargeCommandFromApiJsonDeserializer loanChargeCommandFromApiJsonDeserializer,
final CalculateLoanScheduleQueryFromApiJsonDeserializer calculateLoanScheduleQueryFromApiJsonDeserializer, final CalculateLoanScheduleQueryFromApiJsonDeserializer calculateLoanScheduleQueryFromApiJsonDeserializer,
final AprCalculator aprCalculator, final LoanAssembler loanAssembler, final LoanChargeAssembler loanChargeAssembler, final AprCalculator aprCalculator, final LoanAssembler loanAssembler, final LoanChargeAssembler loanChargeAssembler,
final LoanRepository loanRepository, final LoanTransactionRepository loanTransactionRepository, final LoanRepository loanRepository, final LoanTransactionRepository loanTransactionRepository,
@@ -108,6 +110,7 @@ public class LoanWritePlatformServiceJpaRepositoryImpl implements LoanWritePlatf
this.fromApiJsonDeserializer = fromApiJsonDeserializer; this.fromApiJsonDeserializer = fromApiJsonDeserializer;
this.loanStateTransitionCommandFromApiJsonDeserializer = loanStateTransitionCommandFromApiJsonDeserializer; this.loanStateTransitionCommandFromApiJsonDeserializer = loanStateTransitionCommandFromApiJsonDeserializer;
this.loanTransactionCommandFromApiJsonDeserializer = loanTransactionCommandFromApiJsonDeserializer; this.loanTransactionCommandFromApiJsonDeserializer = loanTransactionCommandFromApiJsonDeserializer;
this.loanChargeCommandFromApiJsonDeserializer = loanChargeCommandFromApiJsonDeserializer;
this.calculateLoanScheduleQueryFromApiJsonDeserializer = calculateLoanScheduleQueryFromApiJsonDeserializer; this.calculateLoanScheduleQueryFromApiJsonDeserializer = calculateLoanScheduleQueryFromApiJsonDeserializer;
this.aprCalculator = aprCalculator; this.aprCalculator = aprCalculator;
this.loanAssembler = loanAssembler; this.loanAssembler = loanAssembler;
@@ -420,14 +423,14 @@ public class LoanWritePlatformServiceJpaRepositoryImpl implements LoanWritePlatf
final LoanTransactionCommand loanTransactionCommand = this.loanTransactionCommandFromApiJsonDeserializer.commandFromApiJson(command final LoanTransactionCommand loanTransactionCommand = this.loanTransactionCommandFromApiJsonDeserializer.commandFromApiJson(command
.json()); .json());
loanTransactionCommand.validate(); loanTransactionCommand.validate();
final LocalDate transactionDate = command.localDateValueOfParameterNamed("transactionDate"); final LocalDate transactionDate = command.localDateValueOfParameterNamed("transactionDate");
final BigDecimal transactionAmount = command.bigDecimalValueOfParameterNamed("transactionAmount"); final BigDecimal transactionAmount = command.bigDecimalValueOfParameterNamed("transactionAmount");
final Map<String, Object> changes = new LinkedHashMap<String, Object>(); final Map<String, Object> changes = new LinkedHashMap<String, Object>();
changes.put("transactionDate", command.stringValueOfParameterNamed("transactionDate")); changes.put("transactionDate", command.stringValueOfParameterNamed("transactionDate"));
changes.put("transactionAmount", command.stringValueOfParameterNamed("transactionAmount")); changes.put("transactionAmount", command.stringValueOfParameterNamed("transactionAmount"));
final Loan loan = retrieveLoanBy(loanId); final Loan loan = retrieveLoanBy(loanId);
if (this.isBeforeToday(transactionDate) && currentUser.canNotMakeRepaymentOnLoanInPast()) { throw new NoAuthorizationException( 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); Note note = Note.loanTransactionNote(loan, loanRepayment, noteText);
this.noteRepository.save(note); this.noteRepository.save(note);
} }
changes.put("locale", command.locale()); changes.put("locale", command.locale());
changes.put("dateFormat", command.dateFormat()); changes.put("dateFormat", command.dateFormat());
@@ -459,7 +462,7 @@ public class LoanWritePlatformServiceJpaRepositoryImpl implements LoanWritePlatf
final LoanTransactionCommand loanTransactionCommand = this.loanTransactionCommandFromApiJsonDeserializer.commandFromApiJson(command final LoanTransactionCommand loanTransactionCommand = this.loanTransactionCommandFromApiJsonDeserializer.commandFromApiJson(command
.json()); .json());
loanTransactionCommand.validate(); loanTransactionCommand.validate();
final Loan loan = retrieveLoanBy(loanId); final Loan loan = retrieveLoanBy(loanId);
final LoanTransaction transactionToAdjust = this.loanTransactionRepository.findOne(transactionId); final LoanTransaction transactionToAdjust = this.loanTransactionRepository.findOne(transactionId);
@@ -467,13 +470,13 @@ public class LoanWritePlatformServiceJpaRepositoryImpl implements LoanWritePlatf
final LocalDate transactionDate = command.localDateValueOfParameterNamed("transactionDate"); final LocalDate transactionDate = command.localDateValueOfParameterNamed("transactionDate");
final BigDecimal transactionAmount = command.bigDecimalValueOfParameterNamed("transactionAmount"); final BigDecimal transactionAmount = command.bigDecimalValueOfParameterNamed("transactionAmount");
final Map<String, Object> changes = new LinkedHashMap<String, Object>(); final Map<String, Object> changes = new LinkedHashMap<String, Object>();
changes.put("transactionDate", command.stringValueOfParameterNamed("transactionDate")); changes.put("transactionDate", command.stringValueOfParameterNamed("transactionDate"));
changes.put("transactionAmount", command.stringValueOfParameterNamed("transactionAmount")); changes.put("transactionAmount", command.stringValueOfParameterNamed("transactionAmount"));
final LoanTransaction newTransactionDetail = loan.adjustExistingTransaction(transactionDate, transactionAmount, defaultLoanLifecycleStateMachine(), final LoanTransaction newTransactionDetail = loan.adjustExistingTransaction(transactionDate, transactionAmount,
transactionToAdjust); defaultLoanLifecycleStateMachine(), transactionToAdjust);
if (newTransactionDetail.isGreaterThanZero(loan.getPrincpal().getCurrency())) { if (newTransactionDetail.isGreaterThanZero(loan.getPrincpal().getCurrency())) {
this.loanTransactionRepository.save(newTransactionDetail); this.loanTransactionRepository.save(newTransactionDetail);
} }
@@ -489,7 +492,7 @@ public class LoanWritePlatformServiceJpaRepositoryImpl implements LoanWritePlatf
changes.put("locale", command.locale()); changes.put("locale", command.locale());
changes.put("dateFormat", command.dateFormat()); changes.put("dateFormat", command.dateFormat());
return EntityIdentifier.subResourceResult(loanId, transactionId, command.commandId(), changes); return EntityIdentifier.subResourceResult(loanId, transactionId, command.commandId(), changes);
} }
@@ -502,7 +505,7 @@ public class LoanWritePlatformServiceJpaRepositoryImpl implements LoanWritePlatf
final LoanTransactionCommand loanTransactionCommand = this.loanTransactionCommandFromApiJsonDeserializer.commandFromApiJson(command final LoanTransactionCommand loanTransactionCommand = this.loanTransactionCommandFromApiJsonDeserializer.commandFromApiJson(command
.json()); .json());
loanTransactionCommand.validate(); loanTransactionCommand.validate();
final Map<String, Object> changes = new LinkedHashMap<String, Object>(); final Map<String, Object> changes = new LinkedHashMap<String, Object>();
changes.put("transactionDate", command.stringValueOfParameterNamed("transactionDate")); changes.put("transactionDate", command.stringValueOfParameterNamed("transactionDate"));
changes.put("transactionAmount", command.stringValueOfParameterNamed("transactionAmount")); changes.put("transactionAmount", command.stringValueOfParameterNamed("transactionAmount"));
@@ -520,7 +523,7 @@ public class LoanWritePlatformServiceJpaRepositoryImpl implements LoanWritePlatf
final Note note = Note.loanTransactionNote(loan, waiveTransaction, noteText); final Note note = Note.loanTransactionNote(loan, waiveTransaction, noteText);
this.noteRepository.save(note); this.noteRepository.save(note);
} }
changes.put("locale", command.locale()); changes.put("locale", command.locale());
changes.put("dateFormat", command.dateFormat()); changes.put("dateFormat", command.dateFormat());
@@ -535,7 +538,7 @@ public class LoanWritePlatformServiceJpaRepositoryImpl implements LoanWritePlatf
final LoanTransactionCommand loanTransactionCommand = this.loanTransactionCommandFromApiJsonDeserializer.commandFromApiJson(command final LoanTransactionCommand loanTransactionCommand = this.loanTransactionCommandFromApiJsonDeserializer.commandFromApiJson(command
.json()); .json());
loanTransactionCommand.validateNonMonetaryTransaction(); loanTransactionCommand.validateNonMonetaryTransaction();
final Map<String, Object> changes = new LinkedHashMap<String, Object>(); final Map<String, Object> changes = new LinkedHashMap<String, Object>();
changes.put("transactionDate", command.stringValueOfParameterNamed("transactionDate")); changes.put("transactionDate", command.stringValueOfParameterNamed("transactionDate"));
@@ -570,7 +573,7 @@ public class LoanWritePlatformServiceJpaRepositoryImpl implements LoanWritePlatf
loanTransactionCommand.validateNonMonetaryTransaction(); loanTransactionCommand.validateNonMonetaryTransaction();
final Loan loan = retrieveLoanBy(loanId); final Loan loan = retrieveLoanBy(loanId);
final Map<String, Object> changes = new LinkedHashMap<String, Object>(); final Map<String, Object> changes = new LinkedHashMap<String, Object>();
changes.put("transactionDate", command.stringValueOfParameterNamed("transactionDate")); changes.put("transactionDate", command.stringValueOfParameterNamed("transactionDate"));
@@ -586,17 +589,17 @@ public class LoanWritePlatformServiceJpaRepositoryImpl implements LoanWritePlatf
final Note note = Note.loanNote(loan, noteText); final Note note = Note.loanNote(loan, noteText);
this.noteRepository.save(note); this.noteRepository.save(note);
} }
changes.put("locale", command.locale()); changes.put("locale", command.locale());
changes.put("dateFormat", command.dateFormat()); changes.put("dateFormat", command.dateFormat());
EntityIdentifier result = null; EntityIdentifier result = null;
if (possibleClosingTransaction != null) { if (possibleClosingTransaction != null) {
result = EntityIdentifier.subResourceResult(loanId, possibleClosingTransaction.getId(), command.commandId(), changes); result = EntityIdentifier.subResourceResult(loanId, possibleClosingTransaction.getId(), command.commandId(), changes);
} else { } else {
result = EntityIdentifier.resourceResult(loanId, command.commandId(), changes); result = EntityIdentifier.resourceResult(loanId, command.commandId(), changes);
} }
return result; return result;
} }
@@ -610,7 +613,7 @@ public class LoanWritePlatformServiceJpaRepositoryImpl implements LoanWritePlatf
loanTransactionCommand.validateNonMonetaryTransaction(); loanTransactionCommand.validateNonMonetaryTransaction();
final Loan loan = retrieveLoanBy(loanId); final Loan loan = retrieveLoanBy(loanId);
final Map<String, Object> changes = new LinkedHashMap<String, Object>(); final Map<String, Object> changes = new LinkedHashMap<String, Object>();
changes.put("transactionDate", command.stringValueOfParameterNamed("transactionDate")); changes.put("transactionDate", command.stringValueOfParameterNamed("transactionDate"));
@@ -624,7 +627,7 @@ public class LoanWritePlatformServiceJpaRepositoryImpl implements LoanWritePlatf
final Note note = Note.loanNote(loan, noteText); final Note note = Note.loanNote(loan, noteText);
this.noteRepository.save(note); this.noteRepository.save(note);
} }
changes.put("locale", command.locale()); changes.put("locale", command.locale());
changes.put("dateFormat", command.dateFormat()); changes.put("dateFormat", command.dateFormat());
@@ -633,72 +636,68 @@ public class LoanWritePlatformServiceJpaRepositoryImpl implements LoanWritePlatf
@Transactional @Transactional
@Override @Override
public EntityIdentifier addLoanCharge(final LoanChargeCommand command) { public EntityIdentifier addLoanCharge(final Long loanId, final JsonCommand command) {
this.context.authenticatedUser(); this.context.authenticatedUser();
LoanChargeCommandValidator validator = new LoanChargeCommandValidator(command); final LoanChargeCommand loanChargeCommand = this.loanChargeCommandFromApiJsonDeserializer.commandFromApiJson(command.json());
validator.validateForCreate(); loanChargeCommand.validateForCreate();
final Loan loan = this.loanRepository.findOne(command.getLoanId()); final Loan loan = retrieveLoanBy(loanId);
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 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()); } 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())) { if (!loan.hasCurrencyCodeOf(chargeDefinition.getCurrencyCode())) {
String errorMessage = "Charge and Loan must have the same currency."; String errorMessage = "Charge and Loan must have the same currency.";
throw new InvalidCurrencyException("charge", "attach.to.loan", errorMessage); throw new InvalidCurrencyException("charge", "attach.to.loan", errorMessage);
} }
this.loanChargeRepository.save(loanCharge);
loan.addLoanCharge(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 @Transactional
@Override @Override
public EntityIdentifier updateLoanCharge(final LoanChargeCommand command) { public EntityIdentifier updateLoanCharge(final Long loanId, final Long loanChargeId, final JsonCommand command) {
this.context.authenticatedUser(); this.context.authenticatedUser();
LoanChargeCommandValidator validator = new LoanChargeCommandValidator(command); final LoanChargeCommand loanChargeCommand = this.loanChargeCommandFromApiJsonDeserializer.commandFromApiJson(command.json());
validator.validateForUpdate(); loanChargeCommand.validateForUpdate();
final Long loanId = command.getLoanId();
final Loan loan = retrieveLoanBy(loanId); final Loan loan = retrieveLoanBy(loanId);
final Long loanChargeId = command.getId();
final LoanCharge loanCharge = retrieveLoanChargeBy(loanId, loanChargeId); final LoanCharge loanCharge = retrieveLoanChargeBy(loanId, loanChargeId);
loan.updateLoanCharge(loanCharge, command); final Map<String, Object> changes = loan.updateLoanCharge(loanCharge, command);
this.loanRepository.save(loan); this.loanRepository.save(loan);
return new EntityIdentifier(loanCharge.getId()); return EntityIdentifier.subResourceResult(loanId, loanChargeId, command.commandId(), changes);
} }
@Transactional @Transactional
@Override @Override
public EntityIdentifier waiveLoanCharge(final LoanChargeCommand command) { public EntityIdentifier waiveLoanCharge(final Long loanId, final Long loanChargeId, final JsonCommand command) {
this.context.authenticatedUser(); this.context.authenticatedUser();
// LoanChargeCommandValidator validator = new final LoanChargeCommand loanChargeCommand = this.loanChargeCommandFromApiJsonDeserializer.commandFromApiJson(command.json());
// LoanChargeCommandValidator(command); loanChargeCommand.validateForUpdate();
// validator.validateForUpdate();
final Long loanId = command.getLoanId();
final Loan loan = retrieveLoanBy(loanId); final Loan loan = retrieveLoanBy(loanId);
final Long loanChargeId = command.getId();
final LoanCharge loanCharge = retrieveLoanChargeBy(loanId, loanChargeId); 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.loanTransactionRepository.save(waiveTransaction);
this.loanRepository.save(loan); this.loanRepository.save(loan);
@@ -709,23 +708,22 @@ public class LoanWritePlatformServiceJpaRepositoryImpl implements LoanWritePlatf
this.noteRepository.save(note); this.noteRepository.save(note);
} }
return new EntityIdentifier(loanCharge.getId()); return EntityIdentifier.subResourceResult(loanId, loanChargeId, command.commandId(), changes);
} }
@Transactional @Transactional
@Override @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(); this.context.authenticatedUser();
final Loan loan = retrieveLoanBy(loanId); final Loan loan = retrieveLoanBy(loanId);
final LoanCharge loanCharge = retrieveLoanChargeBy(loanId, loanChargeId); final LoanCharge loanCharge = retrieveLoanChargeBy(loanId, loanChargeId);
loan.removeLoanCharge(loanCharge); loan.removeLoanCharge(loanCharge);
this.loanRepository.save(loan); this.loanRepository.save(loan);
return new EntityIdentifier(loanCharge.getId()); return EntityIdentifier.subResourceResult(loanId, loanChargeId, command.commandId());
} }
private Loan retrieveLoanBy(final Long loanId) { private Loan retrieveLoanBy(final Long loanId) {