Implemented persistence and default values for loan loss provisioning.
Connected API to persistence.
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 7f378d5..c401122 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,13 +18,12 @@
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.individuallending.api.v1.domain.product.LossProvisionConfiguration;
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.*;
-import java.util.List;
import java.util.stream.Stream;
/**
@@ -35,22 +34,22 @@
public interface IndividualLending {
@RequestMapping(
- value = "/individuallending/products/{productidentifier}/lossprovisionsteps",
+ value = "/individuallending/products/{productidentifier}/lossprovisionconfiguration",
method = RequestMethod.PUT,
produces = MediaType.ALL_VALUE,
consumes = MediaType.APPLICATION_JSON_VALUE
)
- void setLossProvisionSteps(
+ void changeLossProvisionConfiguration(
@PathVariable("productidentifier") final String productIdentifier,
- @RequestBody List<LossProvisionStep> lossProvisionSteps);
+ @RequestBody LossProvisionConfiguration lossProvisionConfiguration);
@RequestMapping(
- value = "/individuallending/products/{productidentifier}/lossprovisionsteps",
+ value = "/individuallending/products/{productidentifier}/lossprovisionconfiguration",
method = RequestMethod.GET,
produces = MediaType.ALL_VALUE,
consumes = MediaType.APPLICATION_JSON_VALUE
)
- List<LossProvisionStep> getAllLossProvisionSteps(
+ LossProvisionConfiguration getLossProvisionConfiguration(
@PathVariable("productidentifier") final String productIdentifier);
@RequestMapping(
diff --git a/api/src/main/java/io/mifos/individuallending/api/v1/domain/product/LossProvisionConfiguration.java b/api/src/main/java/io/mifos/individuallending/api/v1/domain/product/LossProvisionConfiguration.java
new file mode 100644
index 0000000..aa3707f
--- /dev/null
+++ b/api/src/main/java/io/mifos/individuallending/api/v1/domain/product/LossProvisionConfiguration.java
@@ -0,0 +1,62 @@
+/*
+ * 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 io.mifos.portfolio.api.v1.validation.ValidLossProvisionList;
+
+import java.util.List;
+import java.util.Objects;
+
+@SuppressWarnings("WeakerAccess")
+public class LossProvisionConfiguration {
+ @ValidLossProvisionList
+ private List<LossProvisionStep> lossProvisionSteps;
+
+ public LossProvisionConfiguration() {
+ }
+
+ public LossProvisionConfiguration(List<LossProvisionStep> lossProvisionSteps) {
+ this.lossProvisionSteps = lossProvisionSteps;
+ }
+
+ public List<LossProvisionStep> getLossProvisionSteps() {
+ return lossProvisionSteps;
+ }
+
+ public void setLossProvisionSteps(List<LossProvisionStep> lossProvisionSteps) {
+ this.lossProvisionSteps = lossProvisionSteps;
+ }
+
+ @Override
+ public boolean equals(Object o) {
+ if (this == o) return true;
+ if (o == null || getClass() != o.getClass()) return false;
+ LossProvisionConfiguration that = (LossProvisionConfiguration) o;
+ return Objects.equals(lossProvisionSteps, that.lossProvisionSteps);
+ }
+
+ @Override
+ public int hashCode() {
+ return Objects.hash(lossProvisionSteps);
+ }
+
+ @Override
+ public String toString() {
+ return "LossProvisionConfiguration{" +
+ "lossProvisionSteps=" + lossProvisionSteps +
+ '}';
+ }
+}
diff --git a/api/src/main/java/io/mifos/individuallending/api/v1/events/IndividualLoanEventConstants.java b/api/src/main/java/io/mifos/individuallending/api/v1/events/IndividualLoanEventConstants.java
index 89e1e4f..6264e74 100644
--- a/api/src/main/java/io/mifos/individuallending/api/v1/events/IndividualLoanEventConstants.java
+++ b/api/src/main/java/io/mifos/individuallending/api/v1/events/IndividualLoanEventConstants.java
@@ -22,6 +22,7 @@
String DESTINATION = "portfolio-v1";
String SELECTOR_NAME = "action";
+ String PUT_LOSS_PROVISION_STEPS = "put-loss-provision-steps";
String OPEN_INDIVIDUALLOAN_CASE = "open-individualloan-case";
String DENY_INDIVIDUALLOAN_CASE = "deny-individualloan-case";
String APPROVE_INDIVIDUALLOAN_CASE = "approve-individualloan-case";
@@ -34,6 +35,7 @@
String CLOSE_INDIVIDUALLOAN_CASE = "close-individualloan-case";
String RECOVER_INDIVIDUALLOAN_CASE = "recover-individualloan-case";
+ String SELECTOR_PUT_LOSS_PROVISION_STEPS = SELECTOR_NAME + " = '" + PUT_LOSS_PROVISION_STEPS + "'";
String SELECTOR_OPEN_INDIVIDUALLOAN_CASE = SELECTOR_NAME + " = '" + OPEN_INDIVIDUALLOAN_CASE + "'";
String SELECTOR_DENY_INDIVIDUALLOAN_CASE = SELECTOR_NAME + " = '" + DENY_INDIVIDUALLOAN_CASE + "'";
String SELECTOR_APPROVE_INDIVIDUALLOAN_CASE = SELECTOR_NAME + " = '" + APPROVE_INDIVIDUALLOAN_CASE + "'";
@@ -45,4 +47,4 @@
String SELECTOR_WRITE_OFF_INDIVIDUALLOAN_CASE = SELECTOR_NAME + " = '" + WRITE_OFF_INDIVIDUALLOAN_CASE + "'";
String SELECTOR_CLOSE_INDIVIDUALLOAN_CASE = SELECTOR_NAME + " = '" + CLOSE_INDIVIDUALLOAN_CASE + "'";
String SELECTOR_RECOVER_INDIVIDUALLOAN_CASE = SELECTOR_NAME + " = '" + RECOVER_INDIVIDUALLOAN_CASE + "'";
-}
+}
\ No newline at end of file
diff --git a/api/src/main/java/io/mifos/portfolio/api/v1/validation/CheckValidLossProvisionList.java b/api/src/main/java/io/mifos/portfolio/api/v1/validation/CheckValidLossProvisionList.java
new file mode 100644
index 0000000..3085033
--- /dev/null
+++ b/api/src/main/java/io/mifos/portfolio/api/v1/validation/CheckValidLossProvisionList.java
@@ -0,0 +1,44 @@
+/*
+ * 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.portfolio.api.v1.validation;
+
+import io.mifos.individuallending.api.v1.domain.product.LossProvisionStep;
+
+import javax.validation.ConstraintValidator;
+import javax.validation.ConstraintValidatorContext;
+import java.math.BigDecimal;
+import java.util.List;
+
+/**
+ * @author Myrle Krantz
+ */
+public class CheckValidLossProvisionList implements ConstraintValidator<ValidLossProvisionList, List<LossProvisionStep>> {
+ @Override
+ public void initialize(ValidLossProvisionList constraintAnnotation) {
+
+ }
+
+ @Override
+ public boolean isValid(
+ final List<LossProvisionStep> value,
+ final ConstraintValidatorContext context) {
+ final BigDecimal sum = value.stream()
+ .map(LossProvisionStep::getPercentProvision)
+ .map(x -> x.setScale(2, BigDecimal.ROUND_HALF_EVEN))
+ .reduce(BigDecimal.ZERO, BigDecimal::add);
+ return sum.compareTo(BigDecimal.valueOf(100_00, 2)) == 0;
+ }
+}
\ No newline at end of file
diff --git a/api/src/main/java/io/mifos/portfolio/api/v1/validation/ValidLossProvisionList.java b/api/src/main/java/io/mifos/portfolio/api/v1/validation/ValidLossProvisionList.java
new file mode 100644
index 0000000..4e4fb44
--- /dev/null
+++ b/api/src/main/java/io/mifos/portfolio/api/v1/validation/ValidLossProvisionList.java
@@ -0,0 +1,38 @@
+/*
+ * 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.portfolio.api.v1.validation;
+
+import javax.validation.Constraint;
+import javax.validation.Payload;
+import java.lang.annotation.*;
+
+/**
+ * @author Myrle Krantz
+ */
+@SuppressWarnings("unused")
+@Target({ElementType.FIELD, ElementType.METHOD, ElementType.PARAMETER})
+@Retention(RetentionPolicy.RUNTIME)
+@Documented
+@Constraint(
+ validatedBy = {CheckValidLossProvisionList.class}
+)
+public @interface ValidLossProvisionList {
+ String message() default "Loss provision percents should sum to 100.";
+
+ Class<?>[] groups() default {};
+
+ Class<? extends Payload>[] payload() default {};
+}
diff --git a/api/src/test/java/io/mifos/individuallending/api/v1/domain/product/LossProvisionConfigurationTest.java b/api/src/test/java/io/mifos/individuallending/api/v1/domain/product/LossProvisionConfigurationTest.java
new file mode 100644
index 0000000..ba6e24b
--- /dev/null
+++ b/api/src/test/java/io/mifos/individuallending/api/v1/domain/product/LossProvisionConfigurationTest.java
@@ -0,0 +1,66 @@
+/*
+ * 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 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;
+import java.util.Collections;
+import java.util.List;
+
+public class LossProvisionConfigurationTest extends ValidationTest<LossProvisionConfiguration> {
+
+ public LossProvisionConfigurationTest(ValidationTestCase<LossProvisionConfiguration> testCase) {
+ super(testCase);
+ }
+
+ @Override
+ protected LossProvisionConfiguration createValidTestSubject() {
+ final LossProvisionConfiguration ret = new LossProvisionConfiguration();
+ final List<LossProvisionStep> lossProvisionSteps = new ArrayList<>();
+ lossProvisionSteps.add(new LossProvisionStep(0, BigDecimal.ONE));
+ lossProvisionSteps.add(new LossProvisionStep(1, BigDecimal.valueOf(9)));
+ lossProvisionSteps.add(new LossProvisionStep(10, BigDecimal.valueOf(20)));
+ lossProvisionSteps.add(new LossProvisionStep(50, BigDecimal.valueOf(70)));
+ ret.setLossProvisionSteps(lossProvisionSteps);
+ return ret;
+ }
+
+ @Parameterized.Parameters
+ public static Collection testCases() {
+ final Collection<ValidationTestCase> ret = new ArrayList<>();
+
+ ret.add(new ValidationTestCase<LossProvisionConfiguration>("valid"));
+ ret.add(new ValidationTestCase<LossProvisionConfiguration>("emptyList")
+ .adjustment(x -> x.setLossProvisionSteps(Collections.emptyList()))
+ .valid(false));
+ ret.add(new ValidationTestCase<LossProvisionConfiguration>("nullList")
+ .adjustment(x -> x.setLossProvisionSteps(Collections.emptyList()))
+ .valid(false));
+ ret.add(new ValidationTestCase<LossProvisionConfiguration>("sumTooSmall")
+ .adjustment(x -> x.getLossProvisionSteps().get(0).setPercentProvision(BigDecimal.valueOf(0.1)))
+ .valid(false));
+ ret.add(new ValidationTestCase<LossProvisionConfiguration>("sumTooLarge")
+ .adjustment(x -> x.getLossProvisionSteps().get(3).setPercentProvision(BigDecimal.valueOf(71)))
+ .valid(false));
+
+ return ret;
+ }
+}
\ No newline at end of file
diff --git a/component-test/src/main/java/io/mifos/portfolio/TestLossProvisionSteps.java b/component-test/src/main/java/io/mifos/portfolio/TestLossProvisionSteps.java
new file mode 100644
index 0000000..f86ef33
--- /dev/null
+++ b/component-test/src/main/java/io/mifos/portfolio/TestLossProvisionSteps.java
@@ -0,0 +1,48 @@
+/*
+ * 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.portfolio;
+
+import io.mifos.individuallending.api.v1.domain.product.LossProvisionConfiguration;
+import io.mifos.individuallending.api.v1.domain.product.LossProvisionStep;
+import io.mifos.individuallending.api.v1.events.IndividualLoanEventConstants;
+import io.mifos.portfolio.api.v1.domain.Product;
+import org.junit.Assert;
+import org.junit.Test;
+
+import java.math.BigDecimal;
+import java.util.ArrayList;
+import java.util.List;
+
+/**
+ * @author Myrle Krantz
+ */
+public class TestLossProvisionSteps extends AbstractPortfolioTest {
+ @Test
+ public void shouldChangeAndGetLossProvisionSteps() throws InterruptedException {
+ final Product product = createAdjustedProduct(x -> {});
+ final List<LossProvisionStep> lossProvisionSteps = new ArrayList<>();
+ lossProvisionSteps.add(new LossProvisionStep(0, BigDecimal.valueOf(1_00, 2)));
+ lossProvisionSteps.add(new LossProvisionStep(1, BigDecimal.valueOf(9_00, 2)));
+ lossProvisionSteps.add(new LossProvisionStep(30, BigDecimal.valueOf(35_00, 2)));
+ lossProvisionSteps.add(new LossProvisionStep(60, BigDecimal.valueOf(55_00, 2)));
+ final LossProvisionConfiguration lossProvisionConfiguration = new LossProvisionConfiguration(lossProvisionSteps);
+ individualLending.changeLossProvisionConfiguration(product.getIdentifier(), lossProvisionConfiguration);
+
+ Assert.assertTrue(eventRecorder.wait(IndividualLoanEventConstants.PUT_LOSS_PROVISION_STEPS, product.getIdentifier()));
+ final LossProvisionConfiguration lossProvisionConfigurationAsSaved = individualLending.getLossProvisionConfiguration(product.getIdentifier());
+ Assert.assertEquals(lossProvisionConfiguration, lossProvisionConfigurationAsSaved);
+ }
+}
\ No newline at end of file
diff --git a/component-test/src/main/java/io/mifos/portfolio/TestSuite.java b/component-test/src/main/java/io/mifos/portfolio/TestSuite.java
index 44d8cc3..0be9417 100644
--- a/component-test/src/main/java/io/mifos/portfolio/TestSuite.java
+++ b/component-test/src/main/java/io/mifos/portfolio/TestSuite.java
@@ -32,7 +32,8 @@
TestPatterns.class,
TestProducts.class,
TestTaskDefinitions.class,
- TestTaskInstances.class
+ TestTaskInstances.class,
+ TestLossProvisionSteps.class
})
public class TestSuite extends SuiteTestEnvironment {
}
diff --git a/component-test/src/main/java/io/mifos/portfolio/listener/LossProvisionStepsEventListener.java b/component-test/src/main/java/io/mifos/portfolio/listener/LossProvisionStepsEventListener.java
new file mode 100644
index 0000000..b6bc1c4
--- /dev/null
+++ b/component-test/src/main/java/io/mifos/portfolio/listener/LossProvisionStepsEventListener.java
@@ -0,0 +1,51 @@
+/*
+ * 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.portfolio.listener;
+
+import io.mifos.core.lang.config.TenantHeaderFilter;
+import io.mifos.core.test.listener.EventRecorder;
+import io.mifos.individuallending.api.v1.events.IndividualLoanEventConstants;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.jms.annotation.JmsListener;
+import org.springframework.messaging.handler.annotation.Header;
+import org.springframework.stereotype.Component;
+
+/**
+ * @author Myrle Krantz
+ */
+@SuppressWarnings("unused")
+@Component
+public class LossProvisionStepsEventListener {
+ private final EventRecorder eventRecorder;
+
+ @Autowired
+ public LossProvisionStepsEventListener(final EventRecorder eventRecorder) {
+ super();
+ this.eventRecorder = eventRecorder;
+ }
+
+ @JmsListener(
+ subscription = IndividualLoanEventConstants.DESTINATION,
+ destination = IndividualLoanEventConstants.DESTINATION,
+ selector = IndividualLoanEventConstants.SELECTOR_PUT_LOSS_PROVISION_STEPS
+ )
+ public void onChangeLossProvisionSteps(
+ @Header(TenantHeaderFilter.TENANT_HEADER) final String tenant,
+ final String payload)
+ {
+ this.eventRecorder.event(tenant, IndividualLoanEventConstants.PUT_LOSS_PROVISION_STEPS, payload, String.class);
+ }
+}
\ No newline at end of file
diff --git a/service/src/main/java/io/mifos/individuallending/internal/command/ChangeLossProvisionSteps.java b/service/src/main/java/io/mifos/individuallending/internal/command/ChangeLossProvisionSteps.java
index 13419dc..7468b78 100644
--- a/service/src/main/java/io/mifos/individuallending/internal/command/ChangeLossProvisionSteps.java
+++ b/service/src/main/java/io/mifos/individuallending/internal/command/ChangeLossProvisionSteps.java
@@ -15,19 +15,33 @@
*/
package io.mifos.individuallending.internal.command;
-import io.mifos.individuallending.api.v1.domain.product.LossProvisionStep;
-
-import java.util.List;
+import io.mifos.individuallending.api.v1.domain.product.LossProvisionConfiguration;
/**
* @author Myrle Krantz
*/
public class ChangeLossProvisionSteps {
private final String productIdentifier;
- private final List<LossProvisionStep> lossProvisionSteps;
+ private final LossProvisionConfiguration lossProvisionConfiguration;
- public ChangeLossProvisionSteps(String productIdentifier, List<LossProvisionStep> lossProvisionSteps) {
+ public ChangeLossProvisionSteps(String productIdentifier, LossProvisionConfiguration lossProvisionConfiguration) {
this.productIdentifier = productIdentifier;
- this.lossProvisionSteps = lossProvisionSteps;
+ this.lossProvisionConfiguration = lossProvisionConfiguration;
+ }
+
+ public String getProductIdentifier() {
+ return productIdentifier;
+ }
+
+ public LossProvisionConfiguration getLossProvisionConfiguration() {
+ return lossProvisionConfiguration;
+ }
+
+ @Override
+ public String toString() {
+ return "ChangeLossProvisionSteps{" +
+ "productIdentifier='" + productIdentifier + '\'' +
+ ", lossProvisionConfiguration=" + lossProvisionConfiguration +
+ '}';
}
}
diff --git a/service/src/main/java/io/mifos/individuallending/internal/command/handler/IndividualLoanCommandHandler.java b/service/src/main/java/io/mifos/individuallending/internal/command/handler/IndividualLoanCommandHandler.java
index 46f7689..23f313f 100644
--- a/service/src/main/java/io/mifos/individuallending/internal/command/handler/IndividualLoanCommandHandler.java
+++ b/service/src/main/java/io/mifos/individuallending/internal/command/handler/IndividualLoanCommandHandler.java
@@ -38,7 +38,6 @@
import io.mifos.portfolio.api.v1.domain.AccountAssignment;
import io.mifos.portfolio.api.v1.domain.Case;
import io.mifos.portfolio.api.v1.domain.CostComponent;
-import io.mifos.portfolio.api.v1.events.EventConstants;
import io.mifos.portfolio.service.internal.mapper.CaseMapper;
import io.mifos.portfolio.service.internal.repository.*;
import io.mifos.portfolio.service.internal.util.AccountingAdapter;
@@ -118,7 +117,7 @@
@Transactional
@CommandHandler(logStart = CommandLogLevel.INFO, logFinish = CommandLogLevel.INFO)
@EventEmitter(
- selectorName = EventConstants.SELECTOR_NAME,
+ selectorName = IndividualLoanEventConstants.SELECTOR_NAME,
selectorValue = IndividualLoanEventConstants.OPEN_INDIVIDUALLOAN_CASE)
public IndividualLoanCommandEvent process(final OpenCommand command) {
final String productIdentifier = command.getProductIdentifier();
@@ -165,7 +164,7 @@
@Transactional
@CommandHandler(logStart = CommandLogLevel.INFO, logFinish = CommandLogLevel.INFO)
@EventEmitter(
- selectorName = EventConstants.SELECTOR_NAME,
+ selectorName = IndividualLoanEventConstants.SELECTOR_NAME,
selectorValue = IndividualLoanEventConstants.DENY_INDIVIDUALLOAN_CASE)
public IndividualLoanCommandEvent process(final DenyCommand command) {
final String productIdentifier = command.getProductIdentifier();
@@ -224,7 +223,7 @@
@Transactional
@CommandHandler(logStart = CommandLogLevel.INFO, logFinish = CommandLogLevel.INFO)
@EventEmitter(
- selectorName = EventConstants.SELECTOR_NAME,
+ selectorName = IndividualLoanEventConstants.SELECTOR_NAME,
selectorValue = IndividualLoanEventConstants.APPROVE_INDIVIDUALLOAN_CASE)
public IndividualLoanCommandEvent process(final ApproveCommand command) throws InterruptedException
{
@@ -306,7 +305,7 @@
@Transactional
@CommandHandler(logStart = CommandLogLevel.INFO, logFinish = CommandLogLevel.INFO)
- @EventEmitter(selectorName = EventConstants.SELECTOR_NAME, selectorValue = IndividualLoanEventConstants.DISBURSE_INDIVIDUALLOAN_CASE)
+ @EventEmitter(selectorName = IndividualLoanEventConstants.SELECTOR_NAME, selectorValue = IndividualLoanEventConstants.DISBURSE_INDIVIDUALLOAN_CASE)
public IndividualLoanCommandEvent process(final DisburseCommand command) {
final String productIdentifier = command.getProductIdentifier();
final String caseIdentifier = command.getCaseIdentifier();
@@ -368,7 +367,7 @@
@Transactional
@CommandHandler(logStart = CommandLogLevel.INFO, logFinish = CommandLogLevel.INFO)
@EventEmitter(
- selectorName = EventConstants.SELECTOR_NAME,
+ selectorName = IndividualLoanEventConstants.SELECTOR_NAME,
selectorValue = IndividualLoanEventConstants.APPLY_INTEREST_INDIVIDUALLOAN_CASE)
public IndividualLoanCommandEvent process(final ApplyInterestCommand command) {
final String productIdentifier = command.getProductIdentifier();
@@ -411,7 +410,7 @@
@Transactional
@CommandHandler(logStart = CommandLogLevel.INFO, logFinish = CommandLogLevel.INFO)
@EventEmitter(
- selectorName = EventConstants.SELECTOR_NAME,
+ selectorName = IndividualLoanEventConstants.SELECTOR_NAME,
selectorValue = IndividualLoanEventConstants.ACCEPT_PAYMENT_INDIVIDUALLOAN_CASE)
public IndividualLoanCommandEvent process(final AcceptPaymentCommand command) {
final String productIdentifier = command.getProductIdentifier();
@@ -462,7 +461,7 @@
@Transactional
@CommandHandler(logStart = CommandLogLevel.INFO, logFinish = CommandLogLevel.INFO)
@EventEmitter(
- selectorName = EventConstants.SELECTOR_NAME,
+ selectorName = IndividualLoanEventConstants.SELECTOR_NAME,
selectorValue = IndividualLoanEventConstants.MARK_LATE_INDIVIDUALLOAN_CASE)
public IndividualLoanCommandEvent process(final MarkLateCommand command) {
final String productIdentifier = command.getProductIdentifier();
@@ -509,7 +508,7 @@
@Transactional
@CommandHandler(logStart = CommandLogLevel.INFO, logFinish = CommandLogLevel.INFO)
- @EventEmitter(selectorName = EventConstants.SELECTOR_NAME, selectorValue = IndividualLoanEventConstants.WRITE_OFF_INDIVIDUALLOAN_CASE)
+ @EventEmitter(selectorName = IndividualLoanEventConstants.SELECTOR_NAME, selectorValue = IndividualLoanEventConstants.WRITE_OFF_INDIVIDUALLOAN_CASE)
public IndividualLoanCommandEvent process(final WriteOffCommand command) {
final String productIdentifier = command.getProductIdentifier();
final String caseIdentifier = command.getCaseIdentifier();
@@ -555,7 +554,7 @@
@Transactional
@CommandHandler(logStart = CommandLogLevel.INFO, logFinish = CommandLogLevel.INFO)
- @EventEmitter(selectorName = EventConstants.SELECTOR_NAME, selectorValue = IndividualLoanEventConstants.CLOSE_INDIVIDUALLOAN_CASE)
+ @EventEmitter(selectorName = IndividualLoanEventConstants.SELECTOR_NAME, selectorValue = IndividualLoanEventConstants.CLOSE_INDIVIDUALLOAN_CASE)
public IndividualLoanCommandEvent process(final CloseCommand command) {
final String productIdentifier = command.getProductIdentifier();
final String caseIdentifier = command.getCaseIdentifier();
@@ -592,7 +591,7 @@
@Transactional
@CommandHandler(logStart = CommandLogLevel.INFO, logFinish = CommandLogLevel.INFO)
- @EventEmitter(selectorName = EventConstants.SELECTOR_NAME, selectorValue = IndividualLoanEventConstants.RECOVER_INDIVIDUALLOAN_CASE)
+ @EventEmitter(selectorName = IndividualLoanEventConstants.SELECTOR_NAME, selectorValue = IndividualLoanEventConstants.RECOVER_INDIVIDUALLOAN_CASE)
public IndividualLoanCommandEvent process(final RecoverCommand command) {
final String productIdentifier = command.getProductIdentifier();
final String caseIdentifier = command.getCaseIdentifier();
diff --git a/service/src/main/java/io/mifos/individuallending/internal/command/handler/LossProvisionStepsCommandHandler.java b/service/src/main/java/io/mifos/individuallending/internal/command/handler/LossProvisionStepsCommandHandler.java
new file mode 100644
index 0000000..31cd9d8
--- /dev/null
+++ b/service/src/main/java/io/mifos/individuallending/internal/command/handler/LossProvisionStepsCommandHandler.java
@@ -0,0 +1,68 @@
+/*
+ * 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.internal.command.handler;
+
+import io.mifos.core.command.annotation.Aggregate;
+import io.mifos.core.command.annotation.CommandHandler;
+import io.mifos.core.command.annotation.CommandLogLevel;
+import io.mifos.core.command.annotation.EventEmitter;
+import io.mifos.core.lang.ServiceException;
+import io.mifos.individuallending.api.v1.events.IndividualLoanEventConstants;
+import io.mifos.individuallending.internal.command.ChangeLossProvisionSteps;
+import io.mifos.individuallending.internal.mapper.LossProvisionStepMapper;
+import io.mifos.individuallending.internal.repository.LossProvisionStepEntity;
+import io.mifos.individuallending.internal.repository.LossProvisionStepRepository;
+import io.mifos.portfolio.service.internal.repository.ProductEntity;
+import io.mifos.portfolio.service.internal.repository.ProductRepository;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.transaction.annotation.Transactional;
+
+import java.util.stream.Stream;
+
+
+/**
+ * @author Myrle Krantz
+ */
+@Aggregate
+public class LossProvisionStepsCommandHandler {
+ private final LossProvisionStepRepository lossProvisionStepRepository;
+ private final ProductRepository productRepository;
+
+ @Autowired
+ public LossProvisionStepsCommandHandler(
+ final LossProvisionStepRepository lossProvisionStepRepository,
+ final ProductRepository productRepository) {
+ this.lossProvisionStepRepository = lossProvisionStepRepository;
+ this.productRepository = productRepository;
+ }
+
+ @Transactional
+ @CommandHandler(logStart = CommandLogLevel.INFO, logFinish = CommandLogLevel.INFO)
+ @EventEmitter(
+ selectorName = IndividualLoanEventConstants.SELECTOR_NAME,
+ selectorValue = IndividualLoanEventConstants.PUT_LOSS_PROVISION_STEPS)
+ public String process(final ChangeLossProvisionSteps command) {
+ final ProductEntity productEntity = productRepository.findByIdentifier(command.getProductIdentifier())
+ .orElseThrow(() -> ServiceException.notFound("Product not found ''{0}''.", command.getProductIdentifier()));
+ final Stream<LossProvisionStepEntity> lossProvisionSteps = lossProvisionStepRepository.findByProductId(productEntity.getId());
+ lossProvisionSteps.forEach(lossProvisionStepRepository::delete);
+ command.getLossProvisionConfiguration().getLossProvisionSteps().stream()
+ .map(lossProvisionStep -> LossProvisionStepMapper.map(productEntity.getId(), lossProvisionStep))
+ .forEach(lossProvisionStepRepository::save);
+
+ return command.getProductIdentifier();
+ }
+}
\ No newline at end of file
diff --git a/service/src/main/java/io/mifos/individuallending/internal/service/LossProvisionStepService.java b/service/src/main/java/io/mifos/individuallending/internal/service/LossProvisionStepService.java
index a079ecf..d07df7d 100644
--- a/service/src/main/java/io/mifos/individuallending/internal/service/LossProvisionStepService.java
+++ b/service/src/main/java/io/mifos/individuallending/internal/service/LossProvisionStepService.java
@@ -23,6 +23,8 @@
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
+import java.math.BigDecimal;
+import java.util.Arrays;
import java.util.List;
import java.util.Optional;
import java.util.stream.Collectors;
@@ -32,6 +34,12 @@
*/
@Service
public class LossProvisionStepService {
+ private final static List<LossProvisionStep> DEFAULT_LOSS_PROVISION_STEPS = Arrays.asList(
+ new LossProvisionStep(0, BigDecimal.ONE),
+ new LossProvisionStep(1, BigDecimal.valueOf(9)),
+ new LossProvisionStep(30, BigDecimal.valueOf(30)),
+ new LossProvisionStep(60, BigDecimal.valueOf(60)));
+
private final ProductRepository productRepository;
private final LossProvisionStepRepository lossProvisionStepRepository;
@@ -54,8 +62,12 @@
final Long productId = productRepository.findByIdentifier(productIdentifier)
.orElseThrow(() -> ServiceException.notFound("Product ''{}'' doesn''t exist.", productIdentifier))
.getId();
- return lossProvisionStepRepository.findByProductId(productId)
+ final List<LossProvisionStep> ret = lossProvisionStepRepository.findByProductId(productId)
.map(LossProvisionStepMapper::map)
.collect(Collectors.toList());
+ if (!ret.isEmpty())
+ return ret;
+ else
+ return DEFAULT_LOSS_PROVISION_STEPS;
}
}
\ No newline at end of file
diff --git a/service/src/main/java/io/mifos/individuallending/rest/LossProvisionStepRestController.java b/service/src/main/java/io/mifos/individuallending/rest/LossProvisionStepRestController.java
index c2d0d0d..24dc64b 100644
--- a/service/src/main/java/io/mifos/individuallending/rest/LossProvisionStepRestController.java
+++ b/service/src/main/java/io/mifos/individuallending/rest/LossProvisionStepRestController.java
@@ -19,7 +19,7 @@
import io.mifos.anubis.annotation.Permittable;
import io.mifos.core.command.gateway.CommandGateway;
import io.mifos.core.lang.ServiceException;
-import io.mifos.individuallending.api.v1.domain.product.LossProvisionStep;
+import io.mifos.individuallending.api.v1.domain.product.LossProvisionConfiguration;
import io.mifos.individuallending.internal.command.ChangeLossProvisionSteps;
import io.mifos.individuallending.internal.service.LossProvisionStepService;
import io.mifos.portfolio.api.v1.PermittableGroupIds;
@@ -31,13 +31,12 @@
import org.springframework.web.bind.annotation.*;
import javax.validation.Valid;
-import java.util.List;
/**
* @author Myrle Krantz
*/
@RestController
-@RequestMapping("/individuallending/products/{productidentifier}/cases/lossprovisionsteps")
+@RequestMapping("/individuallending/products/{productidentifier}/lossprovisionconfiguration")
public class LossProvisionStepRestController {
private final CommandGateway commandGateway;
private final ProductService productService;
@@ -60,12 +59,12 @@
produces = MediaType.APPLICATION_JSON_VALUE)
public @ResponseBody
ResponseEntity<Void>
- setLossProvisionSteps(
+ changeLossProvisionConfiguration(
@PathVariable("productidentifier") final String productIdentifier,
- @RequestBody @Valid List<LossProvisionStep> lossProvisionSteps) {
+ @RequestBody @Valid LossProvisionConfiguration lossProvisionConfiguration) {
checkProductExists(productIdentifier);
- commandGateway.process(new ChangeLossProvisionSteps(productIdentifier, lossProvisionSteps));
+ commandGateway.process(new ChangeLossProvisionSteps(productIdentifier, lossProvisionConfiguration));
return new ResponseEntity<>(HttpStatus.ACCEPTED);
}
@@ -77,12 +76,12 @@
produces = MediaType.APPLICATION_JSON_VALUE
)
public @ResponseBody
- List<LossProvisionStep>
- getAllLossProvisionSteps(
+ LossProvisionConfiguration
+ getLossProvisionConfiguration(
@PathVariable("productidentifier") final String productIdentifier) {
checkProductExists(productIdentifier);
- return lossProvisionStepService.findByProductIdentifier(productIdentifier);
+ return new LossProvisionConfiguration(lossProvisionStepService.findByProductIdentifier(productIdentifier));
}
private void checkProductExists(@PathVariable("productidentifier") String productIdentifier) {