First draft loss provisioning API.
diff --git a/api/src/main/java/io/mifos/individuallending/api/v1/client/IndividualLending.java b/api/src/main/java/io/mifos/individuallending/api/v1/client/IndividualLending.java
index c2264be..b483ec3 100644
--- a/api/src/main/java/io/mifos/individuallending/api/v1/client/IndividualLending.java
+++ b/api/src/main/java/io/mifos/individuallending/api/v1/client/IndividualLending.java
@@ -18,14 +18,13 @@
import io.mifos.core.api.util.CustomFeignClientsConfiguration;
import io.mifos.individuallending.api.v1.domain.caseinstance.PlannedPayment;
import io.mifos.individuallending.api.v1.domain.caseinstance.PlannedPaymentPage;
+import io.mifos.individuallending.api.v1.domain.product.LossProvisionStep;
import io.mifos.portfolio.api.v1.domain.CasePage;
import org.springframework.cloud.netflix.feign.FeignClient;
import org.springframework.http.MediaType;
-import org.springframework.web.bind.annotation.PathVariable;
-import org.springframework.web.bind.annotation.RequestMapping;
-import org.springframework.web.bind.annotation.RequestMethod;
-import org.springframework.web.bind.annotation.RequestParam;
+import org.springframework.web.bind.annotation.*;
+import java.util.List;
import java.util.stream.Stream;
/**
@@ -35,6 +34,35 @@
@FeignClient (value = "portfolio-v1", path = "/portfolio/v1", configuration = CustomFeignClientsConfiguration.class)
public interface IndividualLending {
@RequestMapping(
+ value = "/individuallending/products/{productidentifier}/lossprovisionsteps/{dayslate}",
+ method = RequestMethod.DELETE,
+ produces = MediaType.ALL_VALUE,
+ consumes = MediaType.APPLICATION_JSON_VALUE
+ )
+ void deleteLossProvisionStep(
+ @PathVariable("productidentifier") final String productIdentifier,
+ @PathVariable("dayslate") final String daysLate);
+
+ @RequestMapping(
+ value = "/individuallending/products/{productidentifier}/lossprovisionsteps/",
+ method = RequestMethod.PUT,
+ produces = MediaType.ALL_VALUE,
+ consumes = MediaType.APPLICATION_JSON_VALUE
+ )
+ void setLossProvisionSteps(
+ @PathVariable("productidentifier") final String productIdentifier,
+ @RequestBody List<LossProvisionStep> lossProvisionSteps);
+
+ @RequestMapping(
+ value = "/individuallending/products/{productidentifier}/lossprovisionsteps",
+ method = RequestMethod.GET,
+ produces = MediaType.ALL_VALUE,
+ consumes = MediaType.APPLICATION_JSON_VALUE
+ )
+ List<LossProvisionStep> getAllLossProvisionSteps(
+ @PathVariable("productidentifier") final String productIdentifier);
+
+ @RequestMapping(
value = "/individuallending/products/{productidentifier}/cases/{caseidentifier}/plannedpayments",
method = RequestMethod.GET,
produces = MediaType.ALL_VALUE,
diff --git a/api/src/main/java/io/mifos/individuallending/api/v1/domain/product/LossProvisionStep.java b/api/src/main/java/io/mifos/individuallending/api/v1/domain/product/LossProvisionStep.java
new file mode 100644
index 0000000..664f669
--- /dev/null
+++ b/api/src/main/java/io/mifos/individuallending/api/v1/domain/product/LossProvisionStep.java
@@ -0,0 +1,83 @@
+/*
+ * Copyright 2017 Kuelap, Inc.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package io.mifos.individuallending.api.v1.domain.product;
+
+import org.hibernate.validator.constraints.Range;
+
+import javax.validation.constraints.DecimalMax;
+import javax.validation.constraints.DecimalMin;
+import javax.validation.constraints.NotNull;
+import java.math.BigDecimal;
+import java.util.Objects;
+
+/**
+ * @author Myrle Krantz
+ */
+public class LossProvisionStep {
+ @Range(min = 0)
+ private int daysLate;
+
+ @DecimalMin(value = "0.00")
+ @DecimalMax(value = "100.00")
+ @NotNull
+ private BigDecimal percentProvision;
+
+ public LossProvisionStep() {
+ }
+
+ public LossProvisionStep(int daysLate, BigDecimal percentProvision) {
+ this.daysLate = daysLate;
+ this.percentProvision = percentProvision;
+ }
+
+ public int getDaysLate() {
+ return daysLate;
+ }
+
+ public void setDaysLate(int daysLate) {
+ this.daysLate = daysLate;
+ }
+
+ public BigDecimal getPercentProvision() {
+ return percentProvision;
+ }
+
+ public void setPercentProvision(BigDecimal percentProvision) {
+ this.percentProvision = percentProvision;
+ }
+
+ @Override
+ public boolean equals(Object o) {
+ if (this == o) return true;
+ if (o == null || getClass() != o.getClass()) return false;
+ LossProvisionStep that = (LossProvisionStep) o;
+ return daysLate == that.daysLate &&
+ Objects.equals(percentProvision, that.percentProvision);
+ }
+
+ @Override
+ public int hashCode() {
+ return Objects.hash(daysLate, percentProvision);
+ }
+
+ @Override
+ public String toString() {
+ return "LossProvisionStep{" +
+ "daysLate=" + daysLate +
+ ", percentProvision=" + percentProvision +
+ '}';
+ }
+}
diff --git a/api/src/main/java/io/mifos/portfolio/api/v1/PermittableGroupIds.java b/api/src/main/java/io/mifos/portfolio/api/v1/PermittableGroupIds.java
index 85dab16..48b294c 100644
--- a/api/src/main/java/io/mifos/portfolio/api/v1/PermittableGroupIds.java
+++ b/api/src/main/java/io/mifos/portfolio/api/v1/PermittableGroupIds.java
@@ -21,6 +21,7 @@
@SuppressWarnings("unused")
public interface PermittableGroupIds {
String PRODUCT_OPERATIONS_MANAGEMENT = "portfolio__v1__products__enable";
+ String PRODUCT_LOSS_PROVISIONING_MANAGEMENT = "portfolio__v1__products__lossprov";
String PRODUCT_MANAGEMENT = "portfolio__v1__products";
String CASE_MANAGEMENT = "portfolio__v1__case";
}
diff --git a/api/src/test/java/io/mifos/Fixture.java b/api/src/test/java/io/mifos/Fixture.java
index 55fe883..6e10700 100644
--- a/api/src/test/java/io/mifos/Fixture.java
+++ b/api/src/test/java/io/mifos/Fixture.java
@@ -63,7 +63,7 @@
accountAssignments.add(new AccountAssignment(INTEREST_ACCRUAL, "001-007"));
accountAssignments.add(new AccountAssignment(LATE_FEE_INCOME, "001-008"));
accountAssignments.add(new AccountAssignment(LATE_FEE_ACCRUAL, "001-009"));
- accountAssignments.add(new AccountAssignment(ARREARS_ALLOWANCE, "001-010"));
+ accountAssignments.add(new AccountAssignment(GENERAL_LOSS_ALLOWANCE, "001-010"));
//accountAssignments.add(new AccountAssignment(ENTRY, ...));
// Don't assign entry account in test since it usually will not be assigned IRL.
accountAssignments.add(new AccountAssignment(LOAN_FUNDS_SOURCE, LOAN_FUNDS_SOURCE_ACCOUNT_IDENTIFIER));
diff --git a/api/src/test/java/io/mifos/individuallending/api/v1/domain/product/LossProvisionStepTest.java b/api/src/test/java/io/mifos/individuallending/api/v1/domain/product/LossProvisionStepTest.java
new file mode 100644
index 0000000..e7947b6
--- /dev/null
+++ b/api/src/test/java/io/mifos/individuallending/api/v1/domain/product/LossProvisionStepTest.java
@@ -0,0 +1,56 @@
+package io.mifos.individuallending.api.v1.domain.product;
+
+import io.mifos.core.test.domain.ValidationTest;
+import io.mifos.core.test.domain.ValidationTestCase;
+import org.junit.runners.Parameterized;
+
+import java.math.BigDecimal;
+import java.util.ArrayList;
+import java.util.Collection;
+
+public class LossProvisionStepTest extends ValidationTest<LossProvisionStep> {
+
+ public LossProvisionStepTest(final ValidationTestCase<LossProvisionStep> testCase)
+ {
+ super(testCase);
+ }
+
+ @Override
+ protected LossProvisionStep createValidTestSubject() {
+ final LossProvisionStep ret = new LossProvisionStep();
+ ret.setPercentProvision(BigDecimal.ONE);
+ ret.setDaysLate(10);
+ return ret;
+ }
+
+ @Parameterized.Parameters
+ public static Collection testCases() {
+ final Collection<ValidationTestCase> ret = new ArrayList<>();
+
+ ret.add(new ValidationTestCase<LossProvisionStep>("valid"));
+ ret.add(new ValidationTestCase<LossProvisionStep>("largeDaysLate")
+ .adjustment(x -> x.setDaysLate(Integer.MAX_VALUE))
+ .valid(true));
+ ret.add(new ValidationTestCase<LossProvisionStep>("zeroDaysLate")
+ .adjustment(x -> x.setDaysLate(0))
+ .valid(true));
+ ret.add(new ValidationTestCase<LossProvisionStep>("oneDaysLate")
+ .adjustment(x -> x.setDaysLate(1))
+ .valid(true));
+ ret.add(new ValidationTestCase<LossProvisionStep>("negativeDaysLate")
+ .adjustment(x -> x.setDaysLate(-1))
+ .valid(false));
+ ret.add(new ValidationTestCase<LossProvisionStep>("negativeProvisioning")
+ .adjustment(x -> x.setPercentProvision(BigDecimal.TEN.negate()))
+ .valid(false));
+ ret.add(new ValidationTestCase<LossProvisionStep>("over100Provisioning")
+ .adjustment(x -> x.setPercentProvision(BigDecimal.valueOf(100_01, 2)))
+ .valid(false));
+ ret.add(new ValidationTestCase<LossProvisionStep>("exactly100Provisioning")
+ .adjustment(x -> x.setPercentProvision(BigDecimal.valueOf(100_00, 2)))
+ .valid(true));
+
+ return ret;
+ }
+
+}
\ No newline at end of file