diff --git a/mifosng-data/src/main/java/org/mifosng/data/command/LoanProductCommand.java b/mifosng-data/src/main/java/org/mifosng/data/command/LoanProductCommand.java
index 4cc6299bf..1c307bb00 100644
--- a/mifosng-data/src/main/java/org/mifosng/data/command/LoanProductCommand.java
+++ b/mifosng-data/src/main/java/org/mifosng/data/command/LoanProductCommand.java
@@ -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;
+ }
}
\ No newline at end of file
diff --git a/mifosng-individual-lending-app/src/main/webapp/WEB-INF/static/global-translations/messages.properties b/mifosng-individual-lending-app/src/main/webapp/WEB-INF/static/global-translations/messages.properties
index c89199b73..8ed555824 100644
--- a/mifosng-individual-lending-app/src/main/webapp/WEB-INF/static/global-translations/messages.properties
+++ b/mifosng-individual-lending-app/src/main/webapp/WEB-INF/static/global-translations/messages.properties
@@ -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:
diff --git a/mifosng-individual-lending-app/src/main/webapp/WEB-INF/static/global-translations/messages_fr.properties b/mifosng-individual-lending-app/src/main/webapp/WEB-INF/static/global-translations/messages_fr.properties
index 37a8b21d0..26599d4cc 100644
--- a/mifosng-individual-lending-app/src/main/webapp/WEB-INF/static/global-translations/messages_fr.properties
+++ b/mifosng-individual-lending-app/src/main/webapp/WEB-INF/static/global-translations/messages_fr.properties
@@ -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)
diff --git a/mifosng-individual-lending-app/src/main/webapp/WEB-INF/views/administration-view-templates.jsp b/mifosng-individual-lending-app/src/main/webapp/WEB-INF/views/administration-view-templates.jsp
index c1642c36a..a64ce3ac7 100644
--- a/mifosng-individual-lending-app/src/main/webapp/WEB-INF/views/administration-view-templates.jsp
+++ b/mifosng-individual-lending-app/src/main/webapp/WEB-INF/views/administration-view-templates.jsp
@@ -57,7 +57,7 @@
-
+
{{#each interestFrequencyOptions}}
@@ -147,7 +147,7 @@
-
+
diff --git a/mifosng-provider/src/main/java/org/mifosng/platform/DataValidatorBuilder.java b/mifosng-provider/src/main/java/org/mifosng/platform/DataValidatorBuilder.java
new file mode 100644
index 000000000..37060c7bc
--- /dev/null
+++ b/mifosng-provider/src/main/java/org/mifosng/platform/DataValidatorBuilder.java
@@ -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 dataValidationErrors;
+ private String resource;
+ private String parameter;
+ private Object value;
+ private boolean ignoreNullValue = false;
+
+ public DataValidatorBuilder(List 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;
+ }
+}
\ No newline at end of file
diff --git a/mifosng-provider/src/main/java/org/mifosng/platform/api/LoanProductApiResource.java b/mifosng-provider/src/main/java/org/mifosng/platform/api/LoanProductApiResource.java
index 24291e28c..a9c779aea 100644
--- a/mifosng-provider/src/main/java/org/mifosng/platform/api/LoanProductApiResource.java
+++ b/mifosng-provider/src/main/java/org/mifosng/platform/api/LoanProductApiResource.java
@@ -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);
diff --git a/mifosng-provider/src/main/java/org/mifosng/platform/api/infrastructure/ApiDataConversionServiceImpl.java b/mifosng-provider/src/main/java/org/mifosng/platform/api/infrastructure/ApiDataConversionServiceImpl.java
index de35718da..356053bae 100644
--- a/mifosng-provider/src/main/java/org/mifosng/platform/api/infrastructure/ApiDataConversionServiceImpl.java
+++ b/mifosng-provider/src/main/java/org/mifosng/platform/api/infrastructure/ApiDataConversionServiceImpl.java
@@ -54,7 +54,7 @@ public class ApiDataConversionServiceImpl implements ApiDataConversionService {
} catch (ParseException e) {
List dataValidationErrors = new ArrayList();
- 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);
diff --git a/mifosng-provider/src/main/java/org/mifosng/platform/loan/domain/LoanProduct.java b/mifosng-provider/src/main/java/org/mifosng/platform/loan/domain/LoanProduct.java
index 1e2d731c4..17fe044e5 100644
--- a/mifosng-provider/src/main/java/org/mifosng/platform/loan/domain/LoanProduct.java
+++ b/mifosng-provider/src/main/java/org/mifosng/platform/loan/domain/LoanProduct.java
@@ -133,8 +133,12 @@ public class LoanProduct extends AbstractAuditableCustom {
}
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);
}
}
\ No newline at end of file
diff --git a/mifosng-provider/src/main/java/org/mifosng/platform/loan/domain/LoanProductRelatedDetail.java b/mifosng-provider/src/main/java/org/mifosng/platform/loan/domain/LoanProductRelatedDetail.java
index f92e8d599..5f4a2fe11 100644
--- a/mifosng-provider/src/main/java/org/mifosng/platform/loan/domain/LoanProductRelatedDetail.java
+++ b/mifosng-provider/src/main/java/org/mifosng/platform/loan/domain/LoanProductRelatedDetail.java
@@ -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());
+ }
}
}
\ No newline at end of file
diff --git a/mifosng-provider/src/main/java/org/mifosng/platform/loanproduct/service/LoanProductCommandValidator.java b/mifosng-provider/src/main/java/org/mifosng/platform/loanproduct/service/LoanProductCommandValidator.java
index 91cf5b4b2..83b9e7793 100644
--- a/mifosng-provider/src/main/java/org/mifosng/platform/loanproduct/service/LoanProductCommandValidator.java
+++ b/mifosng-provider/src/main/java/org/mifosng/platform/loanproduct/service/LoanProductCommandValidator.java
@@ -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 dataValidationErrors = new ArrayList();
- 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 dataValidationErrors = new ArrayList();
+ 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 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 dataValidationErrors = new ArrayList();
+
+ 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 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;
+// }
}
\ No newline at end of file
diff --git a/mifosng-provider/src/main/java/org/mifosng/platform/loanproduct/service/LoanProductWritePlatformServiceJpaRepositoryImpl.java b/mifosng-provider/src/main/java/org/mifosng/platform/loanproduct/service/LoanProductWritePlatformServiceJpaRepositoryImpl.java
index e838dfead..44849bca3 100644
--- a/mifosng-provider/src/main/java/org/mifosng/platform/loanproduct/service/LoanProductWritePlatformServiceJpaRepositoryImpl.java
+++ b/mifosng-provider/src/main/java/org/mifosng/platform/loanproduct/service/LoanProductWritePlatformServiceJpaRepositoryImpl.java
@@ -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) {
diff --git a/mifosng-provider/src/main/java/org/mifosng/platform/organisation/service/OfficeCommandValidator.java b/mifosng-provider/src/main/java/org/mifosng/platform/organisation/service/OfficeCommandValidator.java
index 75ce13e3c..d4ff61c9d 100644
--- a/mifosng-provider/src/main/java/org/mifosng/platform/organisation/service/OfficeCommandValidator.java
+++ b/mifosng-provider/src/main/java/org/mifosng/platform/organisation/service/OfficeCommandValidator.java
@@ -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 dataValidationErrors = new ArrayList();
- 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 dataValidationErrors = new ArrayList();
- 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 dataValidationErrors) {
- if (value == null && ignoreNulls) return false;
- return true;
- }
-
- private boolean validateParameterNotGreaterThan(Integer maxLength, String value, String resourceName, String parameterName, boolean ignoreNulls, List 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 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;
- }
}
\ No newline at end of file