You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@fineract.apache.org by my...@apache.org on 2018/01/22 15:47:05 UTC
[fineract-cn-customer] 04/46: Add identification card upload
This is an automated email from the ASF dual-hosted git repository.
myrle pushed a commit to branch develop
in repository https://gitbox.apache.org/repos/asf/fineract-cn-customer.git
commit 498c48ec0336bfe0ba0c17b26d042876cb31bf34
Author: Mark <ma...@gmail.com>
AuthorDate: Wed Jul 19 18:24:20 2017 +0200
Add identification card upload
---
.../customer/api/v1/CustomerEventConstants.java | 6 +
.../customer/api/v1/client/CustomerManager.java | 83 +++++--
.../api/v1/client/ScanAlreadyExistsException.java | 19 +-
.../api/v1/client/ScanNotFoundException.java | 19 +-
.../api/v1/client/ScanValidationException.java | 17 +-
.../api/v1/domain/IdentificationCardScan.java | 38 ++--
.../io/mifos/customer/api/v1/events/ScanEvent.java | 52 +++++
.../main/java/io/mifos/customer/TestCustomer.java | 105 +--------
.../io/mifos/customer/TestIdentificationCards.java | 252 +++++++++++++++++++++
.../src/main/java/io/mifos/customer/TestSuite.java | 1 +
.../customer/listener/CustomerEventListener.java | 19 ++
.../java/io/mifos/customer/util/ScanGenerator.java | 39 ++++
.../CreateIdentificationCardScanCommand.java | 52 +++++
.../DeleteIdentificationCardScanCommand.java | 32 +--
.../command/handler/CustomerAggregate.java | 64 ++++++
.../mapper/IdentificationCardScanMapper.java | 44 ++++
.../repository/IdentificationCardScanEntity.java | 128 +++++++++++
.../IdentificationCardScanRepository.java | 35 +++
.../service/internal/service/CustomerService.java | 45 +++-
.../rest/controller/CustomerRestController.java | 151 +++++++++++-
.../mariadb/V4__identification_card_scans.sql | 30 +++
21 files changed, 1016 insertions(+), 215 deletions(-)
diff --git a/api/src/main/java/io/mifos/customer/api/v1/CustomerEventConstants.java b/api/src/main/java/io/mifos/customer/api/v1/CustomerEventConstants.java
index 97a15c8..ab5a9a3 100644
--- a/api/src/main/java/io/mifos/customer/api/v1/CustomerEventConstants.java
+++ b/api/src/main/java/io/mifos/customer/api/v1/CustomerEventConstants.java
@@ -32,6 +32,9 @@ public interface CustomerEventConstants {
String PUT_IDENTIFICATION_CARD = "put-identification-card";
String DELETE_IDENTIFICATION_CARD = "delete-identification-card";
+ String POST_IDENTIFICATION_CARD_SCAN = "post-identification-card-scan";
+ String DELETE_IDENTIFICATION_CARD_SCAN = "delete-identification-card-scan";
+
String ACTIVATE_CUSTOMER = "activate-customer";
String LOCK_CUSTOMER = "lock-customer";
String UNLOCK_CUSTOMER = "unlock-customer";
@@ -55,6 +58,9 @@ public interface CustomerEventConstants {
String SELECTOR_PUT_IDENTIFICATION_CARD = SELECTOR_NAME + " = '" + PUT_IDENTIFICATION_CARD + "'";
String SELECTOR_DELETE_IDENTIFICATION_CARD = SELECTOR_NAME + " = '" + DELETE_IDENTIFICATION_CARD + "'";
+ String SELECTOR_POST_IDENTIFICATION_CARD_SCAN = SELECTOR_NAME + " = '" + POST_IDENTIFICATION_CARD_SCAN + "'";
+ String SELECTOR_DELETE_IDENTIFICATION_CARD_SCAN = SELECTOR_NAME + " = '" + DELETE_IDENTIFICATION_CARD_SCAN + "'";
+
String SELECTOR_ACTIVATE_CUSTOMER = SELECTOR_NAME + " = '" + ACTIVATE_CUSTOMER + "'";
String SELECTOR_LOCK_CUSTOMER = SELECTOR_NAME + " = '" + LOCK_CUSTOMER + "'";
String SELECTOR_UNLOCK_CUSTOMER = SELECTOR_NAME + " = '" + UNLOCK_CUSTOMER + "'";
diff --git a/api/src/main/java/io/mifos/customer/api/v1/client/CustomerManager.java b/api/src/main/java/io/mifos/customer/api/v1/client/CustomerManager.java
index bac6bcb..597a3aa 100644
--- a/api/src/main/java/io/mifos/customer/api/v1/client/CustomerManager.java
+++ b/api/src/main/java/io/mifos/customer/api/v1/client/CustomerManager.java
@@ -17,26 +17,16 @@ package io.mifos.customer.api.v1.client;
import io.mifos.core.api.annotation.ThrowsException;
import io.mifos.core.api.annotation.ThrowsExceptions;
-import io.mifos.core.api.util.CustomFeignClientsConfiguration;
+import io.mifos.core.lang.validation.constraints.ValidIdentifier;
import io.mifos.customer.api.v1.config.CustomerFeignClientConfig;
-import io.mifos.customer.api.v1.domain.Address;
-import io.mifos.customer.api.v1.domain.Command;
-import io.mifos.customer.api.v1.domain.ContactDetail;
-import io.mifos.customer.api.v1.domain.IdentificationCard;
-import io.mifos.customer.api.v1.domain.Customer;
-import io.mifos.customer.api.v1.domain.CustomerPage;
-import io.mifos.customer.api.v1.domain.ProcessStep;
-import io.mifos.customer.api.v1.domain.TaskDefinition;
+import io.mifos.customer.api.v1.domain.*;
import org.springframework.cloud.netflix.feign.FeignClient;
import org.springframework.http.HttpStatus;
import org.springframework.http.MediaType;
-import org.springframework.web.bind.annotation.PathVariable;
-import org.springframework.web.bind.annotation.RequestBody;
-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 org.springframework.web.multipart.MultipartFile;
+import javax.validation.constraints.Size;
import java.util.List;
@SuppressWarnings("unused")
@@ -233,6 +223,71 @@ public interface CustomerManager {
@PathVariable("number") final String number);
@RequestMapping(
+ value = "/customers/{identifier}/identifications/{number}/scans",
+ method = RequestMethod.GET,
+ produces = MediaType.ALL_VALUE,
+ consumes = MediaType.APPLICATION_JSON_VALUE
+ )
+ @ThrowsExceptions({
+ @ThrowsException(status = HttpStatus.NOT_FOUND, exception = IdentificationCardNotFoundException.class)
+ })
+ List<IdentificationCardScan> fetchIdentificationCardScans(@PathVariable("identifier") final String identifier,
+ @PathVariable("number") final String number);
+
+ @RequestMapping(
+ value = "/customers/{identifier}/identifications/{number}/scans/{scanIdentifier}",
+ method = RequestMethod.GET,
+ produces = MediaType.ALL_VALUE,
+ consumes = MediaType.APPLICATION_JSON_VALUE
+ )
+ @ThrowsExceptions({
+ @ThrowsException(status = HttpStatus.NOT_FOUND, exception = ScanNotFoundException.class)
+ })
+ IdentificationCardScan findIdentificationCardScan(@PathVariable("identifier") final String identifier,
+ @PathVariable("number") final String number,
+ @PathVariable("scanIdentifier") final String scanIdentifier);
+
+ @RequestMapping(
+ value = "/customers/{identifier}/identifications/{number}/scans/{scanIdentifier}/image",
+ method = RequestMethod.GET,
+ produces = MediaType.ALL_VALUE,
+ consumes = MediaType.APPLICATION_JSON_VALUE
+ )
+ @ThrowsExceptions({
+ @ThrowsException(status = HttpStatus.NOT_FOUND, exception = ScanNotFoundException.class)
+ })
+ byte[] fetchIdentificationCardScanImage(@PathVariable("identifier") final String identifier,
+ @PathVariable("number") final String number,
+ @PathVariable("scanIdentifier") final String scanIdentifier);
+
+ @RequestMapping(
+ value = "/customers/{identifier}/identifications/{number}/scans",
+ method = RequestMethod.POST,
+ produces = MediaType.ALL_VALUE,
+ consumes = MediaType.MULTIPART_FORM_DATA_VALUE
+ )
+ @ThrowsExceptions({
+ @ThrowsException(status = HttpStatus.NOT_FOUND, exception = IdentificationCardNotFoundException.class),
+ @ThrowsException(status = HttpStatus.BAD_REQUEST, exception = ScanValidationException.class),
+ @ThrowsException(status = HttpStatus.CONFLICT, exception = ScanAlreadyExistsException.class)
+ })
+ void postIdentificationCardScan(@PathVariable("identifier") final String identifier,
+ @PathVariable("number") final String number,
+ @RequestParam("scanIdentifier") @ValidIdentifier final String scanIdentifier,
+ @RequestParam("description") @Size(max = 4096) final String description,
+ @RequestBody final MultipartFile image);
+
+ @RequestMapping(
+ value = "/customers/{identifier}/identifications/{number}/scans/{scanIdentifier}",
+ method = RequestMethod.DELETE,
+ produces = MediaType.ALL_VALUE,
+ consumes = MediaType.APPLICATION_JSON_VALUE
+ )
+ void deleteScan(@PathVariable("identifier") final String identifier,
+ @PathVariable("number") final String number,
+ @PathVariable("scanIdentifier") final String scanIdentifier);
+
+ @RequestMapping(
value = "/customers/{identifier}/portrait",
method = RequestMethod.GET,
produces = MediaType.ALL_VALUE
diff --git a/component-test/src/main/java/io/mifos/customer/TestSuite.java b/api/src/main/java/io/mifos/customer/api/v1/client/ScanAlreadyExistsException.java
similarity index 60%
copy from component-test/src/main/java/io/mifos/customer/TestSuite.java
copy to api/src/main/java/io/mifos/customer/api/v1/client/ScanAlreadyExistsException.java
index 2e12b10..45ef5a1 100644
--- a/component-test/src/main/java/io/mifos/customer/TestSuite.java
+++ b/api/src/main/java/io/mifos/customer/api/v1/client/ScanAlreadyExistsException.java
@@ -1,5 +1,5 @@
/*
- * Copyright 2017 The Mifos Initiative.
+ * Copyright 2016 The Mifos Initiative.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@@ -13,20 +13,7 @@
* See the License for the specific language governing permissions and
* limitations under the License.
*/
-package io.mifos.customer;
+package io.mifos.customer.api.v1.client;
-import org.junit.runner.RunWith;
-import org.junit.runners.Suite;
-
-/**
- * @author Myrle Krantz
- */
-@RunWith(Suite.class)
-@Suite.SuiteClasses({
- TestCustomer.class,
- TestInfrastructure.class,
- TestTaskDefinition.class,
- TestTaskInstance.class,
-})
-public class TestSuite extends SuiteTestEnvironment {
+public final class ScanAlreadyExistsException extends RuntimeException {
}
diff --git a/component-test/src/main/java/io/mifos/customer/TestSuite.java b/api/src/main/java/io/mifos/customer/api/v1/client/ScanNotFoundException.java
similarity index 60%
copy from component-test/src/main/java/io/mifos/customer/TestSuite.java
copy to api/src/main/java/io/mifos/customer/api/v1/client/ScanNotFoundException.java
index 2e12b10..3f2ada1 100644
--- a/component-test/src/main/java/io/mifos/customer/TestSuite.java
+++ b/api/src/main/java/io/mifos/customer/api/v1/client/ScanNotFoundException.java
@@ -1,5 +1,5 @@
/*
- * Copyright 2017 The Mifos Initiative.
+ * Copyright 2016 The Mifos Initiative.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@@ -13,20 +13,7 @@
* See the License for the specific language governing permissions and
* limitations under the License.
*/
-package io.mifos.customer;
+package io.mifos.customer.api.v1.client;
-import org.junit.runner.RunWith;
-import org.junit.runners.Suite;
-
-/**
- * @author Myrle Krantz
- */
-@RunWith(Suite.class)
-@Suite.SuiteClasses({
- TestCustomer.class,
- TestInfrastructure.class,
- TestTaskDefinition.class,
- TestTaskInstance.class,
-})
-public class TestSuite extends SuiteTestEnvironment {
+public final class ScanNotFoundException extends RuntimeException {
}
diff --git a/component-test/src/main/java/io/mifos/customer/TestSuite.java b/api/src/main/java/io/mifos/customer/api/v1/client/ScanValidationException.java
similarity index 64%
copy from component-test/src/main/java/io/mifos/customer/TestSuite.java
copy to api/src/main/java/io/mifos/customer/api/v1/client/ScanValidationException.java
index 2e12b10..cef64f9 100644
--- a/component-test/src/main/java/io/mifos/customer/TestSuite.java
+++ b/api/src/main/java/io/mifos/customer/api/v1/client/ScanValidationException.java
@@ -13,20 +13,7 @@
* See the License for the specific language governing permissions and
* limitations under the License.
*/
-package io.mifos.customer;
+package io.mifos.customer.api.v1.client;
-import org.junit.runner.RunWith;
-import org.junit.runners.Suite;
-
-/**
- * @author Myrle Krantz
- */
-@RunWith(Suite.class)
-@Suite.SuiteClasses({
- TestCustomer.class,
- TestInfrastructure.class,
- TestTaskDefinition.class,
- TestTaskInstance.class,
-})
-public class TestSuite extends SuiteTestEnvironment {
+public final class ScanValidationException extends RuntimeException {
}
diff --git a/component-test/src/main/java/io/mifos/customer/TestSuite.java b/api/src/main/java/io/mifos/customer/api/v1/domain/IdentificationCardScan.java
similarity index 53%
copy from component-test/src/main/java/io/mifos/customer/TestSuite.java
copy to api/src/main/java/io/mifos/customer/api/v1/domain/IdentificationCardScan.java
index 2e12b10..462e4fe 100644
--- a/component-test/src/main/java/io/mifos/customer/TestSuite.java
+++ b/api/src/main/java/io/mifos/customer/api/v1/domain/IdentificationCardScan.java
@@ -1,5 +1,5 @@
/*
- * Copyright 2017 The Mifos Initiative.
+ * Copyright 2016 The Mifos Initiative.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@@ -13,20 +13,28 @@
* See the License for the specific language governing permissions and
* limitations under the License.
*/
-package io.mifos.customer;
+package io.mifos.customer.api.v1.domain;
-import org.junit.runner.RunWith;
-import org.junit.runners.Suite;
+public class IdentificationCardScan {
+
+ private String identifier;
+
+ private String description;
+
+ public String getIdentifier() {
+ return identifier;
+ }
+
+ public void setIdentifier(String identifier) {
+ this.identifier = identifier;
+ }
+
+ public String getDescription() {
+ return description;
+ }
+
+ public void setDescription(String description) {
+ this.description = description;
+ }
-/**
- * @author Myrle Krantz
- */
-@RunWith(Suite.class)
-@Suite.SuiteClasses({
- TestCustomer.class,
- TestInfrastructure.class,
- TestTaskDefinition.class,
- TestTaskInstance.class,
-})
-public class TestSuite extends SuiteTestEnvironment {
}
diff --git a/api/src/main/java/io/mifos/customer/api/v1/events/ScanEvent.java b/api/src/main/java/io/mifos/customer/api/v1/events/ScanEvent.java
new file mode 100644
index 0000000..f4f8057
--- /dev/null
+++ b/api/src/main/java/io/mifos/customer/api/v1/events/ScanEvent.java
@@ -0,0 +1,52 @@
+/*
+ * Copyright 2016 The Mifos Initiative.
+ *
+ * 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.customer.api.v1.events;
+
+import java.util.Objects;
+
+public class ScanEvent {
+
+ private final String number;
+
+ private final String scanIdentifier;
+
+ public ScanEvent(final String number, final String scanIdentifier) {
+ this.number = number;
+ this.scanIdentifier = scanIdentifier;
+ }
+
+ @Override
+ public boolean equals(Object o) {
+ if (this == o) return true;
+ if (o == null || getClass() != o.getClass()) return false;
+ ScanEvent scanEvent = (ScanEvent) o;
+ return Objects.equals(number, scanEvent.number) &&
+ Objects.equals(scanIdentifier, scanEvent.scanIdentifier);
+ }
+
+ @Override
+ public int hashCode() {
+ return Objects.hash(number, scanIdentifier);
+ }
+
+ @Override
+ public String toString() {
+ return "ScanEvent{" +
+ "number='" + number + '\'' +
+ ", scanIdentifier='" + scanIdentifier + '\'' +
+ '}';
+ }
+}
diff --git a/component-test/src/main/java/io/mifos/customer/TestCustomer.java b/component-test/src/main/java/io/mifos/customer/TestCustomer.java
index 7ddf59e..228bc53 100644
--- a/component-test/src/main/java/io/mifos/customer/TestCustomer.java
+++ b/component-test/src/main/java/io/mifos/customer/TestCustomer.java
@@ -18,7 +18,10 @@ package io.mifos.customer;
import io.mifos.customer.api.v1.CustomerEventConstants;
import io.mifos.customer.api.v1.client.*;
import io.mifos.customer.api.v1.domain.*;
-import io.mifos.customer.util.*;
+import io.mifos.customer.util.AddressGenerator;
+import io.mifos.customer.util.CommandGenerator;
+import io.mifos.customer.util.ContactDetailGenerator;
+import io.mifos.customer.util.CustomerGenerator;
import org.apache.commons.lang3.RandomStringUtils;
import org.junit.Assert;
import org.junit.Test;
@@ -303,106 +306,6 @@ public class TestCustomer extends AbstractCustomerTest {
}
@Test
- public void shouldFetchIdentificationCards() throws Exception {
- final Customer customer = CustomerGenerator.createRandomCustomer();
-
- this.customerManager.createCustomer(customer);
-
- this.eventRecorder.wait(CustomerEventConstants.POST_CUSTOMER, customer.getIdentifier());
-
- Stream.of(
- IdentificationCardGenerator.createRandomIdentificationCard(),
- IdentificationCardGenerator.createRandomIdentificationCard(),
- IdentificationCardGenerator.createRandomIdentificationCard()
- ).forEach(identificationCard -> {
- this.customerManager.createIdentificationCard(customer.getIdentifier(), identificationCard);
- try {
- this.eventRecorder.wait(CustomerEventConstants.POST_IDENTIFICATION_CARD, identificationCard.getNumber());
- } catch (final InterruptedException ex) {
- Assert.fail(ex.getMessage());
- }
- });
-
- final List<IdentificationCard> result = this.customerManager.fetchIdentificationCards(customer.getIdentifier());
-
- Assert.assertTrue(result.size() == 3);
- }
-
- @Test
- public void shouldCreateIdentificationCard() throws Exception {
- final Customer customer = CustomerGenerator.createRandomCustomer();
-
- this.customerManager.createCustomer(customer);
-
- this.eventRecorder.wait(CustomerEventConstants.POST_CUSTOMER, customer.getIdentifier());
-
- final IdentificationCard newIdentificationCard = IdentificationCardGenerator.createRandomIdentificationCard();
-
- this.customerManager.createIdentificationCard(customer.getIdentifier(), newIdentificationCard);
-
- this.eventRecorder.wait(CustomerEventConstants.POST_IDENTIFICATION_CARD, newIdentificationCard.getNumber());
-
- final IdentificationCard identificationCard = this.customerManager.findIdentificationCard(customer.getIdentifier(), newIdentificationCard.getNumber());
-
- Assert.assertNotNull(identificationCard);
-
- Assert.assertEquals(identificationCard.getCreatedBy(), TEST_USER);
- }
-
- @Test
- public void shouldUpdateIdentificationCard() throws Exception {
- final Customer customer = CustomerGenerator.createRandomCustomer();
-
- this.customerManager.createCustomer(customer);
-
- this.eventRecorder.wait(CustomerEventConstants.POST_CUSTOMER, customer.getIdentifier());
-
- final IdentificationCard newIdentificationCard = IdentificationCardGenerator.createRandomIdentificationCard();
-
- this.customerManager.createIdentificationCard(customer.getIdentifier(), newIdentificationCard);
-
- this.eventRecorder.wait(CustomerEventConstants.POST_IDENTIFICATION_CARD, newIdentificationCard.getNumber());
-
- final IdentificationCard identificationCard = this.customerManager.findIdentificationCard(customer.getIdentifier(), newIdentificationCard.getNumber());
-
- final IdentificationCard updatedIdentificationCard = IdentificationCardGenerator.createRandomIdentificationCard();
-
- updatedIdentificationCard.setNumber(newIdentificationCard.getNumber());
-
- this.customerManager.updateIdentificationCard(customer.getIdentifier(), updatedIdentificationCard.getNumber(), updatedIdentificationCard);
-
- this.eventRecorder.wait(CustomerEventConstants.PUT_IDENTIFICATION_CARD, updatedIdentificationCard.getNumber());
-
- final IdentificationCard changedIdentificationCard = this.customerManager.findIdentificationCard(customer.getIdentifier(), identificationCard.getNumber());
-
- Assert.assertEquals(updatedIdentificationCard.getType(), changedIdentificationCard.getType());
- Assert.assertEquals(updatedIdentificationCard.getIssuer(), changedIdentificationCard.getIssuer());
- Assert.assertEquals(updatedIdentificationCard.getNumber(), changedIdentificationCard.getNumber());
- Assert.assertEquals(TEST_USER, changedIdentificationCard.getLastModifiedBy());
- }
-
- @Test(expected = IdentificationCardNotFoundException.class)
- public void shouldDeleteIdentificationCard() throws Exception {
- final Customer customer = CustomerGenerator.createRandomCustomer();
-
- this.customerManager.createCustomer(customer);
-
- this.eventRecorder.wait(CustomerEventConstants.POST_CUSTOMER, customer.getIdentifier());
-
- final IdentificationCard identificationCard = IdentificationCardGenerator.createRandomIdentificationCard();
-
- this.customerManager.createIdentificationCard(customer.getIdentifier(), identificationCard);
-
- this.eventRecorder.wait(CustomerEventConstants.POST_IDENTIFICATION_CARD, identificationCard.getNumber());
-
- this.customerManager.deleteIdentificationCard(customer.getIdentifier(), identificationCard.getNumber());
-
- this.eventRecorder.wait(CustomerEventConstants.DELETE_IDENTIFICATION_CARD, identificationCard.getNumber());
-
- this.customerManager.findIdentificationCard(customer.getIdentifier(), identificationCard.getNumber());
- }
-
- @Test
public void shouldUploadPortrait() throws Exception {
final Customer customer = CustomerGenerator.createRandomCustomer();
this.customerManager.createCustomer(customer);
diff --git a/component-test/src/main/java/io/mifos/customer/TestIdentificationCards.java b/component-test/src/main/java/io/mifos/customer/TestIdentificationCards.java
new file mode 100644
index 0000000..0740bba
--- /dev/null
+++ b/component-test/src/main/java/io/mifos/customer/TestIdentificationCards.java
@@ -0,0 +1,252 @@
+/*
+ * Copyright 2016 The Mifos Initiative.
+ *
+ * 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.customer;
+
+import io.mifos.customer.api.v1.CustomerEventConstants;
+import io.mifos.customer.api.v1.client.IdentificationCardNotFoundException;
+import io.mifos.customer.api.v1.client.ScanAlreadyExistsException;
+import io.mifos.customer.api.v1.client.ScanNotFoundException;
+import io.mifos.customer.api.v1.domain.Customer;
+import io.mifos.customer.api.v1.domain.IdentificationCard;
+import io.mifos.customer.api.v1.domain.IdentificationCardScan;
+import io.mifos.customer.api.v1.events.ScanEvent;
+import io.mifos.customer.util.CustomerGenerator;
+import io.mifos.customer.util.IdentificationCardGenerator;
+import io.mifos.customer.util.ScanGenerator;
+import org.apache.commons.lang3.RandomStringUtils;
+import org.junit.Assert;
+import org.junit.Test;
+import org.springframework.http.MediaType;
+import org.springframework.mock.web.MockMultipartFile;
+
+import java.util.List;
+import java.util.stream.Stream;
+
+public class TestIdentificationCards extends AbstractCustomerTest {
+
+ @Test
+ public void shouldFetchIdentificationCards() throws Exception {
+ final String customerIdentifier = this.createCustomer();
+
+ Stream.of(
+ IdentificationCardGenerator.createRandomIdentificationCard(),
+ IdentificationCardGenerator.createRandomIdentificationCard(),
+ IdentificationCardGenerator.createRandomIdentificationCard()
+ ).forEach(identificationCard -> {
+ this.customerManager.createIdentificationCard(customerIdentifier, identificationCard);
+ try {
+ this.eventRecorder.wait(CustomerEventConstants.POST_IDENTIFICATION_CARD, identificationCard.getNumber());
+ } catch (final InterruptedException ex) {
+ Assert.fail(ex.getMessage());
+ }
+ });
+
+ final List<IdentificationCard> result = this.customerManager.fetchIdentificationCards(customerIdentifier);
+
+ Assert.assertTrue(result.size() == 3);
+ }
+
+ @Test
+ public void shouldCreateIdentificationCard() throws Exception {
+ final String customerIdentifier = this.createCustomer();
+
+ final String identificationCardNumber = this.createIdentificationCard(customerIdentifier);
+
+ final IdentificationCard identificationCard = this.customerManager.findIdentificationCard(customerIdentifier, identificationCardNumber);
+
+ Assert.assertNotNull(identificationCard);
+
+ Assert.assertEquals(identificationCard.getCreatedBy(), TEST_USER);
+ }
+
+ @Test
+ public void shouldUpdateIdentificationCard() throws Exception {
+ final String customerIdentifier = this.createCustomer();
+
+ final String identificationCardNumber = this.createIdentificationCard(customerIdentifier);
+
+ final IdentificationCard identificationCard = this.customerManager.findIdentificationCard(customerIdentifier, identificationCardNumber);
+
+ final IdentificationCard updatedIdentificationCard = IdentificationCardGenerator.createRandomIdentificationCard();
+
+ updatedIdentificationCard.setNumber(identificationCardNumber);
+
+ this.customerManager.updateIdentificationCard(customerIdentifier, updatedIdentificationCard.getNumber(), updatedIdentificationCard);
+
+ this.eventRecorder.wait(CustomerEventConstants.PUT_IDENTIFICATION_CARD, updatedIdentificationCard.getNumber());
+
+ final IdentificationCard changedIdentificationCard = this.customerManager.findIdentificationCard(customerIdentifier, identificationCard.getNumber());
+
+ Assert.assertEquals(updatedIdentificationCard.getType(), changedIdentificationCard.getType());
+ Assert.assertEquals(updatedIdentificationCard.getIssuer(), changedIdentificationCard.getIssuer());
+ Assert.assertEquals(updatedIdentificationCard.getNumber(), changedIdentificationCard.getNumber());
+ Assert.assertEquals(TEST_USER, changedIdentificationCard.getLastModifiedBy());
+ }
+
+ @Test(expected = IdentificationCardNotFoundException.class)
+ public void shouldDeleteIdentificationCard() throws Exception {
+ final String customerIdentifier = this.createCustomer();
+
+ final String identificationCardNumber = this.createIdentificationCard(customerIdentifier);
+
+ this.customerManager.deleteIdentificationCard(customerIdentifier, identificationCardNumber);
+
+ this.eventRecorder.wait(CustomerEventConstants.DELETE_IDENTIFICATION_CARD, identificationCardNumber);
+
+ this.customerManager.findIdentificationCard(customerIdentifier, identificationCardNumber);
+ }
+
+ @Test(expected = IdentificationCardNotFoundException.class)
+ public void shouldDeleteIdentificationCardWithScan() throws Exception {
+ final String customerIdentifier = this.createCustomer();
+
+ final String identificationCardNumber = this.createIdentificationCard(customerIdentifier);
+
+ this.createScan(customerIdentifier, identificationCardNumber);
+
+ this.customerManager.deleteIdentificationCard(customerIdentifier, identificationCardNumber);
+
+ this.eventRecorder.wait(CustomerEventConstants.DELETE_IDENTIFICATION_CARD, identificationCardNumber);
+
+ this.customerManager.findIdentificationCard(customerIdentifier, identificationCardNumber);
+ }
+
+ @Test
+ public void shouldFetchScans() throws Exception {
+ final String customerIdentifier = this.createCustomer();
+
+ final String identificationCardNumber = this.createIdentificationCard(customerIdentifier);
+
+ this.createScan(customerIdentifier, identificationCardNumber);
+ this.createScan(customerIdentifier, identificationCardNumber);
+ this.createScan(customerIdentifier, identificationCardNumber);
+
+ final List<IdentificationCardScan> result = this.customerManager.fetchIdentificationCardScans(customerIdentifier, identificationCardNumber);
+
+ Assert.assertTrue(result.size() == 3);
+ }
+
+ @Test
+ public void shouldFindScan() throws Exception {
+ final String customerIdentifier = this.createCustomer();
+
+ final String identificationCardNumberOne = this.createIdentificationCard(customerIdentifier);
+ final String identificationCardNumberTwo = this.createIdentificationCard(customerIdentifier);
+ this.createScan(customerIdentifier, identificationCardNumberOne, "sameIdentifier");
+ final IdentificationCardScan createdScan = this.createScan(customerIdentifier, identificationCardNumberTwo, "sameIdentifier");
+
+ final IdentificationCardScan scan = this.customerManager.findIdentificationCardScan(customerIdentifier, identificationCardNumberTwo, createdScan.getIdentifier());
+
+ Assert.assertNotNull(scan);
+
+ Assert.assertEquals(scan.getIdentifier(), createdScan.getIdentifier());
+ Assert.assertEquals(scan.getDescription(), createdScan.getDescription());
+ }
+
+ @Test
+ public void shouldFindScanWithImage() throws Exception {
+ final String customerIdentifier = this.createCustomer();
+
+ final String identificationCardNumber = this.createIdentificationCard(customerIdentifier);
+
+ final IdentificationCardScan scan = ScanGenerator.createRandomScan(null);
+
+ final byte[] imageInBytes = RandomStringUtils.randomAlphanumeric(20).getBytes();
+
+ final MockMultipartFile image = new MockMultipartFile("image", "test.png", MediaType.IMAGE_PNG_VALUE, imageInBytes);
+
+ this.customerManager.postIdentificationCardScan(customerIdentifier, identificationCardNumber, scan.getIdentifier(), scan.getDescription(), image);
+
+ this.eventRecorder.wait(CustomerEventConstants.POST_IDENTIFICATION_CARD_SCAN, new ScanEvent(identificationCardNumber, scan.getIdentifier()));
+
+ final byte[] persistedImageInBytes = this.customerManager.fetchIdentificationCardScanImage(customerIdentifier, identificationCardNumber, scan.getIdentifier());
+
+ Assert.assertArrayEquals(imageInBytes, persistedImageInBytes);
+ }
+
+ @Test(expected = ScanAlreadyExistsException.class)
+ public void shouldThrowIfScanAlreadyExists() throws Exception {
+ final String customerIdentifier = this.createCustomer();
+
+ final String identificationCardNumber = this.createIdentificationCard(customerIdentifier);
+
+ final IdentificationCardScan scan = this.createScan(customerIdentifier, identificationCardNumber);
+
+ final MockMultipartFile image = new MockMultipartFile("image", "test.png", MediaType.IMAGE_PNG_VALUE, RandomStringUtils.randomAlphanumeric(20).getBytes());
+
+ this.customerManager.postIdentificationCardScan(customerIdentifier, identificationCardNumber, scan.getIdentifier(), scan.getDescription(), image);
+ }
+
+ @Test(expected = ScanNotFoundException.class)
+ public void shouldDeleteScan() throws Exception {
+ final String customerIdentifier = this.createCustomer();
+
+ final String identificationCardNumber = this.createIdentificationCard(customerIdentifier);
+
+ final IdentificationCardScan createdScan = this.createScan(customerIdentifier, identificationCardNumber);
+
+ this.customerManager.deleteScan(customerIdentifier, identificationCardNumber, createdScan.getIdentifier());
+
+ this.eventRecorder.wait(CustomerEventConstants.DELETE_IDENTIFICATION_CARD_SCAN, new ScanEvent(identificationCardNumber, createdScan.getIdentifier()));
+
+ this.customerManager.findIdentificationCardScan(customerIdentifier, identificationCardNumber, createdScan.getIdentifier());
+ }
+
+ private String createCustomer() throws Exception {
+ final Customer customer = CustomerGenerator.createRandomCustomer();
+
+ this.customerManager.createCustomer(customer);
+
+ this.eventRecorder.wait(CustomerEventConstants.POST_CUSTOMER, customer.getIdentifier());
+
+ return customer.getIdentifier();
+ }
+
+ private String createIdentificationCard(final String customerIdentifier) throws Exception {
+ final IdentificationCard identificationCard = IdentificationCardGenerator.createRandomIdentificationCard();
+
+ this.customerManager.createIdentificationCard(customerIdentifier, identificationCard);
+
+ this.eventRecorder.wait(CustomerEventConstants.POST_IDENTIFICATION_CARD, identificationCard.getNumber());
+
+ return identificationCard.getNumber();
+ }
+
+ private IdentificationCardScan createScan(final String customerIdentifier, final String cardNumber) throws Exception {
+ final IdentificationCardScan scan = ScanGenerator.createRandomScan(null);
+
+ this.postIdentificationCardScan(customerIdentifier, cardNumber, scan);
+
+ return scan;
+ }
+
+ private IdentificationCardScan createScan(final String customerIdentifier, final String cardNumber, final String identifier) throws Exception {
+ final IdentificationCardScan scan = ScanGenerator.createRandomScan(identifier);
+
+ this.postIdentificationCardScan(customerIdentifier, cardNumber, scan);
+
+ return scan;
+ }
+
+ private void postIdentificationCardScan(final String customerIdentifier, final String cardNumber, final IdentificationCardScan scan) throws InterruptedException {
+ final MockMultipartFile image = new MockMultipartFile("image", "test.png", MediaType.IMAGE_PNG_VALUE, RandomStringUtils.randomAlphanumeric(20).getBytes());
+
+ this.customerManager.postIdentificationCardScan(customerIdentifier, cardNumber, scan.getIdentifier(), scan.getDescription(), image);
+
+ this.eventRecorder.wait(CustomerEventConstants.POST_IDENTIFICATION_CARD_SCAN, new ScanEvent(cardNumber, scan.getIdentifier()));
+ }
+
+}
diff --git a/component-test/src/main/java/io/mifos/customer/TestSuite.java b/component-test/src/main/java/io/mifos/customer/TestSuite.java
index 2e12b10..4ed78bb 100644
--- a/component-test/src/main/java/io/mifos/customer/TestSuite.java
+++ b/component-test/src/main/java/io/mifos/customer/TestSuite.java
@@ -24,6 +24,7 @@ import org.junit.runners.Suite;
@RunWith(Suite.class)
@Suite.SuiteClasses({
TestCustomer.class,
+ TestIdentificationCards.class,
TestInfrastructure.class,
TestTaskDefinition.class,
TestTaskInstance.class,
diff --git a/component-test/src/main/java/io/mifos/customer/listener/CustomerEventListener.java b/component-test/src/main/java/io/mifos/customer/listener/CustomerEventListener.java
index f066746..5c1d2e1 100644
--- a/component-test/src/main/java/io/mifos/customer/listener/CustomerEventListener.java
+++ b/component-test/src/main/java/io/mifos/customer/listener/CustomerEventListener.java
@@ -18,6 +18,7 @@ package io.mifos.customer.listener;
import io.mifos.core.lang.config.TenantHeaderFilter;
import io.mifos.core.test.listener.EventRecorder;
import io.mifos.customer.api.v1.CustomerEventConstants;
+import io.mifos.customer.api.v1.events.ScanEvent;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.jms.annotation.JmsListener;
import org.springframework.messaging.handler.annotation.Header;
@@ -144,6 +145,24 @@ public class CustomerEventListener {
@JmsListener(
destination = CustomerEventConstants.DESTINATION,
+ selector = CustomerEventConstants.SELECTOR_POST_IDENTIFICATION_CARD_SCAN
+ )
+ public void identificationCardScanCreateEvent(@Header(TenantHeaderFilter.TENANT_HEADER) final String tenant,
+ final String payload) {
+ this.eventRecorder.event(tenant, CustomerEventConstants.POST_IDENTIFICATION_CARD_SCAN, payload, ScanEvent.class);
+ }
+
+ @JmsListener(
+ destination = CustomerEventConstants.DESTINATION,
+ selector = CustomerEventConstants.SELECTOR_DELETE_IDENTIFICATION_CARD_SCAN
+ )
+ public void identificationCardScanDeleteEvent(@Header(TenantHeaderFilter.TENANT_HEADER) final String tenant,
+ final String payload) {
+ this.eventRecorder.event(tenant, CustomerEventConstants.DELETE_IDENTIFICATION_CARD_SCAN, payload, ScanEvent.class);
+ }
+
+ @JmsListener(
+ destination = CustomerEventConstants.DESTINATION,
selector = CustomerEventConstants.SELECTOR_PUT_PORTRAIT
)
public void portraitPutEvent(@Header(TenantHeaderFilter.TENANT_HEADER) final String tenant,
diff --git a/component-test/src/main/java/io/mifos/customer/util/ScanGenerator.java b/component-test/src/main/java/io/mifos/customer/util/ScanGenerator.java
new file mode 100644
index 0000000..b139623
--- /dev/null
+++ b/component-test/src/main/java/io/mifos/customer/util/ScanGenerator.java
@@ -0,0 +1,39 @@
+/*
+ * Copyright 2016 The Mifos Initiative.
+ *
+ * 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.customer.util;
+
+import io.mifos.customer.api.v1.domain.IdentificationCardScan;
+import org.apache.commons.lang3.RandomStringUtils;
+
+import javax.annotation.Nullable;
+
+public class ScanGenerator {
+
+ private ScanGenerator() {}
+
+ public static IdentificationCardScan createRandomScan(@Nullable final String identifier) {
+ final IdentificationCardScan scan = new IdentificationCardScan();
+
+ if(identifier != null) {
+ scan.setIdentifier(identifier);
+ } else {
+ scan.setIdentifier(RandomStringUtils.randomAlphanumeric(32));
+ }
+
+ scan.setDescription(RandomStringUtils.randomAlphanumeric(128));
+ return scan;
+ }
+}
diff --git a/service/src/main/java/io/mifos/customer/service/internal/command/CreateIdentificationCardScanCommand.java b/service/src/main/java/io/mifos/customer/service/internal/command/CreateIdentificationCardScanCommand.java
new file mode 100644
index 0000000..166ba69
--- /dev/null
+++ b/service/src/main/java/io/mifos/customer/service/internal/command/CreateIdentificationCardScanCommand.java
@@ -0,0 +1,52 @@
+/*
+ * Copyright 2016 The Mifos Initiative.
+ *
+ * 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.customer.service.internal.command;
+
+import io.mifos.customer.api.v1.domain.IdentificationCardScan;
+import org.springframework.web.multipart.MultipartFile;
+
+public class CreateIdentificationCardScanCommand {
+
+ private final String number;
+
+ private final IdentificationCardScan scan;
+
+ private final MultipartFile image;
+
+ public CreateIdentificationCardScanCommand(final String number, final IdentificationCardScan scan, final MultipartFile image) {
+ this.number = number;
+ this.scan = scan;
+ this.image = image;
+ }
+
+ public String number () {
+ return number;
+ }
+
+ public IdentificationCardScan scan() {
+ return scan;
+ }
+
+ public MultipartFile image() { return image; }
+
+ @Override
+ public String toString() {
+ return "CreateIdentificationCardScanCommand{" +
+ "number='" + number + '\'' +
+ ", scan=" + scan +
+ '}';
+ }
+}
diff --git a/component-test/src/main/java/io/mifos/customer/TestSuite.java b/service/src/main/java/io/mifos/customer/service/internal/command/DeleteIdentificationCardScanCommand.java
similarity index 53%
copy from component-test/src/main/java/io/mifos/customer/TestSuite.java
copy to service/src/main/java/io/mifos/customer/service/internal/command/DeleteIdentificationCardScanCommand.java
index 2e12b10..2240c0a 100644
--- a/component-test/src/main/java/io/mifos/customer/TestSuite.java
+++ b/service/src/main/java/io/mifos/customer/service/internal/command/DeleteIdentificationCardScanCommand.java
@@ -1,5 +1,5 @@
/*
- * Copyright 2017 The Mifos Initiative.
+ * Copyright 2016 The Mifos Initiative.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@@ -13,20 +13,22 @@
* See the License for the specific language governing permissions and
* limitations under the License.
*/
-package io.mifos.customer;
+package io.mifos.customer.service.internal.command;
-import org.junit.runner.RunWith;
-import org.junit.runners.Suite;
+public class DeleteIdentificationCardScanCommand {
-/**
- * @author Myrle Krantz
- */
-@RunWith(Suite.class)
-@Suite.SuiteClasses({
- TestCustomer.class,
- TestInfrastructure.class,
- TestTaskDefinition.class,
- TestTaskInstance.class,
-})
-public class TestSuite extends SuiteTestEnvironment {
+ private final String number;
+
+ private final String scanIdentifier;
+
+ public DeleteIdentificationCardScanCommand(final String number, final String scanIdentifier) {
+ this.number = number;
+ this.scanIdentifier = scanIdentifier;
+ }
+
+ public String number() { return number; }
+
+ public String scanIdentifier() {
+ return scanIdentifier;
+ }
}
diff --git a/service/src/main/java/io/mifos/customer/service/internal/command/handler/CustomerAggregate.java b/service/src/main/java/io/mifos/customer/service/internal/command/handler/CustomerAggregate.java
index 953f8fd..7ec7770 100644
--- a/service/src/main/java/io/mifos/customer/service/internal/command/handler/CustomerAggregate.java
+++ b/service/src/main/java/io/mifos/customer/service/internal/command/handler/CustomerAggregate.java
@@ -18,11 +18,13 @@ package io.mifos.customer.service.internal.command.handler;
import io.mifos.core.api.util.UserContextHolder;
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.customer.api.v1.CustomerEventConstants;
import io.mifos.customer.api.v1.domain.Command;
import io.mifos.customer.api.v1.domain.Customer;
+import io.mifos.customer.api.v1.events.ScanEvent;
import io.mifos.customer.catalog.service.internal.repository.CatalogEntity;
import io.mifos.customer.catalog.service.internal.repository.CatalogRepository;
import io.mifos.customer.catalog.service.internal.repository.FieldEntity;
@@ -34,6 +36,7 @@ import io.mifos.customer.service.internal.mapper.*;
import io.mifos.customer.service.internal.repository.*;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.transaction.annotation.Transactional;
+import org.springframework.web.multipart.MultipartFile;
import java.io.IOException;
import java.sql.Date;
@@ -51,6 +54,7 @@ public class CustomerAggregate {
private final AddressRepository addressRepository;
private final CustomerRepository customerRepository;
private final IdentificationCardRepository identificationCardRepository;
+ private final IdentificationCardScanRepository identificationCardScanRepository;
private final PortraitRepository portraitRepository;
private final ContactDetailRepository contactDetailRepository;
private final FieldValueRepository fieldValueRepository;
@@ -63,6 +67,7 @@ public class CustomerAggregate {
public CustomerAggregate(final AddressRepository addressRepository,
final CustomerRepository customerRepository,
final IdentificationCardRepository identificationCardRepository,
+ final IdentificationCardScanRepository identificationCardScanRepository,
final PortraitRepository portraitRepository,
final ContactDetailRepository contactDetailRepository,
final FieldValueRepository fieldValueRepository,
@@ -74,6 +79,7 @@ public class CustomerAggregate {
this.addressRepository = addressRepository;
this.customerRepository = customerRepository;
this.identificationCardRepository = identificationCardRepository;
+ this.identificationCardScanRepository = identificationCardScanRepository;
this.portraitRepository = portraitRepository;
this.contactDetailRepository = contactDetailRepository;
this.fieldValueRepository = fieldValueRepository;
@@ -381,6 +387,10 @@ public class CustomerAggregate {
optionalIdentificationCardEntity.ifPresent(identificationCardEntity -> {
+ final List<IdentificationCardScanEntity> cardScanEntities = this.identificationCardScanRepository.findByIdentificationCard(identificationCardEntity);
+
+ this.identificationCardScanRepository.delete(cardScanEntities);
+
this.identificationCardRepository.delete(identificationCardEntity);
final CustomerEntity customerEntity = identificationCardEntity.getCustomer();
@@ -395,6 +405,60 @@ public class CustomerAggregate {
}
@Transactional
+ @CommandHandler(logStart = CommandLogLevel.INFO, logFinish = CommandLogLevel.INFO)
+ @EventEmitter(selectorName = CustomerEventConstants.SELECTOR_NAME, selectorValue = CustomerEventConstants.POST_IDENTIFICATION_CARD_SCAN)
+ public ScanEvent createIdentificationCardScan(final CreateIdentificationCardScanCommand command) throws Exception {
+ final Optional<IdentificationCardEntity> identificationCardEntity = this.identificationCardRepository.findByNumber(command.number());
+
+ final IdentificationCardEntity cardEntity = identificationCardEntity.orElseThrow(() -> ServiceException.notFound("Identification card {0} not found.", command.number()));
+
+ final IdentificationCardScanEntity identificationCardScanEntity = IdentificationCardScanMapper.map(command.scan());
+
+ final MultipartFile image = command.image();
+
+ final LocalDateTime now = LocalDateTime.now(Clock.systemUTC());
+
+ identificationCardScanEntity.setImage(image.getBytes());
+ identificationCardScanEntity.setContentType(image.getContentType());
+ identificationCardScanEntity.setSize(image.getSize());
+ identificationCardScanEntity.setIdentificationCard(cardEntity);
+ identificationCardScanEntity.setCreatedBy(UserContextHolder.checkedGetUser());
+ identificationCardScanEntity.setCreatedOn(now);
+
+ identificationCardScanRepository.save(identificationCardScanEntity);
+
+ cardEntity.setLastModifiedBy(UserContextHolder.checkedGetUser());
+ cardEntity.setLastModifiedOn(now);
+
+ identificationCardRepository.save(cardEntity);
+
+ return new ScanEvent(command.number(), command.scan().getIdentifier());
+ }
+
+ @Transactional
+ @CommandHandler(logStart = CommandLogLevel.INFO, logFinish = CommandLogLevel.INFO)
+ @EventEmitter(selectorName = CustomerEventConstants.SELECTOR_NAME, selectorValue = CustomerEventConstants.DELETE_IDENTIFICATION_CARD_SCAN)
+ public ScanEvent deleteIdentificationCardScan(final DeleteIdentificationCardScanCommand command) {
+ final Optional<IdentificationCardEntity> cardEntity = this.identificationCardRepository.findByNumber(command.number());
+ final Optional<IdentificationCardScanEntity> scanEntity = cardEntity
+ .flatMap(entity -> this.identificationCardScanRepository.findByIdentifierAndIdentificationCard(command.scanIdentifier(), entity));
+
+ scanEntity.ifPresent(identificationCardScanEntity -> {
+
+ this.identificationCardScanRepository.delete(identificationCardScanEntity);
+
+ final IdentificationCardEntity identificationCard = identificationCardScanEntity.getIdentificationCard();
+
+ identificationCard.setLastModifiedBy(UserContextHolder.checkedGetUser());
+ identificationCard.setLastModifiedOn(LocalDateTime.now(Clock.systemUTC()));
+
+ this.identificationCardRepository.save(identificationCard);
+ });
+
+ return new ScanEvent(command.number(), command.scanIdentifier());
+ }
+
+ @Transactional
@CommandHandler
@EventEmitter(selectorName = CustomerEventConstants.SELECTOR_NAME, selectorValue = CustomerEventConstants.POST_PORTRAIT)
public String createPortrait(final CreatePortraitCommand createPortraitCommand) throws IOException {
diff --git a/service/src/main/java/io/mifos/customer/service/internal/mapper/IdentificationCardScanMapper.java b/service/src/main/java/io/mifos/customer/service/internal/mapper/IdentificationCardScanMapper.java
new file mode 100644
index 0000000..346adfb
--- /dev/null
+++ b/service/src/main/java/io/mifos/customer/service/internal/mapper/IdentificationCardScanMapper.java
@@ -0,0 +1,44 @@
+/*
+ * Copyright 2016 The Mifos Initiative.
+ *
+ * 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.customer.service.internal.mapper;
+
+import io.mifos.customer.api.v1.domain.IdentificationCardScan;
+import io.mifos.customer.service.internal.repository.IdentificationCardScanEntity;
+
+public class IdentificationCardScanMapper {
+
+ private IdentificationCardScanMapper() {
+ super();
+ }
+
+ public static IdentificationCardScanEntity map(final IdentificationCardScan scan) {
+ final IdentificationCardScanEntity entity = new IdentificationCardScanEntity();
+
+ entity.setIdentifier(scan.getIdentifier());
+ entity.setDescription(scan.getDescription());
+
+ return entity;
+ }
+
+ public static IdentificationCardScan map(final IdentificationCardScanEntity entity) {
+ final IdentificationCardScan scan = new IdentificationCardScan();
+
+ scan.setIdentifier(entity.getIdentifier());
+ scan.setDescription(entity.getDescription());
+
+ return scan;
+ }
+}
diff --git a/service/src/main/java/io/mifos/customer/service/internal/repository/IdentificationCardScanEntity.java b/service/src/main/java/io/mifos/customer/service/internal/repository/IdentificationCardScanEntity.java
new file mode 100644
index 0000000..acd9808
--- /dev/null
+++ b/service/src/main/java/io/mifos/customer/service/internal/repository/IdentificationCardScanEntity.java
@@ -0,0 +1,128 @@
+/*
+ * Copyright 2016 The Mifos Initiative.
+ *
+ * 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.customer.service.internal.repository;
+
+import io.mifos.core.mariadb.util.LocalDateTimeConverter;
+import io.mifos.customer.api.v1.domain.IdentificationCard;
+
+import javax.persistence.*;
+import java.time.LocalDateTime;
+
+@Entity
+@Table(name = "maat_identification_card_scans")
+public class IdentificationCardScanEntity {
+
+ @Id
+ @GeneratedValue(strategy = GenerationType.IDENTITY)
+ @Column(name = "id")
+ private Long id;
+ @Column(name = "identifier")
+ private String identifier;
+ @Column(name = "description")
+ private String description;
+ @Lob
+ @Column(name = "image")
+ private byte[] image;
+ @Column(name = "size")
+ private Long size;
+ @Column(name = "content_type")
+ private String contentType;
+ @ManyToOne(fetch = FetchType.LAZY, optional = true)
+ @JoinColumn(name = "identification_card_id")
+ private IdentificationCardEntity identificationCard;
+ @Column(name = "created_by")
+ private String createdBy;
+ @Column(name = "created_on")
+ @Convert(converter = LocalDateTimeConverter.class)
+ private LocalDateTime createdOn;
+
+ public IdentificationCardScanEntity() {
+ super();
+ }
+
+ public Long getId() {
+ return id;
+ }
+
+ public void setId(Long id) {
+ this.id = id;
+ }
+
+ public String getIdentifier() {
+ return identifier;
+ }
+
+ public void setIdentifier(String identifier) {
+ this.identifier = identifier;
+ }
+
+ public String getDescription() {
+ return description;
+ }
+
+ public void setDescription(String description) {
+ this.description = description;
+ }
+
+ public byte[] getImage() {
+ return image;
+ }
+
+ public void setImage(byte[] image) {
+ this.image = image;
+ }
+
+ public Long getSize() {
+ return size;
+ }
+
+ public void setSize(Long size) {
+ this.size = size;
+ }
+
+ public String getContentType() {
+ return contentType;
+ }
+
+ public void setContentType(String contentType) {
+ this.contentType = contentType;
+ }
+
+ public IdentificationCardEntity getIdentificationCard() {
+ return identificationCard;
+ }
+
+ public void setIdentificationCard(IdentificationCardEntity identificationCard) {
+ this.identificationCard = identificationCard;
+ }
+
+ public String getCreatedBy() {
+ return createdBy;
+ }
+
+ public void setCreatedBy(String createdBy) {
+ this.createdBy = createdBy;
+ }
+
+ public LocalDateTime getCreatedOn() {
+ return createdOn;
+ }
+
+ public void setCreatedOn(LocalDateTime createdOn) {
+ this.createdOn = createdOn;
+ }
+
+}
diff --git a/service/src/main/java/io/mifos/customer/service/internal/repository/IdentificationCardScanRepository.java b/service/src/main/java/io/mifos/customer/service/internal/repository/IdentificationCardScanRepository.java
new file mode 100644
index 0000000..dded654
--- /dev/null
+++ b/service/src/main/java/io/mifos/customer/service/internal/repository/IdentificationCardScanRepository.java
@@ -0,0 +1,35 @@
+/*
+ * Copyright 2016 The Mifos Initiative.
+ *
+ * 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.customer.service.internal.repository;
+
+import org.springframework.data.jpa.repository.JpaRepository;
+import org.springframework.data.jpa.repository.Query;
+import org.springframework.data.repository.query.Param;
+import org.springframework.stereotype.Repository;
+
+import java.util.List;
+import java.util.Optional;
+
+@Repository
+public interface IdentificationCardScanRepository extends JpaRepository<IdentificationCardScanEntity, Long> {
+
+ @Query("SELECT CASE WHEN COUNT(i) > 0 THEN 'true' ELSE 'false' END FROM IdentificationCardScanEntity i WHERE i.identifier = :identifier AND i.identificationCard = :identificationCard")
+ Boolean existsByIdentifierAndIdentificationCard(@Param("identifier") final String identifier, @Param("identificationCard") final IdentificationCardEntity identificationCardEntity);
+
+ Optional<IdentificationCardScanEntity> findByIdentifierAndIdentificationCard(final String identifier, final IdentificationCardEntity identificationCardEntity);
+
+ List<IdentificationCardScanEntity> findByIdentificationCard(final IdentificationCardEntity identificationCardEntity);
+}
diff --git a/service/src/main/java/io/mifos/customer/service/internal/service/CustomerService.java b/service/src/main/java/io/mifos/customer/service/internal/service/CustomerService.java
index 5048a4c..f7fd56f 100644
--- a/service/src/main/java/io/mifos/customer/service/internal/service/CustomerService.java
+++ b/service/src/main/java/io/mifos/customer/service/internal/service/CustomerService.java
@@ -15,24 +15,14 @@
*/
package io.mifos.customer.service.internal.service;
-import io.mifos.customer.api.v1.domain.Command;
-import io.mifos.customer.api.v1.domain.Customer;
-import io.mifos.customer.api.v1.domain.CustomerPage;
-import io.mifos.customer.api.v1.domain.IdentificationCard;
-import io.mifos.customer.api.v1.domain.ProcessStep;
-import io.mifos.customer.api.v1.domain.TaskDefinition;
+import io.mifos.customer.api.v1.domain.*;
import io.mifos.customer.catalog.api.v1.domain.Value;
import io.mifos.customer.catalog.service.internal.repository.FieldEntity;
import io.mifos.customer.catalog.service.internal.repository.FieldValueEntity;
import io.mifos.customer.catalog.service.internal.repository.FieldValueRepository;
import io.mifos.customer.service.ServiceConstants;
-import io.mifos.customer.service.internal.mapper.CommandMapper;
-import io.mifos.customer.service.internal.mapper.ContactDetailMapper;
-import io.mifos.customer.service.internal.mapper.CustomerMapper;
-import io.mifos.customer.service.internal.mapper.IdentificationCardMapper;
-import io.mifos.customer.service.internal.mapper.TaskDefinitionMapper;
+import io.mifos.customer.service.internal.mapper.*;
import io.mifos.customer.service.internal.repository.*;
-import io.mifos.customer.service.internal.mapper.AddressMapper;
import org.slf4j.Logger;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Qualifier;
@@ -52,6 +42,7 @@ public class CustomerService {
private final Logger logger;
private final CustomerRepository customerRepository;
private final IdentificationCardRepository identificationCardRepository;
+ private final IdentificationCardScanRepository identificationCardScanRepository;
private final PortraitRepository portraitRepository;
private final ContactDetailRepository contactDetailRepository;
private final FieldValueRepository fieldValueRepository;
@@ -63,6 +54,7 @@ public class CustomerService {
public CustomerService(@Qualifier(ServiceConstants.LOGGER_NAME) final Logger logger,
final CustomerRepository customerRepository,
final IdentificationCardRepository identificationCardRepository,
+ final IdentificationCardScanRepository identificationCardScanRepository,
final PortraitRepository portraitRepository,
final ContactDetailRepository contactDetailRepository,
final FieldValueRepository fieldValueRepository,
@@ -73,6 +65,7 @@ public class CustomerService {
this.logger = logger;
this.customerRepository = customerRepository;
this.identificationCardRepository = identificationCardRepository;
+ this.identificationCardScanRepository = identificationCardScanRepository;
this.portraitRepository = portraitRepository;
this.contactDetailRepository = contactDetailRepository;
this.fieldValueRepository = fieldValueRepository;
@@ -93,6 +86,12 @@ public class CustomerService {
return this.identificationCardRepository.existsByNumber(number);
}
+ public Boolean identificationCardScanExists(final String number, final String identifier) {
+ return this.identificationCardRepository.findByNumber(number)
+ .map(cardEntity -> this.identificationCardScanRepository.existsByIdentifierAndIdentificationCard(identifier, cardEntity))
+ .orElse(false);
+ }
+
public Optional<Customer> findCustomer(final String identifier) {
final CustomerEntity customerEntity = this.customerRepository.findByIdentifier(identifier);
if (customerEntity != null) {
@@ -195,6 +194,28 @@ public class CustomerService {
return identificationCardEntity.map(IdentificationCardMapper::map);
}
+ public final List<IdentificationCardScan> fetchScansByIdentificationCard(final String number) {
+ final Optional<IdentificationCardEntity> identificationCard = this.identificationCardRepository.findByNumber(number);
+
+ return identificationCard.map(this.identificationCardScanRepository::findByIdentificationCard)
+ .map(x -> x.stream().map(IdentificationCardScanMapper::map).collect(Collectors.toList()))
+ .orElseGet(Collections::emptyList);
+ }
+
+ private Optional<IdentificationCardScanEntity> findIdentificationCardEntity(final String number, final String identifier) {
+ final Optional<IdentificationCardEntity> cardEntity = this.identificationCardRepository.findByNumber(number);
+ final Optional<IdentificationCardScanEntity> cardScanEntity = cardEntity.flatMap(card -> this.identificationCardScanRepository.findByIdentifierAndIdentificationCard(identifier, card));
+ return cardScanEntity;
+ }
+
+ public Optional<IdentificationCardScan> findIdentificationCardScan(final String number, final String identifier) {
+ return this.findIdentificationCardEntity(number, identifier).map(IdentificationCardScanMapper::map);
+ }
+
+ public Optional<byte[]> findIdentificationCardScanImage(final String number, final String identifier) {
+ return this.findIdentificationCardEntity(number, identifier).map(IdentificationCardScanEntity::getImage);
+ }
+
public List<ProcessStep> getProcessSteps(final String customerIdentifier) {
final ArrayList<ProcessStep> processSteps = new ArrayList<>();
final CustomerEntity customerEntity = this.customerRepository.findByIdentifier(customerIdentifier);
diff --git a/service/src/main/java/io/mifos/customer/service/rest/controller/CustomerRestController.java b/service/src/main/java/io/mifos/customer/service/rest/controller/CustomerRestController.java
index 41546b9..f68549e 100644
--- a/service/src/main/java/io/mifos/customer/service/rest/controller/CustomerRestController.java
+++ b/service/src/main/java/io/mifos/customer/service/rest/controller/CustomerRestController.java
@@ -20,6 +20,7 @@ import io.mifos.anubis.annotation.Permittable;
import io.mifos.core.api.util.UserContextHolder;
import io.mifos.core.command.gateway.CommandGateway;
import io.mifos.core.lang.ServiceException;
+import io.mifos.core.lang.validation.constraints.ValidIdentifier;
import io.mifos.customer.PermittableGroupIds;
import io.mifos.customer.api.v1.domain.*;
import io.mifos.customer.catalog.service.internal.service.FieldValueValidator;
@@ -28,6 +29,7 @@ import io.mifos.customer.service.internal.command.*;
import io.mifos.customer.service.internal.repository.PortraitEntity;
import io.mifos.customer.service.internal.service.CustomerService;
import io.mifos.customer.service.internal.service.TaskService;
+import org.apache.commons.lang.RandomStringUtils;
import org.slf4j.Logger;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Qualifier;
@@ -41,6 +43,7 @@ import org.springframework.web.bind.annotation.*;
import org.springframework.web.multipart.MultipartFile;
import javax.validation.Valid;
+import javax.validation.constraints.Size;
import java.util.List;
import java.util.Optional;
@@ -454,6 +457,120 @@ public class CustomerRestController {
return ResponseEntity.accepted().build();
}
+ @Permittable(value = AcceptedTokenType.TENANT, groupId = PermittableGroupIds.IDENTIFICATIONS)
+ @RequestMapping(
+ value = "/customers/{identifier}/identifications/{number}/scans",
+ method = RequestMethod.GET,
+ produces = MediaType.APPLICATION_JSON_VALUE,
+ consumes = MediaType.ALL_VALUE
+ )
+ public
+ @ResponseBody
+ ResponseEntity<List<IdentificationCardScan>> fetchIdentificationCardScans(@PathVariable("identifier") final String identifier,
+ @PathVariable("number") final String number) {
+ this.throwIfCustomerNotExists(identifier);
+ this.throwIfIdentificationCardNotExists(number);
+
+ final List<IdentificationCardScan> identificationCardScans = this.customerService.fetchScansByIdentificationCard(number);
+
+ return ResponseEntity.ok(identificationCardScans);
+ }
+
+ @Permittable(value = AcceptedTokenType.TENANT, groupId = PermittableGroupIds.IDENTIFICATIONS)
+ @RequestMapping(
+ value = "/customers/{identifier}/identifications/{number}/scans/{scanIdentifier}",
+ method = RequestMethod.GET,
+ produces = MediaType.APPLICATION_JSON_VALUE,
+ consumes = MediaType.ALL_VALUE
+ )
+ public
+ @ResponseBody
+ ResponseEntity<IdentificationCardScan> findIdentificationCardScan(@PathVariable("identifier") final String identifier,
+ @PathVariable("number") final String number,
+ @PathVariable("scanIdentifier") final String scanIdentifier) {
+ this.throwIfCustomerNotExists(identifier);
+ this.throwIfIdentificationCardNotExists(number);
+
+ final Optional<IdentificationCardScan> identificationCardScan = this.customerService.findIdentificationCardScan(number, scanIdentifier);
+
+ return identificationCardScan
+ .map(ResponseEntity::ok)
+ .orElseThrow(() -> ServiceException.notFound("Identification card scan {0} not found.", number));
+ }
+
+ @Permittable(value = AcceptedTokenType.TENANT, groupId = PermittableGroupIds.IDENTIFICATIONS)
+ @RequestMapping(
+ value = "/customers/{identifier}/identifications/{number}/scans/{scanIdentifier}/image",
+ method = RequestMethod.GET,
+ produces = MediaType.APPLICATION_JSON_VALUE,
+ consumes = MediaType.ALL_VALUE
+ )
+ public
+ @ResponseBody
+ ResponseEntity<byte[]> fetchIdentificationCardScanImage(@PathVariable("identifier") final String identifier,
+ @PathVariable("number") final String number,
+ @PathVariable("scanIdentifier") final String scanIdentifier) {
+ this.throwIfCustomerNotExists(identifier);
+ this.throwIfIdentificationCardNotExists(number);
+ this.throwIfIdentificationCardScanNotExists(number, scanIdentifier);
+
+ final Optional<byte[]> image = this.customerService.findIdentificationCardScanImage(number, scanIdentifier);
+
+ return image.map(ResponseEntity::ok)
+ .orElseThrow(() -> ServiceException.notFound("Identification card scan {0} not found.", number));
+ }
+
+ @Permittable(value = AcceptedTokenType.TENANT, groupId = PermittableGroupIds.IDENTIFICATIONS)
+ @RequestMapping(
+ value = "/customers/{identifier}/identifications/{number}/scans",
+ produces = MediaType.APPLICATION_JSON_VALUE,
+ consumes = MediaType.MULTIPART_FORM_DATA_VALUE
+ )
+ public
+ @ResponseBody
+ ResponseEntity<Void> postIdentificationCardScan(@PathVariable("identifier") final String identifier,
+ @PathVariable("number") final String number,
+ @RequestParam("scanIdentifier") @ValidIdentifier final String scanIdentifier,
+ @RequestParam("description") @Size(max = 4096) final String description,
+ @RequestBody final MultipartFile image) throws Exception {
+ this.throwIfCustomerNotExists(identifier);
+ this.throwIfIdentificationCardNotExists(number);
+ this.throwIfInvalidSize(image.getSize());
+ this.throwIfInvalidContentType(image.getContentType());
+
+ if (this.customerService.identificationCardScanExists(number, scanIdentifier)) {
+ throw ServiceException.conflict("Scan {0} already exists.", scanIdentifier);
+ }
+
+ final IdentificationCardScan scan = new IdentificationCardScan();
+ scan.setIdentifier(scanIdentifier);
+ scan.setDescription(description);
+
+ this.commandGateway.process(new CreateIdentificationCardScanCommand(number, scan, image));
+
+ return ResponseEntity.accepted().build();
+ }
+
+ @Permittable(value = AcceptedTokenType.TENANT, groupId = PermittableGroupIds.IDENTIFICATIONS)
+ @RequestMapping(
+ value = "/customers/{identifier}/identifications/{number}/scans/{scanIdentifier}",
+ method = RequestMethod.DELETE,
+ produces = MediaType.APPLICATION_JSON_VALUE,
+ consumes = MediaType.ALL_VALUE
+ )
+ public
+ @ResponseBody
+ ResponseEntity<Void> deleteScan(@PathVariable("identifier") final String identifier,
+ @PathVariable("number") final String number,
+ @PathVariable("scanIdentifier") final String scanIdentifier) {
+ throwIfCustomerNotExists(identifier);
+ throwIfIdentificationCardNotExists(number);
+
+ this.commandGateway.process(new DeleteIdentificationCardScanCommand(number, scanIdentifier));
+
+ return ResponseEntity.accepted().build();
+ }
+
@Permittable(value = AcceptedTokenType.TENANT, groupId = PermittableGroupIds.PORTRAIT)
@RequestMapping(
value = "/customers/{identifier}/portrait",
@@ -486,17 +603,8 @@ public class CustomerRestController {
}
this.throwIfCustomerNotExists(identifier);
-
- final Long maxSize = this.environment.getProperty("upload.image.max-size", Long.class);
-
- if(portrait.getSize() > maxSize) {
- throw ServiceException.badRequest("Portrait can't exceed size of {0}", maxSize);
- }
-
- if(!portrait.getContentType().contains(MediaType.IMAGE_JPEG_VALUE)
- && !portrait.getContentType().contains(MediaType.IMAGE_PNG_VALUE)) {
- throw ServiceException.badRequest("Only content type {0} and {1} allowed", MediaType.IMAGE_JPEG_VALUE, MediaType.IMAGE_PNG_VALUE);
- }
+ this.throwIfInvalidSize(portrait.getSize());
+ this.throwIfInvalidContentType(portrait.getContentType());
try {
this.commandGateway.process(new DeletePortraitCommand(identifier), String.class).get();
@@ -628,4 +736,25 @@ public class CustomerRestController {
throw ServiceException.notFound("Identification card {0} not found.", number);
}
}
+
+ private void throwIfIdentificationCardScanNotExists(final String number, final String identifier) {
+ if (!this.customerService.identificationCardScanExists(number, identifier)) {
+ throw ServiceException.notFound("Identification card scan {0} not found.", identifier);
+ }
+ }
+
+ private void throwIfInvalidSize(final Long size) {
+ final Long maxSize = this.environment.getProperty("upload.image.max-size", Long.class);
+
+ if(size > maxSize) {
+ throw ServiceException.badRequest("Image can''t exceed size of {0}", maxSize);
+ }
+ }
+
+ private void throwIfInvalidContentType(final String contentType) {
+ if(!contentType.contains(MediaType.IMAGE_JPEG_VALUE)
+ && !contentType.contains(MediaType.IMAGE_PNG_VALUE)) {
+ throw ServiceException.badRequest("Only content type {0} and {1} allowed", MediaType.IMAGE_JPEG_VALUE, MediaType.IMAGE_PNG_VALUE);
+ }
+ }
}
diff --git a/service/src/main/resources/db/migrations/mariadb/V4__identification_card_scans.sql b/service/src/main/resources/db/migrations/mariadb/V4__identification_card_scans.sql
new file mode 100644
index 0000000..1a1b5e3
--- /dev/null
+++ b/service/src/main/resources/db/migrations/mariadb/V4__identification_card_scans.sql
@@ -0,0 +1,30 @@
+--
+-- Copyright 2017 The Mifos Initiative.
+--
+-- 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 maat_identification_card_scans (
+ id BIGINT NOT NULL AUTO_INCREMENT,
+ identifier VARCHAR(32) NOT NULL,
+ description VARCHAR(4096) NOT NULL,
+ identification_card_id BIGINT NOT NULL,
+ content_type VARCHAR(256) NOT NULL,
+ size BIGINT NOT NULL,
+ image MEDIUMBLOB NOT NULL,
+ created_on TIMESTAMP(3) NOT NULL,
+ created_by VARCHAR(32) NOT NULL,
+ CONSTRAINT maat_ident_card_scans_pk PRIMARY KEY (id),
+ CONSTRAINT maat_ident_card_scans_ident_uq UNIQUE (identifier, identification_card_id),
+ CONSTRAINT maat_ident_card_scans_fk FOREIGN KEY (identification_card_id) REFERENCES maat_identification_cards (id)
+);
\ No newline at end of file
--
To stop receiving notification emails like this one, please contact
myrle@apache.org.