Added the ability to reference customer documents from a loan.
diff --git a/api/src/main/java/io/mifos/individuallending/api/v1/client/CaseDocumentsManager.java b/api/src/main/java/io/mifos/individuallending/api/v1/client/CaseDocumentsManager.java
new file mode 100644
index 0000000..1eb9766
--- /dev/null
+++ b/api/src/main/java/io/mifos/individuallending/api/v1/client/CaseDocumentsManager.java
@@ -0,0 +1,52 @@
+/*
+ * 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.client;
+
+import io.mifos.core.api.util.CustomFeignClientsConfiguration;
+import io.mifos.individuallending.api.v1.domain.caseinstance.CaseCustomerDocuments;
+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;
+
+/**
+ * @author Myrle Krantz
+ */
+@SuppressWarnings("unused")
+@FeignClient(value = "portfolio-v1", path = "/portfolio/v1", configuration = CustomFeignClientsConfiguration.class)
+public interface CaseDocumentsManager {
+ @RequestMapping(
+ value = "/individuallending/products/{productidentifier}/cases/{caseidentifier}/documents",
+ method = RequestMethod.GET,
+ produces = MediaType.ALL_VALUE,
+ consumes = MediaType.APPLICATION_JSON_VALUE)
+ CaseCustomerDocuments getCaseDocuments(
+ @PathVariable("productidentifier") final String productIdentifier,
+ @PathVariable("caseidentifier") final String caseIdentifier);
+
+
+ @RequestMapping(
+ value = "/individuallending/products/{productidentifier}/cases/{caseidentifier}/documents",
+ method = RequestMethod.PUT,
+ produces = MediaType.APPLICATION_JSON_VALUE,
+ consumes = MediaType.APPLICATION_JSON_VALUE
+ )
+ void changeCaseDocuments(
+ @PathVariable("productidentifier") final String productIdentifier,
+ @PathVariable("caseidentifier") final String caseIdentifier,
+ final CaseCustomerDocuments caseInstance);
+}
\ No newline at end of file
diff --git a/api/src/main/java/io/mifos/individuallending/api/v1/domain/caseinstance/CaseCustomerDocuments.java b/api/src/main/java/io/mifos/individuallending/api/v1/domain/caseinstance/CaseCustomerDocuments.java
new file mode 100644
index 0000000..f09bf4e
--- /dev/null
+++ b/api/src/main/java/io/mifos/individuallending/api/v1/domain/caseinstance/CaseCustomerDocuments.java
@@ -0,0 +1,113 @@
+/*
+ * 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.caseinstance;
+
+import java.util.List;
+import java.util.Objects;
+
+/**
+ * @author Myrle Krantz
+ */
+public class CaseCustomerDocuments {
+ private List<Document> documents;
+
+ public static class Document {
+ private String customerId;
+ private String documentId;
+
+ public Document() {
+ }
+
+ public Document(String customerId, String documentId) {
+ this.customerId = customerId;
+ this.documentId = documentId;
+ }
+
+ public String getCustomerId() {
+ return customerId;
+ }
+
+ public void setCustomerId(String customerId) {
+ this.customerId = customerId;
+ }
+
+ public String getDocumentId() {
+ return documentId;
+ }
+
+ public void setDocumentId(String documentId) {
+ this.documentId = documentId;
+ }
+
+ @Override
+ public boolean equals(Object o) {
+ if (this == o) return true;
+ if (o == null || getClass() != o.getClass()) return false;
+ Document document = (Document) o;
+ return Objects.equals(customerId, document.customerId) &&
+ Objects.equals(documentId, document.documentId);
+ }
+
+ @Override
+ public int hashCode() {
+ return Objects.hash(customerId, documentId);
+ }
+
+ @Override
+ public String toString() {
+ return "Document{" +
+ "customerId='" + customerId + '\'' +
+ ", documentId='" + documentId + '\'' +
+ '}';
+ }
+ }
+
+ @SuppressWarnings("unused")
+ public CaseCustomerDocuments() {
+ }
+
+ public CaseCustomerDocuments(List<Document> documents) {
+ this.documents = documents;
+ }
+
+ public List<Document> getDocuments() {
+ return documents;
+ }
+
+ public void setDocuments(List<Document> documents) {
+ this.documents = documents;
+ }
+
+ @Override
+ public boolean equals(Object o) {
+ if (this == o) return true;
+ if (o == null || getClass() != o.getClass()) return false;
+ CaseCustomerDocuments that = (CaseCustomerDocuments) o;
+ return Objects.equals(documents, that.documents);
+ }
+
+ @Override
+ public int hashCode() {
+ return Objects.hash(documents);
+ }
+
+ @Override
+ public String toString() {
+ return "CaseCustomerDocuments{" +
+ "documents=" + documents +
+ '}';
+ }
+}
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 219a016..be28810 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,7 +22,9 @@
String DESTINATION = "portfolio-v1";
String SELECTOR_NAME = "action";
- String PUT_LOSS_PROVISION_STEPS = "put-loss-provision-steps";
+ String PUT_DOCUMENT = "put-individualloan-documents";
+ String PUT_LOSS_PROVISION_STEPS = "put-individualloan-loss-provision-steps";
+
String OPEN_INDIVIDUALLOAN_CASE = "open-individualloan-case";
String DENY_INDIVIDUALLOAN_CASE = "deny-individualloan-case";
String APPROVE_INDIVIDUALLOAN_CASE = "approve-individualloan-case";
@@ -36,7 +38,9 @@
String CLOSE_INDIVIDUALLOAN_CASE = "close-individualloan-case";
String RECOVER_INDIVIDUALLOAN_CASE = "recover-individualloan-case";
+ String SELECTOR_PUT_DOCUMENT = SELECTOR_NAME + " = '" + PUT_DOCUMENT + "'";
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 + "'";
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 75f8a7f..e65cf20 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
@@ -24,4 +24,5 @@
String PRODUCT_LOSS_PROVISIONING_MANAGEMENT = "portfolio__v1__products__lossprv";
String PRODUCT_MANAGEMENT = "portfolio__v1__products";
String CASE_MANAGEMENT = "portfolio__v1__case";
+ String CASE_DOCUMENT_MANAGEMENT = "portfolio__v1__case_documents";
}
diff --git a/component-test/src/main/java/io/mifos/portfolio/AbstractPortfolioTest.java b/component-test/src/main/java/io/mifos/portfolio/AbstractPortfolioTest.java
index 0c6b96c..5337030 100644
--- a/component-test/src/main/java/io/mifos/portfolio/AbstractPortfolioTest.java
+++ b/component-test/src/main/java/io/mifos/portfolio/AbstractPortfolioTest.java
@@ -23,6 +23,7 @@
import io.mifos.core.test.listener.EnableEventRecording;
import io.mifos.core.test.listener.EventRecorder;
import io.mifos.customer.api.v1.client.CustomerManager;
+import io.mifos.individuallending.api.v1.client.CaseDocumentsManager;
import io.mifos.individuallending.api.v1.client.IndividualLending;
import io.mifos.individuallending.api.v1.domain.product.AccountDesignators;
import io.mifos.individuallending.api.v1.domain.workflow.Action;
@@ -115,6 +116,10 @@
@Autowired
IndividualLending individualLending;
+ @SuppressWarnings("SpringAutowiredFieldsWarningInspection")
+ @Autowired
+ CaseDocumentsManager caseDocumentsManager;
+
@SuppressWarnings("unused")
@MockBean
RhythmAdapter rhythmAdapter;
diff --git a/component-test/src/main/java/io/mifos/portfolio/TestCaseDocuments.java b/component-test/src/main/java/io/mifos/portfolio/TestCaseDocuments.java
new file mode 100644
index 0000000..ce14b75
--- /dev/null
+++ b/component-test/src/main/java/io/mifos/portfolio/TestCaseDocuments.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.portfolio;
+
+import io.mifos.individuallending.api.v1.domain.caseinstance.CaseCustomerDocuments;
+import io.mifos.individuallending.api.v1.events.IndividualLoanEventConstants;
+import io.mifos.portfolio.api.v1.domain.Case;
+import io.mifos.portfolio.api.v1.domain.Product;
+import io.mifos.portfolio.api.v1.events.CaseEvent;
+import org.junit.Assert;
+import org.junit.Test;
+
+import java.util.Arrays;
+
+/**
+ * @author Myrle Krantz
+ */
+public class TestCaseDocuments extends AbstractPortfolioTest {
+ @Test
+ public void test() throws InterruptedException {
+ //Prepare
+ final Product product = createAndEnableProduct();
+ final Case customerCase = createCase(product.getIdentifier());
+
+
+ //Check that initial state is empty.
+ final CaseCustomerDocuments caseDocuments = caseDocumentsManager.getCaseDocuments(
+ product.getIdentifier(), customerCase.getIdentifier());
+
+ Assert.assertEquals(0, caseDocuments.getDocuments().size());
+
+
+ //Insert some documents.
+ final CaseCustomerDocuments.Document studentLoanDocument
+ = new CaseCustomerDocuments.Document(Fixture.CUSTOMER_IDENTIFIER, "student_loan_papers");
+ final CaseCustomerDocuments.Document houseTitle
+ = new CaseCustomerDocuments.Document(Fixture.CUSTOMER_IDENTIFIER, "house_title");
+ final CaseCustomerDocuments.Document workContract
+ = new CaseCustomerDocuments.Document(Fixture.CUSTOMER_IDENTIFIER, "work_contract");
+
+ caseDocuments.setDocuments(Arrays.asList(studentLoanDocument, houseTitle, workContract));
+
+ caseDocumentsManager.changeCaseDocuments(product.getIdentifier(), customerCase.getIdentifier(), caseDocuments);
+ Assert.assertTrue(this.eventRecorder.wait(IndividualLoanEventConstants.PUT_DOCUMENT,
+ new CaseEvent(product.getIdentifier(), customerCase.getIdentifier())));
+
+
+ //Check that they are as set.
+ {
+ final CaseCustomerDocuments changedCaseDocuments = caseDocumentsManager.getCaseDocuments(product.getIdentifier(), customerCase.getIdentifier());
+ Assert.assertEquals(caseDocuments, changedCaseDocuments);
+ }
+
+ //Re-order the documents
+ caseDocuments.setDocuments(Arrays.asList(houseTitle, studentLoanDocument, workContract));
+
+ caseDocumentsManager.changeCaseDocuments(product.getIdentifier(), customerCase.getIdentifier(), caseDocuments);
+ Assert.assertTrue(this.eventRecorder.wait(IndividualLoanEventConstants.PUT_DOCUMENT,
+ new CaseEvent(product.getIdentifier(), customerCase.getIdentifier())));
+
+ //Check that they are as set.
+ {
+ Thread.sleep(1000);
+ final CaseCustomerDocuments changedCaseDocuments = caseDocumentsManager.getCaseDocuments(product.getIdentifier(), customerCase.getIdentifier());
+ Assert.assertEquals(caseDocuments, changedCaseDocuments);
+ }
+
+ //TODO: mock customer and check that only existing and completed documents are referenced.
+ }
+}
\ 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 0be9417..a189642 100644
--- a/component-test/src/main/java/io/mifos/portfolio/TestSuite.java
+++ b/component-test/src/main/java/io/mifos/portfolio/TestSuite.java
@@ -33,7 +33,8 @@
TestProducts.class,
TestTaskDefinitions.class,
TestTaskInstances.class,
- TestLossProvisionSteps.class
+ TestLossProvisionSteps.class,
+ TestCaseDocuments.class
})
public class TestSuite extends SuiteTestEnvironment {
}
diff --git a/component-test/src/main/java/io/mifos/portfolio/listener/CaseDocumentsListener.java b/component-test/src/main/java/io/mifos/portfolio/listener/CaseDocumentsListener.java
new file mode 100644
index 0000000..a994b2a
--- /dev/null
+++ b/component-test/src/main/java/io/mifos/portfolio/listener/CaseDocumentsListener.java
@@ -0,0 +1,34 @@
+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 io.mifos.portfolio.api.v1.events.CaseEvent;
+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 CaseDocumentsListener {
+ private final EventRecorder eventRecorder;
+
+ @Autowired
+ public CaseDocumentsListener(final EventRecorder eventRecorder) {
+ this.eventRecorder = eventRecorder;
+ }
+
+ @JmsListener(
+ subscription = IndividualLoanEventConstants.DESTINATION,
+ destination = IndividualLoanEventConstants.DESTINATION,
+ selector = IndividualLoanEventConstants.SELECTOR_PUT_DOCUMENT
+ )
+ public void onCreateCase(@Header(TenantHeaderFilter.TENANT_HEADER) final String tenant,
+ final String payload) {
+ this.eventRecorder.event(tenant, IndividualLoanEventConstants.PUT_DOCUMENT, payload, CaseEvent.class);
+ }
+}
diff --git a/service/src/main/java/io/mifos/individuallending/internal/command/ChangeCaseDocuments.java b/service/src/main/java/io/mifos/individuallending/internal/command/ChangeCaseDocuments.java
new file mode 100644
index 0000000..2d6478b
--- /dev/null
+++ b/service/src/main/java/io/mifos/individuallending/internal/command/ChangeCaseDocuments.java
@@ -0,0 +1,53 @@
+/*
+ * 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;
+
+import io.mifos.individuallending.api.v1.domain.caseinstance.CaseCustomerDocuments;
+
+/**
+ * @author Myrle Krantz
+ */
+public class ChangeCaseDocuments {
+ private final String productIdentifier;
+ private final String caseIdentifier;
+ private final CaseCustomerDocuments instance;
+
+ public ChangeCaseDocuments(String productIdentifier, String caseIdentifier, CaseCustomerDocuments instance) {
+ this.productIdentifier = productIdentifier;
+ this.caseIdentifier = caseIdentifier;
+ this.instance = instance;
+ }
+
+ public String getProductIdentifier() {
+ return productIdentifier;
+ }
+
+ public String getCaseIdentifier() {
+ return caseIdentifier;
+ }
+
+ public CaseCustomerDocuments getInstance() {
+ return instance;
+ }
+
+ @Override
+ public String toString() {
+ return "ChangeCaseDocuments{" +
+ "productIdentifier='" + productIdentifier + '\'' +
+ ", caseIdentifier='" + caseIdentifier + '\'' +
+ '}';
+ }
+}
diff --git a/service/src/main/java/io/mifos/individuallending/internal/command/handler/CaseDocumentsCommandHandler.java b/service/src/main/java/io/mifos/individuallending/internal/command/handler/CaseDocumentsCommandHandler.java
new file mode 100644
index 0000000..4a9e3d9
--- /dev/null
+++ b/service/src/main/java/io/mifos/individuallending/internal/command/handler/CaseDocumentsCommandHandler.java
@@ -0,0 +1,85 @@
+/*
+ * 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.domain.caseinstance.CaseCustomerDocuments;
+import io.mifos.individuallending.api.v1.events.IndividualLoanEventConstants;
+import io.mifos.individuallending.internal.command.ChangeCaseDocuments;
+import io.mifos.individuallending.internal.mapper.CaseCustomerDocumentsMapper;
+import io.mifos.individuallending.internal.repository.CaseCustomerDocumentEntity;
+import io.mifos.individuallending.internal.repository.CaseCustomerDocumentsRepository;
+import io.mifos.individuallending.internal.repository.CaseParametersEntity;
+import io.mifos.individuallending.internal.repository.CaseParametersRepository;
+import io.mifos.portfolio.api.v1.events.CaseEvent;
+import io.mifos.portfolio.service.internal.repository.CaseRepository;
+import org.springframework.transaction.annotation.Transactional;
+
+import java.util.List;
+import java.util.Map;
+import java.util.Set;
+import java.util.stream.Collectors;
+
+/**
+ * @author Myrle Krantz
+ */
+@Aggregate
+public class CaseDocumentsCommandHandler {
+ final private CaseRepository caseRepository;
+ final private CaseParametersRepository caseParametersRepository;
+ final private CaseCustomerDocumentsRepository caseCustomerDocumentsRepository;
+
+ public CaseDocumentsCommandHandler(
+ final CaseRepository caseRepository,
+ final CaseParametersRepository caseParametersRepository,
+ final CaseCustomerDocumentsRepository caseCustomerDocumentsRepository) {
+ this.caseRepository = caseRepository;
+ this.caseParametersRepository = caseParametersRepository;
+ this.caseCustomerDocumentsRepository = caseCustomerDocumentsRepository;
+ }
+
+ @Transactional
+ @CommandHandler(logStart = CommandLogLevel.INFO, logFinish = CommandLogLevel.INFO)
+ @EventEmitter(selectorName = IndividualLoanEventConstants.SELECTOR_NAME, selectorValue = IndividualLoanEventConstants.PUT_DOCUMENT)
+ public CaseEvent process(final ChangeCaseDocuments command) {
+ final CaseParametersEntity caseparametersEntity =
+ caseRepository.findByProductIdentifierAndIdentifier(command.getProductIdentifier(), command.getCaseIdentifier())
+ .flatMap(x -> caseParametersRepository.findByCaseId(x.getId()))
+ .orElseThrow(() -> ServiceException.notFound("Case ''{0}.{1}'' not found", command.getProductIdentifier(), command.getCaseIdentifier()));
+
+ final Map<CaseCustomerDocuments.Document, CaseCustomerDocumentEntity> existingCaseCustomerDocuments
+ = caseCustomerDocumentsRepository.findByCaseParametersId(caseparametersEntity.getId())
+ .collect(Collectors.toMap(CaseCustomerDocumentsMapper::map, x -> x));
+
+ final List<CaseCustomerDocumentEntity> newCaseCustomerDocuments = CaseCustomerDocumentsMapper.map(
+ command.getInstance().getDocuments(),
+ caseparametersEntity,
+ existingCaseCustomerDocuments);
+
+ final Set<CaseCustomerDocumentEntity> toDelete = caseCustomerDocumentsRepository.findByCaseParametersId(caseparametersEntity.getId())
+ .filter(x -> !command.getInstance().getDocuments().contains(CaseCustomerDocumentsMapper.map(x)))
+ .collect(Collectors.toSet());
+
+ caseCustomerDocumentsRepository.delete(toDelete);
+ caseCustomerDocumentsRepository.save(newCaseCustomerDocuments);
+
+ return new CaseEvent(command.getProductIdentifier(), command.getCaseIdentifier());
+ }
+}
diff --git a/service/src/main/java/io/mifos/individuallending/internal/mapper/CaseCustomerDocumentsMapper.java b/service/src/main/java/io/mifos/individuallending/internal/mapper/CaseCustomerDocumentsMapper.java
new file mode 100644
index 0000000..c51c1ea
--- /dev/null
+++ b/service/src/main/java/io/mifos/individuallending/internal/mapper/CaseCustomerDocumentsMapper.java
@@ -0,0 +1,69 @@
+/*
+ * 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.mapper;
+
+import io.mifos.individuallending.api.v1.domain.caseinstance.CaseCustomerDocuments;
+import io.mifos.individuallending.internal.repository.CaseCustomerDocumentEntity;
+import io.mifos.individuallending.internal.repository.CaseParametersEntity;
+
+import java.util.ArrayList;
+import java.util.List;
+import java.util.Map;
+
+/**
+ * @author Myrle Krantz
+ */
+public final class CaseCustomerDocumentsMapper {
+ private CaseCustomerDocumentsMapper() {}
+
+ public static CaseCustomerDocuments.Document map(
+ final CaseCustomerDocumentEntity caseCustomerDocumentEntity) {
+ final CaseCustomerDocuments.Document ret = new CaseCustomerDocuments.Document();
+ ret.setCustomerId(caseCustomerDocumentEntity.getCustomerIdentifier());
+ ret.setDocumentId(caseCustomerDocumentEntity.getDocumentIdentifier());
+ return ret;
+ }
+
+ private static CaseCustomerDocumentEntity map(
+ final CaseCustomerDocuments.Document caseCustomerDocument,
+ final Long caseParametersId,
+ final Integer order) {
+ final CaseCustomerDocumentEntity ret = new CaseCustomerDocumentEntity();
+ ret.setCustomerIdentifier(caseCustomerDocument.getCustomerId());
+ ret.setDocumentIdentifier(caseCustomerDocument.getDocumentId());
+ ret.setCaseParametersId(caseParametersId);
+ ret.setOrder(order);
+ return ret;
+ }
+
+
+ public static List<CaseCustomerDocumentEntity> map(
+ final List<CaseCustomerDocuments.Document> documents,
+ final CaseParametersEntity caseparametersEntity,
+ final Map<CaseCustomerDocuments.Document, CaseCustomerDocumentEntity> existingCaseCustomerDocuments) {
+ final List<CaseCustomerDocumentEntity> ret = new ArrayList<>();
+ for (int i = 0; i < documents.size(); i++) {
+ CaseCustomerDocumentEntity toAdd = map(documents.get(i), caseparametersEntity.getId(), i);
+ final CaseCustomerDocumentEntity existing = existingCaseCustomerDocuments.get(documents.get(i));
+ if (existing != null) {
+ existing.setOrder(toAdd.getOrder());
+ toAdd = existing;
+ }
+ ret.add(toAdd);
+ }
+ return ret;
+ }
+}
diff --git a/service/src/main/java/io/mifos/individuallending/internal/mapper/LossProvisionStepMapper.java b/service/src/main/java/io/mifos/individuallending/internal/mapper/LossProvisionStepMapper.java
index 1b4bbbe..0f09fd1 100644
--- a/service/src/main/java/io/mifos/individuallending/internal/mapper/LossProvisionStepMapper.java
+++ b/service/src/main/java/io/mifos/individuallending/internal/mapper/LossProvisionStepMapper.java
@@ -20,6 +20,9 @@
import java.math.BigDecimal;
+/**
+ * @author Myrle Krantz
+ */
public interface LossProvisionStepMapper {
static LossProvisionStepEntity map(
final Long productId,
diff --git a/service/src/main/java/io/mifos/individuallending/internal/repository/CaseCustomerDocumentEntity.java b/service/src/main/java/io/mifos/individuallending/internal/repository/CaseCustomerDocumentEntity.java
new file mode 100644
index 0000000..e1abfaa
--- /dev/null
+++ b/service/src/main/java/io/mifos/individuallending/internal/repository/CaseCustomerDocumentEntity.java
@@ -0,0 +1,100 @@
+/*
+ * 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.repository;
+
+import javax.persistence.*;
+import java.util.Objects;
+
+/**
+ * @author Myrle Krantz
+ */
+@SuppressWarnings("unused")
+@Entity
+@Table(name = "bastet_il_c_docs")
+public class CaseCustomerDocumentEntity {
+ @Id
+ @GeneratedValue(strategy = GenerationType.IDENTITY)
+ @Column(name = "id")
+ private Long id;
+
+ @Column(name = "case_id")
+ private Long caseParametersId;
+
+ @Column(name = "customer_identifier")
+ private String customerIdentifier;
+
+ @Column(name = "document_identifier")
+ private String documentIdentifier;
+
+ @Column(name = "list_order")
+ private Integer order;
+
+ public Long getId() {
+ return id;
+ }
+
+ public void setId(Long id) {
+ this.id = id;
+ }
+
+ public Long getCaseParametersId() {
+ return caseParametersId;
+ }
+
+ public void setCaseParametersId(Long caseParametersId) {
+ this.caseParametersId = caseParametersId;
+ }
+
+ public String getCustomerIdentifier() {
+ return customerIdentifier;
+ }
+
+ public void setCustomerIdentifier(String customerIdentifier) {
+ this.customerIdentifier = customerIdentifier;
+ }
+
+ public String getDocumentIdentifier() {
+ return documentIdentifier;
+ }
+
+ public void setDocumentIdentifier(String documentIdentifier) {
+ this.documentIdentifier = documentIdentifier;
+ }
+
+ public Integer getOrder() {
+ return order;
+ }
+
+ public void setOrder(Integer order) {
+ this.order = order;
+ }
+
+ @Override
+ public boolean equals(Object o) {
+ if (this == o) return true;
+ if (o == null || getClass() != o.getClass()) return false;
+ CaseCustomerDocumentEntity that = (CaseCustomerDocumentEntity) o;
+ return Objects.equals(caseParametersId, that.caseParametersId) &&
+ Objects.equals(customerIdentifier, that.customerIdentifier) &&
+ Objects.equals(documentIdentifier, that.documentIdentifier) &&
+ Objects.equals(order, that.order);
+ }
+
+ @Override
+ public int hashCode() {
+ return Objects.hash(caseParametersId, customerIdentifier, documentIdentifier, order);
+ }
+}
\ No newline at end of file
diff --git a/service/src/main/java/io/mifos/individuallending/internal/repository/CaseCustomerDocumentsRepository.java b/service/src/main/java/io/mifos/individuallending/internal/repository/CaseCustomerDocumentsRepository.java
new file mode 100644
index 0000000..308a1b0
--- /dev/null
+++ b/service/src/main/java/io/mifos/individuallending/internal/repository/CaseCustomerDocumentsRepository.java
@@ -0,0 +1,31 @@
+/*
+ * 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.repository;
+
+import org.springframework.data.jpa.repository.JpaRepository;
+import org.springframework.stereotype.Component;
+import org.springframework.stereotype.Repository;
+
+import java.util.stream.Stream;
+
+/**
+ * @author Myrle Krantz
+ */
+@Component
+@Repository
+public interface CaseCustomerDocumentsRepository extends JpaRepository<CaseCustomerDocumentEntity, Long> {
+ Stream<CaseCustomerDocumentEntity> findByCaseParametersId(Long caseId);
+}
diff --git a/service/src/main/java/io/mifos/individuallending/internal/service/CaseDocumentsService.java b/service/src/main/java/io/mifos/individuallending/internal/service/CaseDocumentsService.java
new file mode 100644
index 0000000..19ccd96
--- /dev/null
+++ b/service/src/main/java/io/mifos/individuallending/internal/service/CaseDocumentsService.java
@@ -0,0 +1,63 @@
+/*
+ * 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.service;
+
+import io.mifos.core.lang.ServiceException;
+import io.mifos.individuallending.api.v1.domain.caseinstance.CaseCustomerDocuments;
+import io.mifos.individuallending.internal.mapper.CaseCustomerDocumentsMapper;
+import io.mifos.individuallending.internal.repository.CaseCustomerDocumentEntity;
+import io.mifos.individuallending.internal.repository.CaseCustomerDocumentsRepository;
+import io.mifos.individuallending.internal.repository.CaseParametersEntity;
+import io.mifos.individuallending.internal.repository.CaseParametersRepository;
+import io.mifos.portfolio.service.internal.repository.CaseRepository;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.stereotype.Service;
+
+import java.util.Comparator;
+import java.util.stream.Stream;
+
+/**
+ * @author Myrle Krantz
+ */
+@Service
+public class CaseDocumentsService {
+ final private CaseCustomerDocumentsRepository caseCustomerDocumentsRepository;
+ final private CaseRepository caseRepository;
+ final private CaseParametersRepository caseParametersRepository;
+
+ @Autowired
+ public CaseDocumentsService(
+ final CaseCustomerDocumentsRepository caseCustomerDocumentsRepository,
+ final CaseRepository caseRepository,
+ final CaseParametersRepository caseParametersRepository) {
+ this.caseCustomerDocumentsRepository = caseCustomerDocumentsRepository;
+ this.caseRepository = caseRepository;
+ this.caseParametersRepository = caseParametersRepository;
+ }
+
+ public Stream<CaseCustomerDocuments.Document> find(
+ final String productIdentifier,
+ final String caseIdentifier) {
+ final CaseParametersEntity caseparametersEntity =
+ caseRepository.findByProductIdentifierAndIdentifier(productIdentifier, caseIdentifier)
+ .flatMap(x -> caseParametersRepository.findByCaseId(x.getId()))
+ .orElseThrow(() -> ServiceException.notFound("Case ''{0}.{1}'' not found", productIdentifier, caseIdentifier));
+
+ return caseCustomerDocumentsRepository.findByCaseParametersId(caseparametersEntity.getId())
+ .sorted(Comparator.comparing(CaseCustomerDocumentEntity::getOrder))
+ .map(CaseCustomerDocumentsMapper::map);
+ }
+}
\ No newline at end of file
diff --git a/service/src/main/java/io/mifos/individuallending/rest/CaseDocumentsRestController.java b/service/src/main/java/io/mifos/individuallending/rest/CaseDocumentsRestController.java
new file mode 100644
index 0000000..e76e291
--- /dev/null
+++ b/service/src/main/java/io/mifos/individuallending/rest/CaseDocumentsRestController.java
@@ -0,0 +1,96 @@
+/*
+ * 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.rest;
+
+import io.mifos.anubis.annotation.AcceptedTokenType;
+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.caseinstance.CaseCustomerDocuments;
+import io.mifos.individuallending.internal.command.ChangeCaseDocuments;
+import io.mifos.individuallending.internal.service.CaseDocumentsService;
+import io.mifos.portfolio.api.v1.PermittableGroupIds;
+import io.mifos.portfolio.api.v1.domain.Case;
+import io.mifos.portfolio.service.internal.service.CaseService;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.http.MediaType;
+import org.springframework.http.ResponseEntity;
+import org.springframework.web.bind.annotation.*;
+
+import java.util.List;
+import java.util.stream.Collectors;
+
+@RestController
+@RequestMapping("/individuallending/products/{productidentifier}/cases/{caseidentifier}/documents")
+public class CaseDocumentsRestController {
+ private final CommandGateway commandGateway;
+ private final CaseService caseService;
+ private final CaseDocumentsService caseDocumentsService;
+
+ @Autowired
+ public CaseDocumentsRestController(
+ final CommandGateway commandGateway,
+ final CaseService caseService,
+ final CaseDocumentsService caseDocumentsService) {
+ this.commandGateway = commandGateway;
+ this.caseService = caseService;
+ this.caseDocumentsService = caseDocumentsService;
+ }
+
+ @Permittable(value = AcceptedTokenType.TENANT, groupId = PermittableGroupIds.CASE_DOCUMENT_MANAGEMENT)
+ @RequestMapping(
+ method = RequestMethod.GET,
+ consumes = MediaType.ALL_VALUE,
+ produces = MediaType.APPLICATION_JSON_VALUE)
+ public @ResponseBody
+ CaseCustomerDocuments
+ getCaseDocuments(
+ @PathVariable("productidentifier") final String productIdentifier,
+ @PathVariable("caseidentifier") final String caseIdentifier) {
+ throwIfCaseDoesntExist(productIdentifier, caseIdentifier);
+
+ final List<CaseCustomerDocuments.Document> ret = caseDocumentsService.find(productIdentifier, caseIdentifier)
+ .collect(Collectors.toList());
+
+ return new CaseCustomerDocuments(ret);
+ }
+
+
+ @Permittable(value = AcceptedTokenType.TENANT, groupId = PermittableGroupIds.CASE_DOCUMENT_MANAGEMENT)
+ @RequestMapping(
+ method = RequestMethod.PUT,
+ consumes = MediaType.APPLICATION_JSON_VALUE,
+ produces = MediaType.APPLICATION_JSON_VALUE
+ )
+ public @ResponseBody
+ ResponseEntity<Void>
+ changeCaseDocuments(
+ @PathVariable("productidentifier") final String productIdentifier,
+ @PathVariable("caseidentifier") final String caseIdentifier,
+ final @RequestBody CaseCustomerDocuments instance) {
+ throwIfCaseDoesntExist(productIdentifier, caseIdentifier);
+
+ commandGateway.process(new ChangeCaseDocuments(productIdentifier, caseIdentifier, instance));
+
+ return ResponseEntity.accepted().build();
+ }
+
+ private void throwIfCaseDoesntExist(final String productIdentifier, final String caseIdentifier) throws ServiceException {
+ //noinspection unused
+ Case x = caseService.findByIdentifier(productIdentifier, caseIdentifier)
+ .orElseThrow(() -> ServiceException.notFound("Case ''{0}.{1}'' does not exist.", productIdentifier, caseIdentifier));
+ }
+}
diff --git a/service/src/main/java/io/mifos/portfolio/service/internal/repository/CaseRepository.java b/service/src/main/java/io/mifos/portfolio/service/internal/repository/CaseRepository.java
index 2d439f6..98865e8 100644
--- a/service/src/main/java/io/mifos/portfolio/service/internal/repository/CaseRepository.java
+++ b/service/src/main/java/io/mifos/portfolio/service/internal/repository/CaseRepository.java
@@ -39,5 +39,4 @@
boolean existsByProductIdentifier(@Param("productIdentifier") String productIdentifier);
Stream<CaseEntity> findByCurrentStateIn(Collection<String> currentStates);
-
}
diff --git a/service/src/main/resources/db/migrations/mariadb/V11__case_documents.sql b/service/src/main/resources/db/migrations/mariadb/V11__case_documents.sql
new file mode 100644
index 0000000..de79dd0
--- /dev/null
+++ b/service/src/main/resources/db/migrations/mariadb/V11__case_documents.sql
@@ -0,0 +1,27 @@
+--
+-- 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.
+--
+
+CREATE TABLE bastet_il_c_docs (
+ id BIGINT NOT NULL AUTO_INCREMENT,
+ case_id BIGINT NOT NULL,
+ customer_identifier VARCHAR(32) NOT NULL,
+ document_identifier VARCHAR(32) NOT NULL,
+ list_order INT NOT NULL,
+
+ CONSTRAINT bastet_il_c_docs_pk PRIMARY KEY (id),
+ CONSTRAINT bastet_il_c_docs_uq UNIQUE (case_id, customer_identifier, document_identifier),
+ CONSTRAINT bastet_il_c_docs_fk FOREIGN KEY (case_id) REFERENCES bastet_il_cases (id)
+);
\ No newline at end of file