support update single piece of information for loan product and tidy up validation.
This commit is contained in:
@@ -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;
|
||||
}
|
||||
}
|
||||
+12
-8
@@ -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:
|
||||
|
||||
+12
-8
@@ -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)
|
||||
|
||||
+3
-3
@@ -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;
|
||||
}
|
||||
}
|
||||
+15
-19
@@ -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);
|
||||
|
||||
+1
-1
@@ -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);
|
||||
}
|
||||
}
|
||||
+33
-12
@@ -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());
|
||||
}
|
||||
}
|
||||
}
|
||||
+251
-201
@@ -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;
|
||||
// }
|
||||
}
|
||||
+10
-23
@@ -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) {
|
||||
|
||||
+13
-71
@@ -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;
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user