support update single piece of information for loan product and tidy up validation.

This commit is contained in:
Keith Woodlock
2012-05-24 01:56:50 +01:00
parent b5d94a8c95
commit 9c8edb45a3
12 changed files with 518 additions and 348 deletions
@@ -15,13 +15,16 @@ public class LoanProductCommand {
private String currencyCode;
private Integer digitsAfterDecimal;
private BigDecimal principal;
private String principalFormatted;
private BigDecimal inArrearsToleranceAmount;
private String inArrearsToleranceAmountFormatted;
private Integer repaymentEvery;
private Integer repaymentFrequency;
private Integer numberOfRepayments;
private BigDecimal interestRatePerPeriod;
private String interestRatePerPeriodFormatted;
private Integer interestRateFrequencyMethod;
private Integer amortizationMethod;
private Integer interestMethod;
@@ -159,4 +162,30 @@ public class LoanProductCommand {
Integer interestCalculationPeriodMethod) {
this.interestCalculationPeriodMethod = interestCalculationPeriodMethod;
}
public String getPrincipalFormatted() {
return principalFormatted;
}
public void setPrincipalFormatted(String principalFormatted) {
this.principalFormatted = principalFormatted;
}
public String getInterestRatePerPeriodFormatted() {
return interestRatePerPeriodFormatted;
}
public void setInterestRatePerPeriodFormatted(
String interestRatePerPeriodFormatted) {
this.interestRatePerPeriodFormatted = interestRatePerPeriodFormatted;
}
public String getInArrearsToleranceAmountFormatted() {
return inArrearsToleranceAmountFormatted;
}
public void setInArrearsToleranceAmountFormatted(
String inArrearsToleranceAmountFormatted) {
this.inArrearsToleranceAmountFormatted = inArrearsToleranceAmountFormatted;
}
}
@@ -242,16 +242,18 @@ form.label.loan.product.interest.rate.calcutated.in.period=Interest calculation
validation.msg.product.name.cannot.be.blank=Product name cannot be blank.
validation.msg.product.description.exceeds.max.length=The content of the description has exceeded max allowed length of 500 characters.
validation.msg.product.currency.digitsAfterDecimal.cannot.be.empty=You must enter a number to represent number of digits after decimal to be supported for product.
validation.msg.product.principal.amount.cannot.be.empty=Loan amount cannot be blank.
validation.msg.product.digitsAfterDecimal.is.not.within.expected.range=Decimal places must be a number between {1} and {2} inclusive.
validation.msg.product.repayment.repaidEvery.cannot.be.empty=Repaid every cannot be blank.
validation.msg.product.repaymentEvery.not.greater.than.zero=Repaid every must be greater than 0.
validation.msg.product.number.of.repayments.cannot.be.empty=# of repayments cannot be blank.
validation.msg.product.arrears.tolerance.amount.cannot.be.empty=Arrears tolerance cannot be blank.
validation.msg.product.interest.rate.per.period.amount.cannot.be.empty=Nominal interest rate % cannot be blank.
validation.msg.product.numberOfRepayments.not.greater.than.zero=# of repayments must be greater than 0.
validation.msg.product.principalFormatted.cannot.be.blank=Loan amount cannot be blank.
validation.msg.product.inArrearsToleranceAmountFormatted.cannot.be.blank=Arrears tolerance cannot be blank.
validation.msg.product.interestRatePerPeriodFormatted.cannot.be.blank=Nominal interest rate % cannot be blank.
validation.msg.product.currency.digitsAfterDecimal.must.be.between.zero.and.six.inclusive=Decimal places must be a number between zero and six inclusive.
validation.msg.product.principal.amount.must.be.greater.than.zero=Loan amount must be greater than zero.
validation.msg.product.repayment.repaidEvery.outside.allowed.range=Repaid every must be between {0} and {1} inclusive given the selected repayment frequency type.
validation.msg.product.number.of.repayments.is.out.of.range=# of repayments is out of allowed range for selected repayment frequency type.
validation.msg.product.arrears.tolerance.amount.cannot.be.negative=Arrears tolerance cannot be negative.
validation.msg.product.interest.rate.per.period.amount.cannot.be.negative=Nominal interest rate % cannot be negative.
@@ -270,8 +272,10 @@ form.label.office.openedon=Opened on:
form.label.office.externalid=External id:
validation.msg.office.name.cannot.be.blank=Office name cannot be blank.
validation.msg.office.parent.cannot.be.blank=You must select a parent office.
validation.msg.office.opening.date.cannot.be.blank=You must choose a date to represent when the office commenced services.
validation.msg.office.parentId.cannot.be.blank=You must select a parent office.
validation.msg.office.parentId.not.greater.than.zero=You must select a parent office.
validation.msg.office.openingDateFormatted.cannot.be.blank=You must choose a date to represent when the office commenced services.
validation.msg.office.externalId.exceeds.max.length=External id exceeds max length of {0} alpha-numeric characters - {1}.
dialog.title.configuration.currencies=Currency Configuration
form.label.configuration.available.currencies=Available currencies:
@@ -241,16 +241,18 @@ form.label.loan.product.interest.rate.calcutated.in.period=Interest calculation
validation.msg.product.name.cannot.be.blank=Product name cannot be blank.(fr)
validation.msg.product.description.exceeds.max.length=The content of the description has exceeded max allowed length of 500 characters.(fr)
validation.msg.product.currency.digitsAfterDecimal.cannot.be.empty=You must enter a number to represent number of digits after decimal to be supported for product.(fr)
validation.msg.product.principal.amount.cannot.be.empty=Loan amount cannot be blank.(fr)
validation.msg.product.digitsAfterDecimal.is.not.within.expected.range=Decimal places must be a number between {1} and {2} inclusive.
validation.msg.product.repayment.repaidEvery.cannot.be.empty=Repaid every cannot be blank.(fr)
validation.msg.product.repaymentEvery.not.greater.than.zero=Repaid every must be greater than 0.(fr)
validation.msg.product.number.of.repayments.cannot.be.empty=# of repayments cannot be blank.(fr)
validation.msg.product.arrears.tolerance.amount.cannot.be.empty=Arrears tolerance cannot be blank.(fr)
validation.msg.product.interest.rate.per.period.amount.cannot.be.empty=Nominal interest rate % cannot be blank.(fr)
validation.msg.product.numberOfRepayments.not.greater.than.zero=# of repayments must be greater than 0.(fr)
validation.msg.product.principalFormatted.cannot.be.blank=Loan amount cannot be blank.(fr)
validation.msg.product.inArrearsToleranceAmountFormatted.cannot.be.blank=Arrears tolerance cannot be blank.(fr)
validation.msg.product.interestRatePerPeriodFormatted.cannot.be.blank=Nominal interest rate % cannot be blank.(fr)
validation.msg.product.currency.digitsAfterDecimal.must.be.between.zero.and.six.inclusive=Decimal places must be a number between zero and six inclusive.(fr)
validation.msg.product.principal.amount.must.be.greater.than.zero=Loan amount must be greater than zero.(fr)
validation.msg.product.repayment.repaidEvery.outside.allowed.range=Repaid every is out of allowed range for selected repayment frequency type.(fr)
validation.msg.product.number.of.repayments.is.out.of.range=# of repayments is out of allowed range for selected repayment frequency type.(fr)
validation.msg.product.arrears.tolerance.amount.cannot.be.negative=Arrears tolerance cannot be negative.(fr)
validation.msg.product.interest.rate.per.period.amount.cannot.be.negative=Nominal interest rate % cannot be negative.(fr)
@@ -269,8 +271,10 @@ form.label.office.openedon=Opened on:(fr)
form.label.office.externalid=External id:(fr)
validation.msg.office.name.cannot.be.blank=Office name cannot be blank.(fr)
validation.msg.office.parent.cannot.be.blank=You must select a parent office.(fr)
validation.msg.office.opening.date.cannot.be.blank=You must choose a date to represent when the office commenced services.(fr)
validation.msg.office.parentId.cannot.be.blank=You must select a parent office.(fr)
validation.msg.office.parentId.not.greater.than.zero=You must select a parent office.(fr)
validation.msg.office.openingDateFormatted.cannot.be.blank=You must choose a date to represent when the office commenced services.(fr)
validation.msg.office.externalId.exceeds.max.length=External id exceeds max length of {0} alpha-numeric characters - {1}.(fr)
form.label.configuration.available.currencies=Available currencies:(fr)
form.label.configuration.allowed.currencies=Allowed currencies:(fr)
@@ -57,7 +57,7 @@
<tr>
<td><spring:message code="form.label.loan.product.loan.amount"/></td>
<td>
<input id="principal" name="principal" title="" style="width: 125px;" value="{{=$ctx.money(principalMoney)}}" />
<input id="principalFormatted" name="principalFormatted" title="" style="width: 125px;" value="{{=$ctx.money(principalMoney)}}" />
</td>
</tr>
<tr>
@@ -89,7 +89,7 @@
<tr>
<td><spring:message code="form.label.loan.product.nominal.interestrate"/></td>
<td>
<input id="interestRatePerPeriod" name="interestRatePerPeriod" title="" style="width: 70px;" value="{{=$ctx.decimal(interestRatePerPeriod, 4)}}" />
<input id="interestRatePerPeriodFormatted" name="interestRatePerPeriodFormatted" title="" style="width: 70px;" value="{{=$ctx.decimal(interestRatePerPeriod, 4)}}" />
<select id="interestRateFrequencyMethod" name="interestRateFrequencyMethod" title="" style="width: 139px;">
{{#each interestFrequencyOptions}}
@@ -147,7 +147,7 @@
<tr>
<td><spring:message code="form.label.loan.product.arrears.tolerance"/></td>
<td>
<input id="inArrearsToleranceAmount" name="inArrearsToleranceAmount" title="" style="width: 215px;" value="{{=$ctx.money(inArrearsTolerance)}}" />
<input id="inArrearsToleranceAmountFormatted" name="inArrearsToleranceAmountFormatted" title="" style="width: 215px;" value="{{=$ctx.money(inArrearsTolerance)}}" />
</td>
</tr>
</table>
@@ -0,0 +1,133 @@
package org.mifosng.platform;
import java.util.List;
import org.apache.commons.lang.StringUtils;
import org.mifosng.data.ApiParameterError;
public class DataValidatorBuilder {
private final List<ApiParameterError> dataValidationErrors;
private String resource;
private String parameter;
private Object value;
private boolean ignoreNullValue = false;
public DataValidatorBuilder(List<ApiParameterError> dataValidationErrors) {
this.dataValidationErrors = dataValidationErrors;
}
public DataValidatorBuilder reset() {
return new DataValidatorBuilder(dataValidationErrors).resource(resource);
}
public DataValidatorBuilder resource(final String resource) {
this.resource = resource;
return this;
}
public DataValidatorBuilder parameter(final String parameter) {
this.parameter = parameter;
return this;
}
public DataValidatorBuilder value(Object value) {
this.value = value;
return this;
}
public DataValidatorBuilder ignoreIfNull() {
this.ignoreNullValue = true;
return this;
}
public DataValidatorBuilder notNull() {
if (value == null && !ignoreNullValue) {
StringBuilder validationErrorCode = new StringBuilder("validation.msg.").append(resource).append(".").append(parameter).append(".cannot.be.blank");
StringBuilder defaultEnglishMessage = new StringBuilder("The parameter ").append(parameter).append(" cannot be blank.");
ApiParameterError error = ApiParameterError.parameterError(validationErrorCode.toString(), defaultEnglishMessage.toString(), parameter);
dataValidationErrors.add(error);
}
return this;
}
public DataValidatorBuilder notBlank() {
if (value == null && ignoreNullValue) {
return this;
}
if (StringUtils.isBlank(value.toString())) {
StringBuilder validationErrorCode = new StringBuilder("validation.msg.").append(resource).append(".").append(parameter).append(".cannot.be.blank");
StringBuilder defaultEnglishMessage = new StringBuilder("The parameter ").append(parameter).append(" cannot be blank.");
ApiParameterError error = ApiParameterError.parameterError(validationErrorCode.toString(), defaultEnglishMessage.toString(), parameter);
dataValidationErrors.add(error);
}
return this;
}
public DataValidatorBuilder notExceedingLengthOf(Integer maxLength) {
if (value == null && ignoreNullValue) {
return this;
}
if (value != null && value.toString().trim().length() > maxLength) {
StringBuilder validationErrorCode = new StringBuilder("validation.msg.").append(resource).append(".").append(parameter).append(".exceeds.max.length");
StringBuilder defaultEnglishMessage = new StringBuilder("The parameter ").append(parameter).append(" exceeds max length of ").append(maxLength).append(".");
ApiParameterError error = ApiParameterError.parameterError(validationErrorCode.toString(), defaultEnglishMessage.toString(), parameter, maxLength, value.toString());
dataValidationErrors.add(error);
}
return this;
}
public DataValidatorBuilder inMinMaxRange(Integer min, Integer max) {
if (value == null && ignoreNullValue) {
return this;
}
if (value != null) {
Integer number = Integer.valueOf(value.toString());
if (number < min || number > max) {
StringBuilder validationErrorCode = new StringBuilder("validation.msg.").append(resource).append(".").append(parameter).append(".is.not.within.expected.range");
StringBuilder defaultEnglishMessage = new StringBuilder("The parameter ").append(parameter).append(" must be between ").append(min).append(" and ").append(max).append(".");
ApiParameterError error = ApiParameterError.parameterError(validationErrorCode.toString(), defaultEnglishMessage.toString(), parameter, number, min, max);
dataValidationErrors.add(error);
}
}
return this;
}
public DataValidatorBuilder greaterThanZero() {
if (value == null && ignoreNullValue) {
return this;
}
if (value != null) {
Integer number = Integer.valueOf(value.toString());
if (number < 1) {
StringBuilder validationErrorCode = new StringBuilder("validation.msg.").append(resource).append(".").append(parameter).append(".not.greater.than.zero");
StringBuilder defaultEnglishMessage = new StringBuilder("The parameter ").append(parameter).append(" must be greater than 0.");
ApiParameterError error = ApiParameterError.parameterError(validationErrorCode.toString(), defaultEnglishMessage.toString(), parameter, number, 0);
dataValidationErrors.add(error);
}
}
return this;
}
public DataValidatorBuilder anyOfNotNull(Object... object) {
boolean hasData = false;
for (Object obj : object) {
if (obj != null) {
hasData = true;
break;
}
}
if (!hasData) {
StringBuilder validationErrorCode = new StringBuilder("validation.msg.").append(resource).append(".no.parameters.for.update");
StringBuilder defaultEnglishMessage = new StringBuilder("No parameters passed for update.");
ApiParameterError error = ApiParameterError.parameterError(validationErrorCode.toString(), defaultEnglishMessage.toString(), "id");
dataValidationErrors.add(error);
}
return this;
}
}
@@ -1,6 +1,8 @@
package org.mifosng.platform.api;
import java.math.BigDecimal;
import java.util.Collection;
import java.util.Locale;
import javax.ws.rs.Consumes;
import javax.ws.rs.GET;
@@ -16,31 +18,13 @@ import org.mifosng.data.EntityIdentifier;
import org.mifosng.data.LoanProductData;
import org.mifosng.data.LoanProductList;
import org.mifosng.data.command.LoanProductCommand;
import org.mifosng.platform.api.infrastructure.ApiDataConversionService;
import org.mifosng.platform.loanproduct.service.LoanProductReadPlatformService;
import org.mifosng.platform.loanproduct.service.LoanProductWritePlatformService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Scope;
import org.springframework.stereotype.Component;
/*
* @see http://viewfromthefringe.blogspot.com/2010/06/versioning-rest-services.html
* @see http://jersey.576304.n2.nabble.com/Restful-Service-Versioning-td6332833.html
*
* Note: Jersey looks for 'requests' starting with 'api' e.g. this resources url is https://[localhost:8080]/api/v1/loanproducts
* Note: Named this class *ApiResource as if you leave it as same class name as older 'resource' class, jersey throws a wobbler.
* Note: no authentication scheme is in place so calls that match api/v1/** are not managed by spring security for now.
*
* 1. resource is versioned here but will move the 'version' part to web.xml when finished.
* 2. using plural of resource e.g. loanproducts rather than loanproduct
* 3. @GET results in list of all loan products being returned (no scoping relevant here)
* 4. Only 'produce'ing JSON by limiting to @Produces({MediaType.APPLICATION_JSON})
* 5. The java object returned is LoanProductData and LoanProductList when list of products returned.
* These java objects are annotated with @XmlRootElement so JAXB reader/writers will automatically translate to JSON format.
* 6. @GET /loanproducts/{productId} results in loan product of that identifier or appropriate error response
* 7. @POST /loanproducts with correct request body creates new loan product
* 8. @PUT /loanproducts/{productId} updates loan product of that identifier
* 9. Using /resource/template pattern for UI specific function of get 'data with defaults' for new resource.
*/
@Path("/v1/loanproducts")
@Component
@Scope("singleton")
@@ -52,6 +36,9 @@ public class LoanProductApiResource {
@Autowired
private LoanProductWritePlatformService loanProductWritePlatformService;
@Autowired
private ApiDataConversionService apiDataConversionService;
@POST
@Consumes({ MediaType.APPLICATION_JSON, MediaType.APPLICATION_XML })
@Produces({ MediaType.APPLICATION_JSON})
@@ -102,6 +89,15 @@ public class LoanProductApiResource {
@Consumes({ MediaType.APPLICATION_JSON, MediaType.APPLICATION_XML })
@Produces({ MediaType.APPLICATION_JSON })
public Response updateLoanProduct(@PathParam("productId") final Long productId, final LoanProductCommand command) {
// FIXME - pass in locale through query string or in 'request body'
Locale clientApplicationLocale = Locale.UK;
BigDecimal principal = this.apiDataConversionService.convertFrom(command.getPrincipalFormatted(), "principalFormatted", clientApplicationLocale);
BigDecimal interestRatePerPeriod = this.apiDataConversionService.convertFrom(command.getInterestRatePerPeriodFormatted(), "interestRatePerPeriodFormatted", clientApplicationLocale);
BigDecimal inArrearsToleranceAmount = this.apiDataConversionService.convertFrom(command.getInArrearsToleranceAmountFormatted(), "inArrearsToleranceAmountFormatted", clientApplicationLocale);
command.setPrincipal(principal);
command.setInterestRatePerPeriod(interestRatePerPeriod);
command.setInArrearsToleranceAmount(inArrearsToleranceAmount);
command.setId(productId);
EntityIdentifier entityIdentifier = this.loanProductWritePlatformService.updateLoanProduct(command);
@@ -54,7 +54,7 @@ public class ApiDataConversionServiceImpl implements ApiDataConversionService {
} catch (ParseException e) {
List<ApiParameterError> dataValidationErrors = new ArrayList<ApiParameterError>();
ApiParameterError error = ApiParameterError.parameterError("validation.msg.invalid.number.format", "The parameter " + parameterName + " is invalid.", parameterName, numericalValueFormatted);
ApiParameterError error = ApiParameterError.parameterError("validation.msg.invalid.number.format", "The parameter " + parameterName + " is invalid for provided locale" + clientApplicationLocale.toString() + ".", parameterName, numericalValueFormatted, clientApplicationLocale);
dataValidationErrors.add(error);
throw new PlatformApiDataValidationException("validation.msg.validation.errors.exist", "Validation errors exist.", dataValidationErrors);
@@ -133,8 +133,12 @@ public class LoanProduct extends AbstractAuditableCustom<AppUser, Long> {
}
public void update(LoanProductCommand command) {
this.name = command.getName();
this.description = command.getDescription();
if (command.getName() != null) {
this.name = command.getName();
}
if (command.getDescription() != null) {
this.description = command.getDescription();
}
this.loanProductRelatedDetail.update(command);
}
}
@@ -173,17 +173,38 @@ public class LoanProductRelatedDetail implements
public void update(LoanProductCommand command) {
this.currency = new MonetaryCurrency(command.getCurrencyCode(), command.getDigitsAfterDecimal());
this.principal = command.getPrincipal();
this.repayEvery = command.getRepaymentEvery();
this.repaymentPeriodFrequencyType = PeriodFrequencyType.fromInt(command.getRepaymentFrequency());
this.numberOfRepayments = command.getNumberOfRepayments();
this.amortizationMethod = AmortizationMethod.fromInt(command.getAmortizationMethod());
this.inArrearsTolerance = command.getInArrearsToleranceAmount();
this.nominalInterestRatePerPeriod = command.getInterestRatePerPeriod();
this.interestPeriodFrequencyType = PeriodFrequencyType.fromInt(command.getInterestRateFrequencyMethod());
this.interestMethod = InterestMethod.fromInt(command.getInterestMethod());
this.interestCalculationPeriodMethod = InterestCalculationPeriodMethod.fromInt(command.getInterestCalculationPeriodMethod());
if (command.getCurrencyCode() != null && command.getDigitsAfterDecimal() != null) {
this.currency = new MonetaryCurrency(command.getCurrencyCode(), command.getDigitsAfterDecimal());
}
if (command.getPrincipal() != null) {
this.principal = command.getPrincipal();
}
if (command.getRepaymentEvery() != null) {
this.repayEvery = command.getRepaymentEvery();
}
if (command.getRepaymentFrequency() != null) {
this.repaymentPeriodFrequencyType = PeriodFrequencyType.fromInt(command.getRepaymentFrequency());
}
if (command.getNumberOfRepayments() != null) {
this.numberOfRepayments = command.getNumberOfRepayments();
}
if (command.getAmortizationMethod() != null) {
this.amortizationMethod = AmortizationMethod.fromInt(command.getAmortizationMethod());
}
if (command.getInArrearsToleranceAmount() != null) {
this.inArrearsTolerance = command.getInArrearsToleranceAmount();
}
if (command.getInterestRatePerPeriod() != null) {
this.nominalInterestRatePerPeriod = command.getInterestRatePerPeriod();
}
if (command.getInterestRateFrequencyMethod() != null) {
this.interestPeriodFrequencyType = PeriodFrequencyType.fromInt(command.getInterestRateFrequencyMethod());
}
if (command.getInterestMethod() != null) {
this.interestMethod = InterestMethod.fromInt(command.getInterestMethod());
}
if (command.getInterestCalculationPeriodMethod() != null) {
this.interestCalculationPeriodMethod = InterestCalculationPeriodMethod.fromInt(command.getInterestCalculationPeriodMethod());
}
}
}
@@ -3,228 +3,278 @@ package org.mifosng.platform.loanproduct.service;
import java.util.ArrayList;
import java.util.List;
import org.apache.commons.lang.StringUtils;
import org.mifosng.data.ApiParameterError;
import org.mifosng.data.command.LoanProductCommand;
import org.mifosng.platform.DataValidatorBuilder;
import org.mifosng.platform.exceptions.PlatformApiDataValidationException;
import org.mifosng.platform.loan.domain.AmortizationMethod;
import org.mifosng.platform.loan.domain.InterestMethod;
import org.mifosng.platform.loan.domain.PeriodFrequencyType;
// FIXME - There is a lot of common validation across parameters for LoanProduct create/update, loan schedule calculation and submit new loan application flows.
// - reduce duplicator across this validators.
public class LoanProductCommandValidator {
public void validateForUpdate(LoanProductCommand command) {
private final LoanProductCommand command;
public LoanProductCommandValidator(LoanProductCommand command) {
this.command = command;
}
public void validateForUpdate() {
List<ApiParameterError> dataValidationErrors = new ArrayList<ApiParameterError>();
Long productId = command.getId();
if (productId == null) {
ApiParameterError error = ApiParameterError.parameterError("validation.msg.product.id.cannot.be.empty", "The parameter id cannot be blank.", "id");
dataValidationErrors.add(error);
}
DataValidatorBuilder baseDataValidator = new DataValidatorBuilder(dataValidationErrors).resource("product");
validateRemainingAttributes(command, dataValidationErrors);
}
public void validateForCreate(LoanProductCommand command) {
List<ApiParameterError> dataValidationErrors = new ArrayList<ApiParameterError>();
baseDataValidator.reset().parameter("id").value(command.getId()).notNull();
baseDataValidator.reset().parameter("name").value(command.getName()).ignoreIfNull().notBlank();
baseDataValidator.reset().parameter("description").value(command.getDescription()).ignoreIfNull().notExceedingLengthOf(500);
baseDataValidator.reset().parameter("externalId").value(command.getExternalId()).ignoreIfNull().notExceedingLengthOf(100);
baseDataValidator.reset().parameter("currencyCode").value(command.getCurrencyCode()).ignoreIfNull().notBlank();
baseDataValidator.reset().parameter("digitsAfterDecimal").value(command.getDigitsAfterDecimal()).ignoreIfNull().notNull().inMinMaxRange(0, 6);
validateRemainingAttributes(command, dataValidationErrors);
}
private void validateRemainingAttributes(LoanProductCommand command, List<ApiParameterError> dataValidationErrors) {
baseDataValidator.reset().parameter("principalFormatted").value(command.getPrincipalFormatted()).ignoreIfNull().notBlank();
baseDataValidator.reset().parameter("inArrearsToleranceAmountFormatted").value(command.getInArrearsToleranceAmountFormatted()).ignoreIfNull().notBlank();
if (StringUtils.isBlank(command.getName())) {
ApiParameterError error = ApiParameterError.parameterError("validation.msg.product.name.cannot.be.blank", "The parameter name cannot be blank.", "name");
dataValidationErrors.add(error);
}
baseDataValidator.reset().parameter("repaymentFrequency").value(command.getRepaymentFrequency()).ignoreIfNull().notNull().inMinMaxRange(0, 3);
baseDataValidator.reset().parameter("repaymentEvery").value(command.getRepaymentEvery()).ignoreIfNull().notNull().greaterThanZero();
baseDataValidator.reset().parameter("numberOfRepayments").value(command.getNumberOfRepayments()).ignoreIfNull().notNull().greaterThanZero();
if (command.getDescription() != null) {
if (command.getDescription().length() > 500) {
ApiParameterError error = ApiParameterError.parameterError("validation.msg.product.description.exceeds.max.length", "The parameter description cannot exceed max length of {}.", "description", 500);
dataValidationErrors.add(error);
}
}
baseDataValidator.reset().parameter("interestRatePerPeriodFormatted").value(command.getInterestRatePerPeriodFormatted()).ignoreIfNull().notBlank();
baseDataValidator.reset().parameter("interestRateFrequencyMethod").value(command.getInterestRateFrequencyMethod()).ignoreIfNull().notNull().inMinMaxRange(0, 3);
if (StringUtils.isBlank(command.getCurrencyCode())) {
ApiParameterError error = ApiParameterError.parameterError("validation.msg.product.currency.cannot.be.empty", "The parameter currencyCode cannot be blank.", "currencyCode");
dataValidationErrors.add(error);
}
baseDataValidator.reset().parameter("amortizationMethod").value(command.getAmortizationMethod()).ignoreIfNull().notNull().inMinMaxRange(0, 1);
baseDataValidator.reset().parameter("interestMethod").value(command.getInterestMethod()).ignoreIfNull().notNull().inMinMaxRange(0, 1);
baseDataValidator.reset().parameter("interestCalculationPeriodMethod").value(command.getInterestCalculationPeriodMethod()).ignoreIfNull().notNull().inMinMaxRange(0, 1);
if (command.getDigitsAfterDecimal() != null) {
if (command.getDigitsAfterDecimal() < 0 || command.getDigitsAfterDecimal() > 6) {
ApiParameterError error = ApiParameterError.parameterError("validation.msg.product.currency.digitsAfterDecimal.must.be.between.zero.and.six.inclusive", "The parameter digitsAfterDecimal must be between {0} and {1} inclusive.", "selectedDigitsAfterDecimal", 0, 6);
dataValidationErrors.add(error);
}
} else {
ApiParameterError error = ApiParameterError.parameterError("validation.msg.product.currency.digitsAfterDecimal.cannot.be.empty", "The parameter digitsAfterDecimal cannot be blank.", "selectedDigitsAfterDecimal");
dataValidationErrors.add(error);
}
if (command.getPrincipal() != null) {
if (command.getPrincipal().doubleValue() <= Double.valueOf("0.0")) {
ApiParameterError error = ApiParameterError.parameterError("validation.msg.product.principal.amount.must.be.greater.than.zero", "The parameter amount must be greater than zero.", "amount");
dataValidationErrors.add(error);
}
} else {
ApiParameterError error = ApiParameterError.parameterError("validation.msg.product.principal.amount.cannot.be.empty", "The parameter amount cannot be blank.", "amount");
dataValidationErrors.add(error);
}
if (command.getRepaymentFrequency() != null) {
PeriodFrequencyType frequencyType = PeriodFrequencyType.fromInt(command.getRepaymentFrequency());
ApiParameterError error = null;
switch (frequencyType) {
case DAYS:
error = validateNumberExistsAndInRange("validation.msg.product.repayment.repaidEvery", "repaidEvery", command.getRepaymentEvery(), 1, 365);
break;
case WEEKS:
error = validateNumberExistsAndInRange("validation.msg.product.repayment.repaidEvery", "repaidEvery", command.getRepaymentEvery(), 1, 52);
break;
case MONTHS:
error = validateNumberExistsAndInRange("validation.msg.product.repayment.repaidEvery", "repaidEvery", command.getRepaymentEvery(), 1, 12);
break;
case YEARS:
error = validateNumberExistsAndInRange("validation.msg.product.repayment.repaidEvery", "repaidEvery", command.getRepaymentEvery(), 1, 2);
break;
default:
error = ApiParameterError.parameterError("validation.msg.product.repayment.frequency.invalid", "The parameter selectedRepaymentFrequencyOption is invalid.", "selectedRepaymentFrequencyOption");
break;
}
if (error != null) {
dataValidationErrors.add(error);
}
} else {
ApiParameterError error = ApiParameterError.parameterError("validation.msg.product.repayment.frequency.cannot.be.empty",
"The parameter selectedRepaymentFrequencyOption cannot be blank.", "selectedRepaymentFrequencyOption");
dataValidationErrors.add(error);
}
if (command.getNumberOfRepayments() != null) {
if (command.getNumberOfRepayments() < 1 || command.getNumberOfRepayments() > 100) {
ApiParameterError error = ApiParameterError.parameterError("validation.msg.product.number.of.repayments.is.out.of.range",
"The parameter numberOfRepayments must be between {} and {} inclusive.", "numberOfRepayments", 1, 100);
dataValidationErrors.add(error);
}
} else {
ApiParameterError error = ApiParameterError.parameterError("validation.msg.product.number.of.repayments.cannot.be.empty",
"The parameter numberOfRepayments cannot be empty.", "numberOfRepayments");
dataValidationErrors.add(error);
}
if (command.getAmortizationMethod() != null) {
AmortizationMethod amortizationMethod = AmortizationMethod.fromInt(command.getAmortizationMethod());
ApiParameterError error = null;
switch (amortizationMethod) {
case EQUAL_PRINCIPAL:
break;
case EQUAL_INSTALLMENTS:
break;
default:
error = ApiParameterError.parameterError("validation.msg.product.amortization.method.invalid",
"The parameter selectedAmortizationMethodOption cannot be empty.", "selectedAmortizationMethodOption");
break;
}
if (error != null) {
dataValidationErrors.add(error);
}
} else {
ApiParameterError error = ApiParameterError.parameterError("validation.msg.product.amortization.method.cannot.be.empty",
"The parameter selectedAmortizationMethodOption cannot be empty.", "selectedAmortizationMethodOption");
dataValidationErrors.add(error);
}
// refactor in validation of monetary value.
if (command.getInArrearsToleranceAmount() != null) {
if (command.getInArrearsToleranceAmount().doubleValue() < Double.valueOf("0.0")) {
ApiParameterError error = ApiParameterError.parameterError("validation.msg.product.arrears.tolerance.amount.cannot.be.negative",
"The parameter inArrearsTolerance cannot be less than zero.", "inArrearsTolerance");
dataValidationErrors.add(error);
}
} else {
ApiParameterError error = ApiParameterError.parameterError("validation.msg.product.arrears.tolerance.amount.cannot.be.empty",
"The parameter inArrearsTolerance cannot be empty.", "inArrearsTolerance");
dataValidationErrors.add(error);
}
if (command.getInterestRatePerPeriod()!= null) {
if (command.getInterestRatePerPeriod().doubleValue() < Double.valueOf("0.0")) {
ApiParameterError error = ApiParameterError.parameterError("validation.msg.product.interest.rate.per.period.amount.cannot.be.negative",
"The parameter nominalInterestRate cannot be less than zero.", "nominalInterestRate");
dataValidationErrors.add(error);
}
} else {
ApiParameterError error = ApiParameterError.parameterError("validation.msg.product.interest.rate.per.period.amount.cannot.be.empty",
"The parameter nominalInterestRate cannot be empty.", "nominalInterestRate");
dataValidationErrors.add(error);
}
// interest rate period type
if (command.getInterestRateFrequencyMethod() != null) {
PeriodFrequencyType frequencyType = PeriodFrequencyType.fromInt(command.getInterestRateFrequencyMethod());
ApiParameterError error = null;
switch (frequencyType) {
case DAYS:
break;
case WEEKS:
break;
case MONTHS:
break;
case YEARS:
break;
default:
error = ApiParameterError.parameterError("validation.msg.product.interest.frequency.invalid",
"The parameter selectedInterestFrequencyOption is invalid.", "selectedInterestFrequencyOption");
break;
}
if (error != null) {
dataValidationErrors.add(error);
}
} else {
ApiParameterError error = ApiParameterError.parameterError("validation.msg.product.interest.frequency.cannot.be.empty",
"The parameter selectedInterestFrequencyOption cannot be empty.", "selectedInterestFrequencyOption");
dataValidationErrors.add(error);
}
if (command.getInterestMethod() != null) {
InterestMethod interestMethod = InterestMethod.fromInt(command.getInterestMethod());
ApiParameterError error = null;
switch (interestMethod) {
case DECLINING_BALANCE:
break;
case FLAT:
break;
default:
error = ApiParameterError.parameterError("validation.msg.product.interest.method.invalid",
"The parameter selectedInterestMethodOption is invalid.", "selectedInterestMethodOption");
break;
}
if (error != null) {
dataValidationErrors.add(error);
}
} else {
ApiParameterError error = ApiParameterError.parameterError("validation.msg.product.interest.method.cannot.be.empty",
"The parameter selectedInterestMethodOption cannot be empty.", "selectedInterestMethodOption");
dataValidationErrors.add(error);
}
baseDataValidator.reset().anyOfNotNull(command.getName(), command.getDescription(), command.getExternalId(), command.getCurrencyCode(), command.getDigitsAfterDecimal(),
command.getPrincipalFormatted(), command.getInArrearsToleranceAmountFormatted(), command.getRepaymentFrequency(), command.getRepaymentEvery(), command.getNumberOfRepayments(),
command.getInterestRatePerPeriodFormatted(), command.getInterestRateFrequencyMethod(), command.getAmortizationMethod(), command.getInterestMethod(), command.getInterestCalculationPeriodMethod());
if (!dataValidationErrors.isEmpty()) {
throw new PlatformApiDataValidationException("validation.msg.validation.errors.exist", "Validation errors exist.", dataValidationErrors);
}
}
private ApiParameterError validateNumberExistsAndInRange(String errorCodePreFix, String fieldName, Integer value, int min, int max) {
ApiParameterError error = null;
if (value == null) {
error = ApiParameterError.parameterError(errorCodePreFix + ".cannot.be.empty", "The parameter " + fieldName + " cannot be blank.", fieldName);
} else {
if (value < min || value > max) {
error = ApiParameterError.parameterError(errorCodePreFix + ".outside.allowed.range", "The parameter " + fieldName + " must be between {0} and {1} inclusive.", fieldName, min, max);
}
public void validateForCreate() {
List<ApiParameterError> dataValidationErrors = new ArrayList<ApiParameterError>();
DataValidatorBuilder baseDataValidator = new DataValidatorBuilder(dataValidationErrors).resource("product");
baseDataValidator.reset().parameter("name").value(command.getName()).notBlank();
baseDataValidator.reset().parameter("description").value(command.getDescription()).notExceedingLengthOf(500);
baseDataValidator.reset().parameter("externalId").value(command.getExternalId()).notExceedingLengthOf(100);
baseDataValidator.reset().parameter("currencyCode").value(command.getCurrencyCode()).notBlank();
baseDataValidator.reset().parameter("digitsAfterDecimal").value(command.getDigitsAfterDecimal()).notNull().inMinMaxRange(0, 6);
baseDataValidator.reset().parameter("principalFormatted").value(command.getPrincipalFormatted()).notBlank();
baseDataValidator.reset().parameter("inArrearsToleranceAmountFormatted").value(command.getInArrearsToleranceAmountFormatted()).notBlank();
baseDataValidator.reset().parameter("repaymentFrequency").value(command.getRepaymentFrequency()).notNull().inMinMaxRange(0, 3);
baseDataValidator.reset().parameter("repaymentEvery").value(command.getRepaymentEvery()).notNull().greaterThanZero();
baseDataValidator.reset().parameter("numberOfRepayments").value(command.getNumberOfRepayments()).notNull().greaterThanZero();
baseDataValidator.reset().parameter("interestRatePerPeriodFormatted").value(command.getInterestRatePerPeriodFormatted()).notBlank();
baseDataValidator.reset().parameter("interestRateFrequencyMethod").value(command.getInterestRateFrequencyMethod()).notNull().inMinMaxRange(0, 3);
baseDataValidator.reset().parameter("amortizationMethod").value(command.getAmortizationMethod()).notNull().inMinMaxRange(0, 1);
baseDataValidator.reset().parameter("interestMethod").value(command.getInterestMethod()).notNull().inMinMaxRange(0, 1);
baseDataValidator.reset().parameter("interestCalculationPeriodMethod").value(command.getInterestCalculationPeriodMethod()).notNull().inMinMaxRange(0, 1);
if (!dataValidationErrors.isEmpty()) {
throw new PlatformApiDataValidationException("validation.msg.validation.errors.exist", "Validation errors exist.", dataValidationErrors);
}
return error;
}
// FIXME - commented out old validation for now. test that new validation is appropriate
// private void validateRemainingAttributes(LoanProductCommand command, List<ApiParameterError> dataValidationErrors) {
//
// if (StringUtils.isBlank(command.getName())) {
// ApiParameterError error = ApiParameterError.parameterError("validation.msg.product.name.cannot.be.blank", "The parameter name cannot be blank.", "name");
// dataValidationErrors.add(error);
// }
//
// if (command.getDescription() != null) {
// if (command.getDescription().length() > 500) {
// ApiParameterError error = ApiParameterError.parameterError("validation.msg.product.description.exceeds.max.length", "The parameter description cannot exceed max length of {}.", "description", 500);
// dataValidationErrors.add(error);
// }
// }
//
// if (StringUtils.isBlank(command.getCurrencyCode())) {
// ApiParameterError error = ApiParameterError.parameterError("validation.msg.product.currency.cannot.be.empty", "The parameter currencyCode cannot be blank.", "currencyCode");
// dataValidationErrors.add(error);
// }
//
// if (command.getDigitsAfterDecimal() != null) {
//
// if (command.getDigitsAfterDecimal() < 0 || command.getDigitsAfterDecimal() > 6) {
// ApiParameterError error = ApiParameterError.parameterError("validation.msg.product.currency.digitsAfterDecimal.must.be.between.zero.and.six.inclusive", "The parameter digitsAfterDecimal must be between {0} and {1} inclusive.", "selectedDigitsAfterDecimal", 0, 6);
// dataValidationErrors.add(error);
// }
// } else {
// ApiParameterError error = ApiParameterError.parameterError("validation.msg.product.currency.digitsAfterDecimal.cannot.be.empty", "The parameter digitsAfterDecimal cannot be blank.", "selectedDigitsAfterDecimal");
// dataValidationErrors.add(error);
// }
//
// if (command.getPrincipal() != null) {
// if (command.getPrincipal().doubleValue() <= Double.valueOf("0.0")) {
// ApiParameterError error = ApiParameterError.parameterError("validation.msg.product.principal.amount.must.be.greater.than.zero", "The parameter amount must be greater than zero.", "amount");
// dataValidationErrors.add(error);
// }
// } else {
// ApiParameterError error = ApiParameterError.parameterError("validation.msg.product.principal.amount.cannot.be.empty", "The parameter amount cannot be blank.", "amount");
// dataValidationErrors.add(error);
// }
//
// if (command.getRepaymentFrequency() != null) {
// PeriodFrequencyType frequencyType = PeriodFrequencyType.fromInt(command.getRepaymentFrequency());
// ApiParameterError error = null;
// switch (frequencyType) {
// case DAYS:
// error = validateNumberExistsAndInRange("validation.msg.product.repayment.repaidEvery", "repaidEvery", command.getRepaymentEvery(), 1, 365);
// break;
// case WEEKS:
// error = validateNumberExistsAndInRange("validation.msg.product.repayment.repaidEvery", "repaidEvery", command.getRepaymentEvery(), 1, 52);
// break;
// case MONTHS:
// error = validateNumberExistsAndInRange("validation.msg.product.repayment.repaidEvery", "repaidEvery", command.getRepaymentEvery(), 1, 12);
// break;
// case YEARS:
// error = validateNumberExistsAndInRange("validation.msg.product.repayment.repaidEvery", "repaidEvery", command.getRepaymentEvery(), 1, 2);
// break;
// default:
// error = ApiParameterError.parameterError("validation.msg.product.repayment.frequency.invalid", "The parameter selectedRepaymentFrequencyOption is invalid.", "selectedRepaymentFrequencyOption");
// break;
// }
// if (error != null) {
// dataValidationErrors.add(error);
// }
// } else {
// ApiParameterError error = ApiParameterError.parameterError("validation.msg.product.repayment.frequency.cannot.be.empty",
// "The parameter selectedRepaymentFrequencyOption cannot be blank.", "selectedRepaymentFrequencyOption");
// dataValidationErrors.add(error);
// }
//
// if (command.getNumberOfRepayments() != null) {
// if (command.getNumberOfRepayments() < 1 || command.getNumberOfRepayments() > 100) {
// ApiParameterError error = ApiParameterError.parameterError("validation.msg.product.number.of.repayments.is.out.of.range",
// "The parameter numberOfRepayments must be between {} and {} inclusive.", "numberOfRepayments", 1, 100);
// dataValidationErrors.add(error);
// }
// } else {
// ApiParameterError error = ApiParameterError.parameterError("validation.msg.product.number.of.repayments.cannot.be.empty",
// "The parameter numberOfRepayments cannot be empty.", "numberOfRepayments");
// dataValidationErrors.add(error);
// }
//
// if (command.getAmortizationMethod() != null) {
// AmortizationMethod amortizationMethod = AmortizationMethod.fromInt(command.getAmortizationMethod());
// ApiParameterError error = null;
// switch (amortizationMethod) {
// case EQUAL_PRINCIPAL:
// break;
// case EQUAL_INSTALLMENTS:
// break;
// default:
// error = ApiParameterError.parameterError("validation.msg.product.amortization.method.invalid",
// "The parameter selectedAmortizationMethodOption cannot be empty.", "selectedAmortizationMethodOption");
// break;
// }
// if (error != null) {
// dataValidationErrors.add(error);
// }
// } else {
// ApiParameterError error = ApiParameterError.parameterError("validation.msg.product.amortization.method.cannot.be.empty",
// "The parameter selectedAmortizationMethodOption cannot be empty.", "selectedAmortizationMethodOption");
// dataValidationErrors.add(error);
// }
//
// // refactor in validation of monetary value.
// if (command.getInArrearsToleranceAmount() != null) {
// if (command.getInArrearsToleranceAmount().doubleValue() < Double.valueOf("0.0")) {
// ApiParameterError error = ApiParameterError.parameterError("validation.msg.product.arrears.tolerance.amount.cannot.be.negative",
// "The parameter inArrearsTolerance cannot be less than zero.", "inArrearsTolerance");
// dataValidationErrors.add(error);
// }
// } else {
// ApiParameterError error = ApiParameterError.parameterError("validation.msg.product.arrears.tolerance.amount.cannot.be.empty",
// "The parameter inArrearsTolerance cannot be empty.", "inArrearsTolerance");
// dataValidationErrors.add(error);
// }
//
// if (command.getInterestRatePerPeriod()!= null) {
// if (command.getInterestRatePerPeriod().doubleValue() < Double.valueOf("0.0")) {
// ApiParameterError error = ApiParameterError.parameterError("validation.msg.product.interest.rate.per.period.amount.cannot.be.negative",
// "The parameter nominalInterestRate cannot be less than zero.", "nominalInterestRate");
// dataValidationErrors.add(error);
// }
// } else {
// ApiParameterError error = ApiParameterError.parameterError("validation.msg.product.interest.rate.per.period.amount.cannot.be.empty",
// "The parameter nominalInterestRate cannot be empty.", "nominalInterestRate");
// dataValidationErrors.add(error);
// }
//
// // interest rate period type
// if (command.getInterestRateFrequencyMethod() != null) {
// PeriodFrequencyType frequencyType = PeriodFrequencyType.fromInt(command.getInterestRateFrequencyMethod());
// ApiParameterError error = null;
// switch (frequencyType) {
// case DAYS:
// break;
// case WEEKS:
// break;
// case MONTHS:
// break;
// case YEARS:
// break;
// default:
// error = ApiParameterError.parameterError("validation.msg.product.interest.frequency.invalid",
// "The parameter selectedInterestFrequencyOption is invalid.", "selectedInterestFrequencyOption");
// break;
// }
// if (error != null) {
// dataValidationErrors.add(error);
// }
// } else {
// ApiParameterError error = ApiParameterError.parameterError("validation.msg.product.interest.frequency.cannot.be.empty",
// "The parameter selectedInterestFrequencyOption cannot be empty.", "selectedInterestFrequencyOption");
// dataValidationErrors.add(error);
// }
//
// if (command.getInterestMethod() != null) {
// InterestMethod interestMethod = InterestMethod.fromInt(command.getInterestMethod());
// ApiParameterError error = null;
// switch (interestMethod) {
// case DECLINING_BALANCE:
// break;
// case FLAT:
// break;
// default:
// error = ApiParameterError.parameterError("validation.msg.product.interest.method.invalid",
// "The parameter selectedInterestMethodOption is invalid.", "selectedInterestMethodOption");
// break;
// }
// if (error != null) {
// dataValidationErrors.add(error);
// }
// } else {
// ApiParameterError error = ApiParameterError.parameterError("validation.msg.product.interest.method.cannot.be.empty",
// "The parameter selectedInterestMethodOption cannot be empty.", "selectedInterestMethodOption");
// dataValidationErrors.add(error);
// }
//
// if (!dataValidationErrors.isEmpty()) {
// throw new PlatformApiDataValidationException("validation.msg.validation.errors.exist", "Validation errors exist.", dataValidationErrors);
// }
// }
//
// private ApiParameterError validateNumberExistsAndInRange(String errorCodePreFix, String fieldName, Integer value, int min, int max) {
// ApiParameterError error = null;
// if (value == null) {
// error = ApiParameterError.parameterError(errorCodePreFix + ".cannot.be.empty", "The parameter " + fieldName + " cannot be blank.", fieldName);
// } else {
// if (value < min || value > max) {
// error = ApiParameterError.parameterError(errorCodePreFix + ".outside.allowed.range", "The parameter " + fieldName + " must be between {0} and {1} inclusive.", fieldName, min, max);
// }
// }
// return error;
// }
}
@@ -14,6 +14,7 @@ import org.mifosng.platform.loan.domain.InterestMethod;
import org.mifosng.platform.loan.domain.LoanProduct;
import org.mifosng.platform.loan.domain.LoanProductRepository;
import org.mifosng.platform.loan.domain.PeriodFrequencyType;
import org.mifosng.platform.loanschedule.domain.AprCalculator;
import org.mifosng.platform.security.PlatformSecurityContext;
import org.mifosng.platform.user.domain.AppUser;
import org.springframework.beans.factory.annotation.Autowired;
@@ -25,11 +26,13 @@ public class LoanProductWritePlatformServiceJpaRepositoryImpl implements LoanPro
private final PlatformSecurityContext context;
private final LoanProductRepository loanProductRepository;
private final AprCalculator aprCalculator;
@Autowired
public LoanProductWritePlatformServiceJpaRepositoryImpl(final PlatformSecurityContext context, final LoanProductRepository loanProductRepository) {
public LoanProductWritePlatformServiceJpaRepositoryImpl(final PlatformSecurityContext context, final LoanProductRepository loanProductRepository, final AprCalculator aprCalculator) {
this.context = context;
this.loanProductRepository = loanProductRepository;
this.aprCalculator = aprCalculator;
}
@Transactional
@@ -38,8 +41,8 @@ public class LoanProductWritePlatformServiceJpaRepositoryImpl implements LoanPro
AppUser currentUser = this.context.authenticatedUser();
LoanProductCommandValidator validator = new LoanProductCommandValidator();
validator.validateForCreate(command);
LoanProductCommandValidator validator = new LoanProductCommandValidator(command);
validator.validateForCreate();
// assemble LoanProduct from data
InterestMethod interestMethod = InterestMethod.fromInt(command.getInterestMethod());
@@ -54,24 +57,8 @@ public class LoanProductWritePlatformServiceJpaRepositoryImpl implements LoanPro
.fromInt(command.getInterestRateFrequencyMethod());
MonetaryCurrency currency = new MonetaryCurrency(command.getCurrencyCode(), command.getDigitsAfterDecimal());
// apr calculator
BigDecimal annualInterestRate = BigDecimal.ZERO;
switch (interestFrequencyType) {
case DAYS:
break;
case WEEKS:
annualInterestRate = command.getInterestRatePerPeriod().multiply(BigDecimal.valueOf(52));
break;
case MONTHS:
annualInterestRate = command.getInterestRatePerPeriod().multiply(BigDecimal.valueOf(12));
break;
case YEARS:
annualInterestRate = command.getInterestRatePerPeriod().multiply(BigDecimal.valueOf(1));
break;
case INVALID:
break;
}
BigDecimal annualInterestRate = this.aprCalculator.calculateFrom(interestFrequencyType, command.getInterestRatePerPeriod());
LoanProduct loanproduct = new LoanProduct(currentUser.getOrganisation(), command.getName(), command.getDescription(),
currency, command.getPrincipal(),
@@ -89,8 +76,8 @@ public class LoanProductWritePlatformServiceJpaRepositoryImpl implements LoanPro
AppUser currentUser = this.context.authenticatedUser();
LoanProductCommandValidator validator = new LoanProductCommandValidator();
validator.validateForUpdate(command);
LoanProductCommandValidator validator = new LoanProductCommandValidator(command);
validator.validateForUpdate();
LoanProduct product = this.loanProductRepository.findOne(productThatMatches(currentUser.getOrganisation(), command.getId()));
if (product == null) {
@@ -3,10 +3,9 @@ package org.mifosng.platform.organisation.service;
import java.util.ArrayList;
import java.util.List;
import org.apache.commons.lang.StringUtils;
import org.joda.time.LocalDate;
import org.mifosng.data.ApiParameterError;
import org.mifosng.data.command.OfficeCommand;
import org.mifosng.platform.DataValidatorBuilder;
import org.mifosng.platform.exceptions.PlatformApiDataValidationException;
public class OfficeCommandValidator {
@@ -21,27 +20,12 @@ public class OfficeCommandValidator {
List<ApiParameterError> dataValidationErrors = new ArrayList<ApiParameterError>();
if (StringUtils.isBlank(this.command.getName())) {
ApiParameterError error = ApiParameterError.parameterError("validation.msg.office.name.cannot.be.blank", "The parameter name cannot be blank.", "name");
dataValidationErrors.add(error);
}
DataValidatorBuilder baseDataValidator = new DataValidatorBuilder(dataValidationErrors).resource("office");
if (!command.isRootOffice() && (this.command.getParentId() == null || this.command.getParentId().intValue() <= 0)) {
ApiParameterError error = ApiParameterError.parameterError("validation.msg.office.parent.cannot.be.blank", "A valid parentId must be provided.", "parentId");
dataValidationErrors.add(error);
}
if (this.command.getOpeningDate() == null) {
ApiParameterError error = ApiParameterError.parameterError("validation.msg.office.opening.date.cannot.be.blank", "The parameter openingDate cannot be blank", "openingDate");
dataValidationErrors.add(error);
}
if (StringUtils.isNotBlank(this.command.getExternalId())) {
if (this.command.getExternalId().trim().length() > 100) {
ApiParameterError error = ApiParameterError.parameterError("validation.msg.office.externalId.exceeds.max.length", "The parameter externalId exceeds max length of {0}", "externalId", 100);
dataValidationErrors.add(error);
}
}
baseDataValidator.reset().parameter("name").value(command.getName()).notBlank();
baseDataValidator.reset().parameter("openingDateFormatted").value(command.getOpeningDateFormatted()).notBlank();
baseDataValidator.reset().parameter("externalId").value(command.getExternalId()).notExceedingLengthOf(100);
baseDataValidator.reset().parameter("parentId").value(command.getParentId()).notNull().greaterThanZero();
if (!dataValidationErrors.isEmpty()) {
throw new PlatformApiDataValidationException("validation.msg.validation.errors.exist", "Validation errors exist.", dataValidationErrors);
@@ -51,60 +35,18 @@ public class OfficeCommandValidator {
public void validateForUpdate() {
List<ApiParameterError> dataValidationErrors = new ArrayList<ApiParameterError>();
if (command.getId() == null) {
ApiParameterError error = ApiParameterError.parameterError("validation.msg.office.id.cannot.be.blank", "A valid id must be provided.", "id");
dataValidationErrors.add(error);
}
DataValidatorBuilder baseDataValidator = new DataValidatorBuilder(dataValidationErrors).resource("office");
boolean ignoreNulls = true;
// NOTE: remember for updates that values that are null are ignored from validation and update.
boolean nameHasData = validateParameterNotEmpty(this.command.getName(), "office", "name", ignoreNulls, dataValidationErrors);
boolean openingDateHasData = validateParameterNotEmpty(this.command.getOpeningDateFormatted(), "office", "openingDateFormatted", ignoreNulls, dataValidationErrors);
boolean externalIdHasData = validateParameterNotGreaterThan(100, this.command.getExternalId(), "office", "externalId", ignoreNulls, dataValidationErrors);
boolean parentidHasData = validateParameterNotNull(this.command.getParentId(), "office", "parentid", ignoreNulls, dataValidationErrors);
baseDataValidator.reset().parameter("id").value(command.getId()).notNull();
baseDataValidator.reset().parameter("name").value(command.getName()).ignoreIfNull().notBlank();
baseDataValidator.reset().parameter("openingDateFormatted").value(command.getOpeningDateFormatted()).ignoreIfNull().notBlank();
baseDataValidator.reset().parameter("externalId").value(command.getExternalId()).ignoreIfNull().notExceedingLengthOf(100);
baseDataValidator.reset().parameter("parentId").value(command.getParentId()).ignoreIfNull().notNull().greaterThanZero();
if (!anyOfTrue(nameHasData, openingDateHasData, externalIdHasData, parentidHasData)) {
ApiParameterError error = ApiParameterError.parameterError("validation.msg.office.no.parameters.for.update", "No parameters passed for update.", "id");
dataValidationErrors.add(error);
}
baseDataValidator.reset().anyOfNotNull(command.getName(), command.getOpeningDateFormatted(), command.getExternalId(), command.getParentId());
if (!dataValidationErrors.isEmpty()) {
throw new PlatformApiDataValidationException("validation.msg.validation.errors.exist", "Validation errors exist.", dataValidationErrors);
}
}
private boolean anyOfTrue(boolean nameHasData, boolean openingDateHasData, boolean externalIdHasData, boolean parentidHasData) {
return nameHasData || openingDateHasData || externalIdHasData || parentidHasData;
}
private boolean validateParameterNotNull(Long value, String resourceName, String parameterName, boolean ignoreNulls, List<ApiParameterError> dataValidationErrors) {
if (value == null && ignoreNulls) return false;
return true;
}
private boolean validateParameterNotGreaterThan(Integer maxLength, String value, String resourceName, String parameterName, boolean ignoreNulls, List<ApiParameterError> dataValidationErrors) {
if (value == null && ignoreNulls) return false;
if (this.command.getExternalId().trim().length() > maxLength) {
ApiParameterError error = ApiParameterError.parameterError("validation.msg." + resourceName + "." + parameterName + ".exceeds.max.length", "The parameter " + parameterName + " exceeds max length of " + maxLength + ".", parameterName, maxLength);
dataValidationErrors.add(error);
return true;
}
return true;
}
private boolean validateParameterNotEmpty(String value, String resourceName, String parameterName, boolean ignoreNulls, List<ApiParameterError> dataValidationErrors) {
if (value == null && ignoreNulls) return false;
if (StringUtils.isBlank(value)) {
ApiParameterError error = ApiParameterError.parameterError("validation.msg." + resourceName + "." + parameterName + ".cannot.be.blank", "The parameter " + parameterName + " cannot be blank.", parameterName);
dataValidationErrors.add(error);
return true;
}
return true;
}
}