You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@fineract.apache.org by ju...@apache.org on 2019/10/09 07:39:17 UTC
[fineract-cn-cheques] 03/41: added MICR resolution for on us cheques
This is an automated email from the ASF dual-hosted git repository.
juhan pushed a commit to branch develop
in repository https://gitbox.apache.org/repos/asf/fineract-cn-cheques.git
commit bad4be7333d76621370b669e3fd0261fe2ca7932
Author: mgeiss <mg...@mifos.org>
AuthorDate: Tue Aug 22 12:01:46 2017 +0200
added MICR resolution for on us cheques
---
.../mifos/cheque/api/v1/client/ChequeManager.java | 19 ++
.../client/DependingResourceNotValidException.java | 19 ++
.../v1/client/InvalidChequeNumberException.java | 19 ++
.../api/v1/{client => domain}/IssuingCount.java | 2 +-
.../mifos/cheque/api/v1/domain/MICRResolution.java | 42 ++++
.../src/main/java/io/mifos/cheque/TestCheques.java | 3 +-
.../java/io/mifos/cheque/TestIssuingCheques.java | 2 +-
.../src/main/java/io/mifos/cheque/TestMICR.java | 271 +++++++++++++++++++++
service/build.gradle | 1 +
.../mifos/cheque/service/ChequeConfiguration.java | 4 +-
.../service/internal/service/MICRService.java | 91 +++++++
.../internal/service/helper/AccountingService.java | 16 +-
...ganizationService.java => CustomerService.java} | 26 +-
.../internal/service/helper/DepositService.java | 10 +
.../service/helper/OrganizationService.java | 12 +-
.../cheque/service/rest/ChequeRestController.java | 2 +-
.../cheque/service/rest/MIRCRestController.java | 58 +++++
shared.gradle | 1 +
18 files changed, 571 insertions(+), 27 deletions(-)
diff --git a/api/src/main/java/io/mifos/cheque/api/v1/client/ChequeManager.java b/api/src/main/java/io/mifos/cheque/api/v1/client/ChequeManager.java
index 781793a..466d20d 100644
--- a/api/src/main/java/io/mifos/cheque/api/v1/client/ChequeManager.java
+++ b/api/src/main/java/io/mifos/cheque/api/v1/client/ChequeManager.java
@@ -18,8 +18,14 @@ package io.mifos.cheque.api.v1.client;
import io.mifos.cheque.api.v1.domain.Cheque;
import io.mifos.cheque.api.v1.domain.ChequeProcessingCommand;
import io.mifos.cheque.api.v1.domain.ChequeTransaction;
+import io.mifos.cheque.api.v1.domain.IssuingCount;
+import io.mifos.cheque.api.v1.domain.MICRResolution;
+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.api.util.NotFoundException;
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;
@@ -84,4 +90,17 @@ public interface ChequeManager {
consumes = {MediaType.APPLICATION_JSON_VALUE}
)
void process(@RequestBody @Valid final ChequeTransaction chequeTransaction);
+
+ @RequestMapping(
+ value = "/micr/{identifier}",
+ method = RequestMethod.GET,
+ produces = {MediaType.ALL_VALUE},
+ consumes = {MediaType.APPLICATION_JSON_VALUE}
+ )
+ @ThrowsExceptions({
+ @ThrowsException(status = HttpStatus.NOT_FOUND, exception = NotFoundException.class),
+ @ThrowsException(status = HttpStatus.CONFLICT, exception = InvalidChequeNumberException.class),
+ @ThrowsException(status = HttpStatus.BAD_REQUEST, exception = DependingResourceNotValidException.class)
+ })
+ MICRResolution expandMicr(@PathVariable("identifier") final String identifier);
}
diff --git a/api/src/main/java/io/mifos/cheque/api/v1/client/DependingResourceNotValidException.java b/api/src/main/java/io/mifos/cheque/api/v1/client/DependingResourceNotValidException.java
new file mode 100644
index 0000000..0c5d945
--- /dev/null
+++ b/api/src/main/java/io/mifos/cheque/api/v1/client/DependingResourceNotValidException.java
@@ -0,0 +1,19 @@
+/*
+ * Copyright 2017 Kuelap, Inc.
+ *
+ * All Rights Reserved.
+ *
+ * NOTICE: All information contained herein is, and remains
+ * the property of Kuelap, Inc and its suppliers, if any.
+ * The intellectual and technical concepts contained herein
+ * are proprietary to Kuelap, Inc and its suppliers and may
+ * be covered by U.S. and Foreign Patents, patents in process,
+ * and are protected by trade secret or copyright law.
+ * Dissemination of this information or reproduction of this material
+ * is strictly forbidden unless prior written permission is obtained
+ * Kuelap, Inc.
+ */
+package io.mifos.cheque.api.v1.client;
+
+public class DependingResourceNotValidException extends RuntimeException {
+}
diff --git a/api/src/main/java/io/mifos/cheque/api/v1/client/InvalidChequeNumberException.java b/api/src/main/java/io/mifos/cheque/api/v1/client/InvalidChequeNumberException.java
new file mode 100644
index 0000000..29084cf
--- /dev/null
+++ b/api/src/main/java/io/mifos/cheque/api/v1/client/InvalidChequeNumberException.java
@@ -0,0 +1,19 @@
+/*
+ * Copyright 2017 Kuelap, Inc.
+ *
+ * All Rights Reserved.
+ *
+ * NOTICE: All information contained herein is, and remains
+ * the property of Kuelap, Inc and its suppliers, if any.
+ * The intellectual and technical concepts contained herein
+ * are proprietary to Kuelap, Inc and its suppliers and may
+ * be covered by U.S. and Foreign Patents, patents in process,
+ * and are protected by trade secret or copyright law.
+ * Dissemination of this information or reproduction of this material
+ * is strictly forbidden unless prior written permission is obtained
+ * Kuelap, Inc.
+ */
+package io.mifos.cheque.api.v1.client;
+
+public class InvalidChequeNumberException extends RuntimeException {
+}
diff --git a/api/src/main/java/io/mifos/cheque/api/v1/client/IssuingCount.java b/api/src/main/java/io/mifos/cheque/api/v1/domain/IssuingCount.java
similarity index 97%
rename from api/src/main/java/io/mifos/cheque/api/v1/client/IssuingCount.java
rename to api/src/main/java/io/mifos/cheque/api/v1/domain/IssuingCount.java
index af37b0d..70a4f53 100644
--- a/api/src/main/java/io/mifos/cheque/api/v1/client/IssuingCount.java
+++ b/api/src/main/java/io/mifos/cheque/api/v1/domain/IssuingCount.java
@@ -13,7 +13,7 @@
* is strictly forbidden unless prior written permission is obtained
* Kuelap, Inc.
*/
-package io.mifos.cheque.api.v1.client;
+package io.mifos.cheque.api.v1.domain;
import javax.validation.constraints.Min;
import javax.validation.constraints.NotNull;
diff --git a/api/src/main/java/io/mifos/cheque/api/v1/domain/MICRResolution.java b/api/src/main/java/io/mifos/cheque/api/v1/domain/MICRResolution.java
new file mode 100644
index 0000000..21c2aae
--- /dev/null
+++ b/api/src/main/java/io/mifos/cheque/api/v1/domain/MICRResolution.java
@@ -0,0 +1,42 @@
+/*
+ * Copyright 2017 Kuelap, Inc.
+ *
+ * All Rights Reserved.
+ *
+ * NOTICE: All information contained herein is, and remains
+ * the property of Kuelap, Inc and its suppliers, if any.
+ * The intellectual and technical concepts contained herein
+ * are proprietary to Kuelap, Inc and its suppliers and may
+ * be covered by U.S. and Foreign Patents, patents in process,
+ * and are protected by trade secret or copyright law.
+ * Dissemination of this information or reproduction of this material
+ * is strictly forbidden unless prior written permission is obtained
+ * Kuelap, Inc.
+ */
+package io.mifos.cheque.api.v1.domain;
+
+public class MICRResolution {
+
+ private String office;
+ private String customer;
+
+ public MICRResolution() {
+ super();
+ }
+
+ public String getOffice() {
+ return this.office;
+ }
+
+ public void setOffice(final String office) {
+ this.office = office;
+ }
+
+ public String getCustomer() {
+ return this.customer;
+ }
+
+ public void setCustomer(final String customer) {
+ this.customer = customer;
+ }
+}
diff --git a/component-test/src/main/java/io/mifos/cheque/TestCheques.java b/component-test/src/main/java/io/mifos/cheque/TestCheques.java
index 78fd545..5ed5c14 100644
--- a/component-test/src/main/java/io/mifos/cheque/TestCheques.java
+++ b/component-test/src/main/java/io/mifos/cheque/TestCheques.java
@@ -20,11 +20,11 @@ import io.mifos.accounting.api.v1.domain.Creditor;
import io.mifos.accounting.api.v1.domain.Debtor;
import io.mifos.accounting.api.v1.domain.JournalEntry;
import io.mifos.cheque.api.v1.EventConstants;
-import io.mifos.cheque.api.v1.client.IssuingCount;
import io.mifos.cheque.api.v1.domain.Action;
import io.mifos.cheque.api.v1.domain.Cheque;
import io.mifos.cheque.api.v1.domain.ChequeProcessingCommand;
import io.mifos.cheque.api.v1.domain.ChequeTransaction;
+import io.mifos.cheque.api.v1.domain.IssuingCount;
import io.mifos.cheque.api.v1.domain.State;
import io.mifos.cheque.service.internal.format.MICRParser;
import io.mifos.cheque.service.internal.service.helper.AccountingService;
@@ -81,7 +81,6 @@ public class TestCheques extends AbstractChequeTest {
.doAnswer(invocation -> true)
.when(this.accountingServiceSpy).accountExists(randomCheque.getMicr().getAccountNumber());
-
final ChequeTransaction chequeTransaction = new ChequeTransaction();
chequeTransaction.setCheque(randomCheque);
chequeTransaction.setCreditorAccountNumber(RandomStringUtils.randomAlphanumeric(34));
diff --git a/component-test/src/main/java/io/mifos/cheque/TestIssuingCheques.java b/component-test/src/main/java/io/mifos/cheque/TestIssuingCheques.java
index 474ad4b..364636d 100644
--- a/component-test/src/main/java/io/mifos/cheque/TestIssuingCheques.java
+++ b/component-test/src/main/java/io/mifos/cheque/TestIssuingCheques.java
@@ -15,7 +15,7 @@
*/
package io.mifos.cheque;
-import io.mifos.cheque.api.v1.client.IssuingCount;
+import io.mifos.cheque.api.v1.domain.IssuingCount;
import io.mifos.cheque.service.internal.repository.IssuedChequeEntity;
import io.mifos.cheque.service.internal.repository.IssuedChequeRepository;
import io.mifos.cheque.service.internal.service.helper.AccountingService;
diff --git a/component-test/src/main/java/io/mifos/cheque/TestMICR.java b/component-test/src/main/java/io/mifos/cheque/TestMICR.java
new file mode 100644
index 0000000..cc50bae
--- /dev/null
+++ b/component-test/src/main/java/io/mifos/cheque/TestMICR.java
@@ -0,0 +1,271 @@
+/*
+ * Copyright 2017 Kuelap, Inc.
+ *
+ * All Rights Reserved.
+ *
+ * NOTICE: All information contained herein is, and remains
+ * the property of Kuelap, Inc and its suppliers, if any.
+ * The intellectual and technical concepts contained herein
+ * are proprietary to Kuelap, Inc and its suppliers and may
+ * be covered by U.S. and Foreign Patents, patents in process,
+ * and are protected by trade secret or copyright law.
+ * Dissemination of this information or reproduction of this material
+ * is strictly forbidden unless prior written permission is obtained
+ * Kuelap, Inc.
+ */
+package io.mifos.cheque;
+
+import io.mifos.cheque.api.v1.EventConstants;
+import io.mifos.cheque.api.v1.client.DependingResourceNotValidException;
+import io.mifos.cheque.api.v1.client.InvalidChequeNumberException;
+import io.mifos.cheque.api.v1.domain.Cheque;
+import io.mifos.cheque.api.v1.domain.ChequeTransaction;
+import io.mifos.cheque.api.v1.domain.IssuingCount;
+import io.mifos.cheque.api.v1.domain.MICR;
+import io.mifos.cheque.api.v1.domain.MICRResolution;
+import io.mifos.cheque.service.internal.format.MICRParser;
+import io.mifos.cheque.service.internal.service.helper.AccountingService;
+import io.mifos.cheque.service.internal.service.helper.CustomerService;
+import io.mifos.cheque.service.internal.service.helper.DepositService;
+import io.mifos.cheque.service.internal.service.helper.OrganizationService;
+import io.mifos.core.api.util.NotFoundException;
+import io.mifos.customer.api.v1.domain.Customer;
+import io.mifos.deposit.api.v1.instance.domain.ProductInstance;
+import io.mifos.office.api.v1.domain.Office;
+import org.apache.commons.lang3.RandomStringUtils;
+import org.junit.Assert;
+import org.junit.Test;
+import org.mockito.Mockito;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.boot.test.mock.mockito.MockBean;
+
+import java.util.Collections;
+import java.util.Optional;
+
+public class TestMICR extends AbstractChequeTest {
+
+ private static final String OFFICE_NAME = "Money Bin";
+ private static final String CUSTOMER_IDENTIFIER = "scrooge.mcduck";
+ private static final String GIVEN_NAME = "Scrooge";
+ private static final String SURNAME = "Mc Duck";
+
+ @MockBean
+ private OrganizationService organizationServiceSpy;
+
+ @MockBean
+ private DepositService depositServiceSpy;
+
+ @MockBean
+ private AccountingService accountingServiceSpy;
+
+ @MockBean
+ private CustomerService customerServiceSpy;
+
+ @Autowired
+ public TestMICR() {
+ super();
+ }
+
+ @Test
+ public void shouldReturnResolution() throws Exception {
+
+ final MICR micr = Fixture.createRandomCheque().getMicr();
+
+ Mockito
+ .doAnswer(invocation -> {
+ final Office mockedOffice = new Office();
+ mockedOffice.setName(TestMICR.OFFICE_NAME);
+ return Optional.of(mockedOffice);
+ })
+ .when(this.organizationServiceSpy).findOffice(micr.getBranchSortCode());
+
+ Mockito
+ .doAnswer(invocation -> {
+ final ProductInstance mockedProductInstance = new ProductInstance();
+ mockedProductInstance.setCustomerIdentifier(TestMICR.CUSTOMER_IDENTIFIER);
+ return Optional.of(mockedProductInstance);
+ })
+ .when(this.depositServiceSpy).findProductInstance(micr.getAccountNumber());
+
+ Mockito
+ .doAnswer(invocation -> Collections.emptyList())
+ .when(this.depositServiceSpy).getIssueChequeCharges(micr.getAccountNumber());
+
+ Mockito
+ .doAnswer(invocation -> {
+ final Customer mockedCustomer = new Customer();
+ mockedCustomer.setGivenName(TestMICR.GIVEN_NAME);
+ mockedCustomer.setSurname(TestMICR.SURNAME);
+ return Optional.of(mockedCustomer);
+ })
+ .when(this.customerServiceSpy).findCustomer(TestMICR.CUSTOMER_IDENTIFIER);
+
+ final IssuingCount issuingCount = new IssuingCount();
+ issuingCount.setAccountIdentifier(micr.getAccountNumber());
+ issuingCount.setAmount(100);
+
+ super.chequeManager.issue(issuingCount);
+
+ Assert.assertTrue(
+ super.eventRecorder.wait(EventConstants.ISSUE_CHEQUES, micr.getAccountNumber())
+ );
+
+ final MICRResolution micrResolution = super.chequeManager.expandMicr(MICRParser.toIdentifier(micr));
+ Assert.assertNotNull(micrResolution);
+ Assert.assertEquals(OFFICE_NAME, micrResolution.getOffice());
+ Assert.assertEquals(GIVEN_NAME + " " + SURNAME, micrResolution.getCustomer());
+ }
+
+ @Test(expected = NotFoundException.class)
+ public void shouldNotReturnResolutionNotOnUs() throws Exception {
+ final MICR micr = Fixture.createRandomCheque().getMicr();
+
+ Mockito
+ .doAnswer(invocation -> Optional.empty())
+ .when(this.organizationServiceSpy).findOffice(micr.getBranchSortCode());
+
+ super.chequeManager.expandMicr(MICRParser.toIdentifier(micr));
+ }
+
+ @Test(expected = InvalidChequeNumberException.class)
+ public void shouldNotReturnResolutionChequeAlreadyUsed() throws Exception {
+ final Cheque randomCheque = Fixture.createRandomCheque();
+ final MICR micr = randomCheque.getMicr();
+
+ final IssuingCount issuingCount = new IssuingCount();
+ issuingCount.setAccountIdentifier(micr.getAccountNumber());
+ issuingCount.setAmount(100);
+
+ super.chequeManager.issue(issuingCount);
+
+ Assert.assertTrue(
+ super.eventRecorder.wait(EventConstants.ISSUE_CHEQUES, micr.getAccountNumber())
+ );
+
+ Mockito
+ .doAnswer(invocation -> true)
+ .when(this.organizationServiceSpy).officeExistsByBranchSortCode(randomCheque.getMicr().getBranchSortCode());
+
+ Mockito
+ .doAnswer(invocation -> true)
+ .when(this.accountingServiceSpy).accountExists(randomCheque.getMicr().getAccountNumber());
+
+ final ChequeTransaction chequeTransaction = new ChequeTransaction();
+ chequeTransaction.setCheque(randomCheque);
+ chequeTransaction.setCreditorAccountNumber(RandomStringUtils.randomAlphanumeric(34));
+ super.chequeManager.process(chequeTransaction);
+
+ Assert.assertTrue(
+ super.eventRecorder.wait(EventConstants.CHEQUE_TRANSACTION, MICRParser.toIdentifier(randomCheque.getMicr()))
+ );
+
+ super.chequeManager.expandMicr(MICRParser.toIdentifier(micr));
+ }
+
+ @Test(expected = InvalidChequeNumberException.class)
+ public void shouldNotReturnResolutionChequeNotIssued() throws Exception {
+ final MICR micr = Fixture.createRandomCheque().getMicr();
+
+ Mockito
+ .doAnswer(invocation -> {
+ final Office mockedOffice = new Office();
+ mockedOffice.setName(TestMICR.OFFICE_NAME);
+ return Optional.of(mockedOffice);
+ })
+ .when(this.organizationServiceSpy).findOffice(micr.getBranchSortCode());
+
+ super.chequeManager.expandMicr(MICRParser.toIdentifier(micr));
+ }
+
+ @Test(expected = InvalidChequeNumberException.class)
+ public void shouldNotReturnResolutionUnknownChequeNumber() throws Exception {
+ final MICR micr = Fixture.createRandomCheque().getMicr();
+ micr.setChequeNumber("0815");
+
+ final IssuingCount issuingCount = new IssuingCount();
+ issuingCount.setAccountIdentifier(micr.getAccountNumber());
+ issuingCount.setAmount(100);
+
+ super.chequeManager.issue(issuingCount);
+
+ Assert.assertTrue(
+ super.eventRecorder.wait(EventConstants.ISSUE_CHEQUES, micr.getAccountNumber())
+ );
+
+ Mockito
+ .doAnswer(invocation -> {
+ final Office mockedOffice = new Office();
+ mockedOffice.setName(TestMICR.OFFICE_NAME);
+ return Optional.of(mockedOffice);
+ })
+ .when(this.organizationServiceSpy).findOffice(micr.getBranchSortCode());
+
+ super.chequeManager.expandMicr(MICRParser.toIdentifier(micr));
+ }
+
+ @Test(expected = DependingResourceNotValidException.class)
+ public void shouldNotReturnResolutionUnknownAccount() throws Exception {
+ final MICR micr = Fixture.createRandomCheque().getMicr();
+
+ Mockito
+ .doAnswer(invocation -> {
+ final Office mockedOffice = new Office();
+ mockedOffice.setName(TestMICR.OFFICE_NAME);
+ return Optional.of(mockedOffice);
+ })
+ .when(this.organizationServiceSpy).findOffice(micr.getBranchSortCode());
+
+ Mockito
+ .doAnswer(invocation -> Optional.empty())
+ .when(this.depositServiceSpy).findProductInstance(micr.getAccountNumber());
+
+ final IssuingCount issuingCount = new IssuingCount();
+ issuingCount.setAccountIdentifier(micr.getAccountNumber());
+ issuingCount.setAmount(100);
+
+ super.chequeManager.issue(issuingCount);
+
+ Assert.assertTrue(
+ super.eventRecorder.wait(EventConstants.ISSUE_CHEQUES, micr.getAccountNumber())
+ );
+
+ super.chequeManager.expandMicr(MICRParser.toIdentifier(micr));
+ }
+
+ @Test(expected = DependingResourceNotValidException.class)
+ public void shouldNotReturnResolutionUnknownCustomer() throws Exception {
+ final MICR micr = Fixture.createRandomCheque().getMicr();
+
+ Mockito
+ .doAnswer(invocation -> {
+ final Office mockedOffice = new Office();
+ mockedOffice.setName(TestMICR.OFFICE_NAME);
+ return Optional.of(mockedOffice);
+ })
+ .when(this.organizationServiceSpy).findOffice(micr.getBranchSortCode());
+
+ Mockito
+ .doAnswer(invocation -> {
+ final ProductInstance mockedProductInstance = new ProductInstance();
+ mockedProductInstance.setCustomerIdentifier(TestMICR.CUSTOMER_IDENTIFIER);
+ return Optional.of(mockedProductInstance);
+ })
+ .when(this.depositServiceSpy).findProductInstance(micr.getAccountNumber());
+
+ Mockito
+ .doAnswer(invocation -> Optional.empty())
+ .when(this.customerServiceSpy).findCustomer(TestMICR.CUSTOMER_IDENTIFIER);
+
+ final IssuingCount issuingCount = new IssuingCount();
+ issuingCount.setAccountIdentifier(micr.getAccountNumber());
+ issuingCount.setAmount(100);
+
+ super.chequeManager.issue(issuingCount);
+
+ Assert.assertTrue(
+ super.eventRecorder.wait(EventConstants.ISSUE_CHEQUES, micr.getAccountNumber())
+ );
+
+ super.chequeManager.expandMicr(MICRParser.toIdentifier(micr));
+ }
+}
diff --git a/service/build.gradle b/service/build.gradle
index af26fc0..234e970 100644
--- a/service/build.gradle
+++ b/service/build.gradle
@@ -35,6 +35,7 @@ dependencies {
[group: 'io.mifos.accounting', name: 'api', version: versions.frameworkaccounting],
[group: 'io.mifos.deposit-account-management', name: 'api', version: versions.frameworkdeposit],
[group: 'io.mifos.office', name: 'api', version: versions.frameworkoffice],
+ [group: 'io.mifos.customer', name: 'api', version: versions.frameworkcustomer],
[group: 'com.google.code.gson', name: 'gson'],
[group: 'io.mifos.core', name: 'lang', version: versions.frameworklang],
[group: 'io.mifos.core', name: 'async', version: versions.frameworkasync],
diff --git a/service/src/main/java/io/mifos/cheque/service/ChequeConfiguration.java b/service/src/main/java/io/mifos/cheque/service/ChequeConfiguration.java
index f1f0570..9e9919c 100644
--- a/service/src/main/java/io/mifos/cheque/service/ChequeConfiguration.java
+++ b/service/src/main/java/io/mifos/cheque/service/ChequeConfiguration.java
@@ -23,6 +23,7 @@ import io.mifos.core.command.config.EnableCommandProcessing;
import io.mifos.core.lang.config.EnableServiceException;
import io.mifos.core.lang.config.EnableTenantContext;
import io.mifos.core.mariadb.config.EnableMariaDB;
+import io.mifos.customer.api.v1.client.CustomerManager;
import io.mifos.deposit.api.v1.client.DepositAccountManager;
import io.mifos.office.api.v1.client.OrganizationManager;
import org.slf4j.Logger;
@@ -52,7 +53,8 @@ import org.springframework.web.servlet.config.annotation.WebMvcConfigurerAdapter
clients = {
LedgerManager.class,
DepositAccountManager.class,
- OrganizationManager.class
+ OrganizationManager.class,
+ CustomerManager.class
}
)
@ComponentScan({
diff --git a/service/src/main/java/io/mifos/cheque/service/internal/service/MICRService.java b/service/src/main/java/io/mifos/cheque/service/internal/service/MICRService.java
new file mode 100644
index 0000000..4bd3351
--- /dev/null
+++ b/service/src/main/java/io/mifos/cheque/service/internal/service/MICRService.java
@@ -0,0 +1,91 @@
+/*
+ * Copyright 2017 Kuelap, Inc.
+ *
+ * All Rights Reserved.
+ *
+ * NOTICE: All information contained herein is, and remains
+ * the property of Kuelap, Inc and its suppliers, if any.
+ * The intellectual and technical concepts contained herein
+ * are proprietary to Kuelap, Inc and its suppliers and may
+ * be covered by U.S. and Foreign Patents, patents in process,
+ * and are protected by trade secret or copyright law.
+ * Dissemination of this information or reproduction of this material
+ * is strictly forbidden unless prior written permission is obtained
+ * Kuelap, Inc.
+ */
+package io.mifos.cheque.service.internal.service;
+
+import io.mifos.cheque.api.v1.domain.MICR;
+import io.mifos.cheque.api.v1.domain.MICRResolution;
+import io.mifos.cheque.service.ServiceConstants;
+import io.mifos.cheque.service.internal.repository.IssuedChequeEntity;
+import io.mifos.cheque.service.internal.repository.IssuedChequeRepository;
+import io.mifos.cheque.service.internal.service.helper.CustomerService;
+import io.mifos.cheque.service.internal.service.helper.DepositService;
+import io.mifos.cheque.service.internal.service.helper.OrganizationService;
+import io.mifos.core.lang.ServiceException;
+import io.mifos.customer.api.v1.domain.Customer;
+import io.mifos.deposit.api.v1.instance.domain.ProductInstance;
+import io.mifos.office.api.v1.domain.Office;
+import org.slf4j.Logger;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.beans.factory.annotation.Qualifier;
+import org.springframework.stereotype.Service;
+
+@Service
+public class MICRService {
+
+ private final Logger logger;
+ private final ChequeService chequeService;
+ private final OrganizationService organizationService;
+ private final DepositService depositService;
+ private final CustomerService customerService;
+ private final IssuedChequeRepository issuedChequeRepository;
+
+ @Autowired
+ public MICRService(@Qualifier(ServiceConstants.LOGGER_NAME) final Logger logger,
+ final ChequeService chequeService,
+ final OrganizationService organizationService,
+ final DepositService depositService,
+ final CustomerService customerService,
+ final IssuedChequeRepository issuedChequeRepository) {
+ super();
+ this.logger = logger;
+ this.chequeService = chequeService;
+ this.organizationService = organizationService;
+ this.depositService = depositService;
+ this.customerService = customerService;
+ this.issuedChequeRepository = issuedChequeRepository;
+ }
+
+ public MICRResolution expand(final MICR micr) {
+
+ if (this.chequeService.findBy(micr).isPresent()) {
+ throw ServiceException.conflict("Cheque already used.");
+ }
+
+ final Office office =
+ this.organizationService.findOffice(micr.getBranchSortCode())
+ .orElseThrow(() -> ServiceException.notFound("Given MICR is unknown."));
+
+ final IssuedChequeEntity issuedChequeEntity =
+ this.issuedChequeRepository.findByAccountIdentifier(micr.getAccountNumber())
+ .orElseThrow(() -> ServiceException.conflict("Cheque was never issued."));
+ if (Integer.valueOf(micr.getChequeNumber()) > issuedChequeEntity.getLastIssuedNumber()) {
+ throw ServiceException.conflict("Cheque number invalid.");
+ }
+
+ final ProductInstance productInstance =
+ this.depositService.findProductInstance(micr.getAccountNumber())
+ .orElseThrow(() -> ServiceException.badRequest("Given account not valid."));
+
+ final Customer customer =
+ this.customerService.findCustomer(productInstance.getCustomerIdentifier())
+ .orElseThrow(() -> ServiceException.badRequest("Given customer not valid."));
+
+ final MICRResolution micrResolution = new MICRResolution();
+ micrResolution.setOffice(office.getName());
+ micrResolution.setCustomer(customer.getGivenName() + " " + customer.getSurname());
+ return micrResolution;
+ }
+}
diff --git a/service/src/main/java/io/mifos/cheque/service/internal/service/helper/AccountingService.java b/service/src/main/java/io/mifos/cheque/service/internal/service/helper/AccountingService.java
index 95ef589..4667c04 100644
--- a/service/src/main/java/io/mifos/cheque/service/internal/service/helper/AccountingService.java
+++ b/service/src/main/java/io/mifos/cheque/service/internal/service/helper/AccountingService.java
@@ -35,6 +35,7 @@ import org.springframework.stereotype.Service;
import java.time.Clock;
import java.time.LocalDateTime;
import java.util.List;
+import java.util.Optional;
import java.util.UUID;
import java.util.stream.Collectors;
@@ -99,12 +100,7 @@ public class AccountingService {
}
public boolean accountExists(final String accountIdentifier) {
- try {
- this.ledgerManager.findAccount(accountIdentifier);
- return true;
- } catch (final AccountNotFoundException anfex) {
- return false;
- }
+ return this.findAccount(accountIdentifier).isPresent();
}
public JournalEntry findJournalEntry(final String identifier) {
@@ -114,4 +110,12 @@ public class AccountingService {
public void processJournalEntry(final JournalEntry journalEntry) {
this.ledgerManager.createJournalEntry(journalEntry);
}
+
+ public Optional<Account> findAccount(final String accountNumber) {
+ try {
+ return Optional.of(this.ledgerManager.findAccount(accountNumber));
+ } catch (final AccountNotFoundException anfex) {
+ return Optional.empty();
+ }
+ }
}
diff --git a/service/src/main/java/io/mifos/cheque/service/internal/service/helper/OrganizationService.java b/service/src/main/java/io/mifos/cheque/service/internal/service/helper/CustomerService.java
similarity index 58%
copy from service/src/main/java/io/mifos/cheque/service/internal/service/helper/OrganizationService.java
copy to service/src/main/java/io/mifos/cheque/service/internal/service/helper/CustomerService.java
index f8e857a..3bfebcd 100644
--- a/service/src/main/java/io/mifos/cheque/service/internal/service/helper/OrganizationService.java
+++ b/service/src/main/java/io/mifos/cheque/service/internal/service/helper/CustomerService.java
@@ -16,33 +16,35 @@
package io.mifos.cheque.service.internal.service.helper;
import io.mifos.cheque.service.ServiceConstants;
-import io.mifos.office.api.v1.client.NotFoundException;
-import io.mifos.office.api.v1.client.OrganizationManager;
+import io.mifos.customer.api.v1.client.CustomerManager;
+import io.mifos.customer.api.v1.client.CustomerNotFoundException;
+import io.mifos.customer.api.v1.domain.Customer;
import org.slf4j.Logger;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Qualifier;
import org.springframework.stereotype.Service;
+import java.util.Optional;
+
@Service
-public class OrganizationService {
+public class CustomerService {
private final Logger logger;
- private final OrganizationManager organizationManager;
+ private final CustomerManager customerManager;
@Autowired
- public OrganizationService(@Qualifier(ServiceConstants.LOGGER_NAME) final Logger logger,
- final OrganizationManager organizationManager) {
+ public CustomerService(@Qualifier(ServiceConstants.LOGGER_NAME) final Logger logger,
+ final CustomerManager customerManager) {
super();
this.logger = logger;
- this.organizationManager = organizationManager;
+ this.customerManager = customerManager;
}
- public boolean officeExistsByBranchSortCode(final String branchSortCode) {
+ public Optional<Customer> findCustomer(final String identifier) {
try {
- this.organizationManager.findOfficeByIdentifier(branchSortCode);
- return true;
- } catch (final NotFoundException nfex) {
- return false;
+ return Optional.of(this.customerManager.findCustomer(identifier));
+ } catch (final CustomerNotFoundException cnfex) {
+ return Optional.empty();
}
}
}
diff --git a/service/src/main/java/io/mifos/cheque/service/internal/service/helper/DepositService.java b/service/src/main/java/io/mifos/cheque/service/internal/service/helper/DepositService.java
index 7047bf8..0ff8257 100644
--- a/service/src/main/java/io/mifos/cheque/service/internal/service/helper/DepositService.java
+++ b/service/src/main/java/io/mifos/cheque/service/internal/service/helper/DepositService.java
@@ -20,6 +20,7 @@ import io.mifos.deposit.api.v1.client.DepositAccountManager;
import io.mifos.deposit.api.v1.definition.domain.Action;
import io.mifos.deposit.api.v1.definition.domain.Charge;
import io.mifos.deposit.api.v1.definition.domain.ProductDefinition;
+import io.mifos.deposit.api.v1.instance.ProductInstanceNotFoundException;
import io.mifos.deposit.api.v1.instance.domain.ProductInstance;
import org.slf4j.Logger;
import org.springframework.beans.factory.annotation.Autowired;
@@ -27,6 +28,7 @@ import org.springframework.beans.factory.annotation.Qualifier;
import org.springframework.stereotype.Service;
import java.util.List;
+import java.util.Optional;
import java.util.stream.Collectors;
@Service
@@ -75,4 +77,12 @@ public class DepositService {
return productDefinition.getCashAccountIdentifier();
}
+
+ public Optional<ProductInstance> findProductInstance(final String accountNumber) {
+ try {
+ return Optional.of(this.depositAccountManager.findProductInstance(accountNumber));
+ } catch (final ProductInstanceNotFoundException pinfex) {
+ return Optional.empty();
+ }
+ }
}
diff --git a/service/src/main/java/io/mifos/cheque/service/internal/service/helper/OrganizationService.java b/service/src/main/java/io/mifos/cheque/service/internal/service/helper/OrganizationService.java
index f8e857a..4a11088 100644
--- a/service/src/main/java/io/mifos/cheque/service/internal/service/helper/OrganizationService.java
+++ b/service/src/main/java/io/mifos/cheque/service/internal/service/helper/OrganizationService.java
@@ -18,11 +18,14 @@ package io.mifos.cheque.service.internal.service.helper;
import io.mifos.cheque.service.ServiceConstants;
import io.mifos.office.api.v1.client.NotFoundException;
import io.mifos.office.api.v1.client.OrganizationManager;
+import io.mifos.office.api.v1.domain.Office;
import org.slf4j.Logger;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Qualifier;
import org.springframework.stereotype.Service;
+import java.util.Optional;
+
@Service
public class OrganizationService {
@@ -38,11 +41,14 @@ public class OrganizationService {
}
public boolean officeExistsByBranchSortCode(final String branchSortCode) {
+ return this.findOffice(branchSortCode).isPresent();
+ }
+
+ public Optional<Office> findOffice(final String branchSortCode) {
try {
- this.organizationManager.findOfficeByIdentifier(branchSortCode);
- return true;
+ return Optional.of(this.organizationManager.findOfficeByIdentifier(branchSortCode));
} catch (final NotFoundException nfex) {
- return false;
+ return Optional.empty();
}
}
}
diff --git a/service/src/main/java/io/mifos/cheque/service/rest/ChequeRestController.java b/service/src/main/java/io/mifos/cheque/service/rest/ChequeRestController.java
index 7f9414f..007e383 100644
--- a/service/src/main/java/io/mifos/cheque/service/rest/ChequeRestController.java
+++ b/service/src/main/java/io/mifos/cheque/service/rest/ChequeRestController.java
@@ -18,10 +18,10 @@ package io.mifos.cheque.service.rest;
import io.mifos.anubis.annotation.AcceptedTokenType;
import io.mifos.anubis.annotation.Permittable;
import io.mifos.cheque.api.v1.PermittableGroupIds;
-import io.mifos.cheque.api.v1.client.IssuingCount;
import io.mifos.cheque.api.v1.domain.Action;
import io.mifos.cheque.api.v1.domain.Cheque;
import io.mifos.cheque.api.v1.domain.ChequeProcessingCommand;
+import io.mifos.cheque.api.v1.domain.IssuingCount;
import io.mifos.cheque.service.ServiceConstants;
import io.mifos.cheque.service.internal.command.ApproveChequeTransactionCommand;
import io.mifos.cheque.service.internal.command.CancelChequeTransactionCommand;
diff --git a/service/src/main/java/io/mifos/cheque/service/rest/MIRCRestController.java b/service/src/main/java/io/mifos/cheque/service/rest/MIRCRestController.java
new file mode 100644
index 0000000..8b56e73
--- /dev/null
+++ b/service/src/main/java/io/mifos/cheque/service/rest/MIRCRestController.java
@@ -0,0 +1,58 @@
+/*
+ * Copyright 2017 Kuelap, Inc.
+ *
+ * All Rights Reserved.
+ *
+ * NOTICE: All information contained herein is, and remains
+ * the property of Kuelap, Inc and its suppliers, if any.
+ * The intellectual and technical concepts contained herein
+ * are proprietary to Kuelap, Inc and its suppliers and may
+ * be covered by U.S. and Foreign Patents, patents in process,
+ * and are protected by trade secret or copyright law.
+ * Dissemination of this information or reproduction of this material
+ * is strictly forbidden unless prior written permission is obtained
+ * Kuelap, Inc.
+ */
+package io.mifos.cheque.service.rest;
+
+import io.mifos.cheque.api.v1.domain.MICRResolution;
+import io.mifos.cheque.service.ServiceConstants;
+import io.mifos.cheque.service.internal.format.MICRParser;
+import io.mifos.cheque.service.internal.service.MICRService;
+import org.slf4j.Logger;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.beans.factory.annotation.Qualifier;
+import org.springframework.http.MediaType;
+import org.springframework.http.ResponseEntity;
+import org.springframework.web.bind.annotation.PathVariable;
+import org.springframework.web.bind.annotation.RequestMapping;
+import org.springframework.web.bind.annotation.RequestMethod;
+import org.springframework.web.bind.annotation.ResponseBody;
+import org.springframework.web.bind.annotation.RestController;
+
+@RestController
+@RequestMapping("/micr")
+public class MIRCRestController {
+
+ private final Logger logger;
+ private final MICRService micrService;
+
+ @Autowired
+ public MIRCRestController(@Qualifier(ServiceConstants.LOGGER_NAME) final Logger logger,
+ final MICRService micrService) {
+ super();
+ this.logger = logger;
+ this.micrService = micrService;
+ }
+
+ @RequestMapping(
+ value = "/{identifier}",
+ method = RequestMethod.GET,
+ produces = {MediaType.APPLICATION_JSON_VALUE},
+ consumes = {MediaType.ALL_VALUE}
+ )
+ @ResponseBody
+ ResponseEntity<MICRResolution> expandMicr(@PathVariable("identifier") final String identifier) {
+ return ResponseEntity.ok(this.micrService.expand(MICRParser.fromIdentifier(identifier)));
+ }
+}
diff --git a/shared.gradle b/shared.gradle
index 53a6aa4..bddedf5 100644
--- a/shared.gradle
+++ b/shared.gradle
@@ -13,6 +13,7 @@ ext.versions = [
frameworkoffice : '0.1.0-BUILD-SNAPSHOT',
frameworkaccounting: '0.1.0-BUILD-SNAPSHOT',
frameworkdeposit : '0.1.0-BUILD-SNAPSHOT',
+ frameworkcustomer : '0.1.0-BUILD-SNAPSHOT',
validator : '5.3.0.Final'
]