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:31:58 UTC

[fineract-cn-teller] branch develop created (now a0abc61)

This is an automated email from the ASF dual-hosted git repository.

myrle pushed a change to branch develop
in repository https://gitbox.apache.org/repos/asf/fineract-cn-teller.git.


      at a0abc61  Removing duplicate resource files from jar.

This branch includes the following new commits:

     new 2d306fc  initial commit
     new 480ddbd  edited readme
     new d66dbe2  edited during review
     new 55ce69b  first iteration for teller management
     new c3a63e3  replaced dot with dash in version number
     new c851ae0  refactored default date range
     new 52d94ef  use today of last modified is not available
     new d1e78ab  added NONE for adjustment
     new 0230a24  added teller transaction handling
     new 2d7e458  retrofitted password field
     new 7ca53ac  retrofitted drawer unlock
     new b4bfdc1  fixed missing customer identifier
     new abdb227  fixed missing debtor in tx processing
     new 94c898e  fixed command type for activation and closing of product instances
     new 1060664  changed transaction types
     new e8a0e97  throw 400 if teller is closed while unlocking
     new d898f75  fixed bug when no charges are applied
     new 8af6853  added TX type as message to journal entry
     new 71839a1  added verification for balance and cash draw limit
     new c536d83  returning teller after unlock
     new 733149b  refactored to add more clarity
     new 23688fb  check if employee is already assigned
     new bc87486  fixed new return type for charges list to set
     new 4da5edd  added account state validation before any transaction added ability to include charges in cash received
     new 2cc1c5c  fixed equal for account stats
     new 1cad446  Fixing (most of) the teller operation test so that I can be sure my changes aren't causing the failures.
     new 41ac0e1  Fixing compile error caused by my changes to the signature of accounting.
     new 5b3e4cc  Introduced a TestSuite to make running all component-tests a hands-free process.
     new 519386a  Fixed query.
     new a0abc61  Removing duplicate resource files from jar.

The 30 revisions listed above as "new" are entirely new to this
repository and will be described in separate emails.  The revisions
listed as "add" were already present in the repository and have only
been added to this reference.


-- 
To stop receiving notification emails like this one, please contact
myrle@apache.org.

[fineract-cn-teller] 11/30: retrofitted drawer unlock

Posted by my...@apache.org.
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-teller.git

commit 7ca53ac6aa05d837dd43a2bd7382017f01436906
Author: mgeiss <mg...@mifos.org>
AuthorDate: Wed Jun 14 14:10:34 2017 +0200

    retrofitted drawer unlock
---
 .../mifos/teller/api/v1/client/TellerManager.java  |  8 +--
 ...uthentication.java => UnlockDrawerCommand.java} |  4 +-
 .../java/io/mifos/teller/TestTellerOperation.java  | 76 +++++++++++-----------
 ...TellerCommand.java => DrawerUnlockCommand.java} | 14 ++--
 .../internal/command/handler/TellerAggregate.java  | 15 ++---
 .../rest/TellerOperationRestController.java        | 23 ++++---
 service/src/main/resources/logback.xml             | 55 ++++++++++++++++
 7 files changed, 125 insertions(+), 70 deletions(-)

diff --git a/api/src/main/java/io/mifos/teller/api/v1/client/TellerManager.java b/api/src/main/java/io/mifos/teller/api/v1/client/TellerManager.java
index 18d5f55..3f3a9b2 100644
--- a/api/src/main/java/io/mifos/teller/api/v1/client/TellerManager.java
+++ b/api/src/main/java/io/mifos/teller/api/v1/client/TellerManager.java
@@ -19,7 +19,7 @@ import io.mifos.core.api.annotation.ThrowsException;
 import io.mifos.core.api.annotation.ThrowsExceptions;
 import io.mifos.core.api.util.CustomFeignClientsConfiguration;
 import io.mifos.teller.api.v1.domain.Teller;
-import io.mifos.teller.api.v1.domain.TellerAuthentication;
+import io.mifos.teller.api.v1.domain.UnlockDrawerCommand;
 import io.mifos.teller.api.v1.domain.TellerBalanceSheet;
 import io.mifos.teller.api.v1.domain.TellerManagementCommand;
 import io.mifos.teller.api.v1.domain.TellerTransaction;
@@ -118,7 +118,7 @@ public interface TellerManager {
                                 @PathVariable("tellerCode") final String tellerCode);
 
   @RequestMapping(
-      value = "/teller/{tellerCode}/auth",
+      value = "/teller/{tellerCode}/drawer",
       method = RequestMethod.POST,
       consumes = MediaType.APPLICATION_JSON_VALUE,
       produces = MediaType.APPLICATION_JSON_VALUE
@@ -128,8 +128,8 @@ public interface TellerManager {
       @ThrowsException(status = HttpStatus.BAD_REQUEST, exception = TellerNotFoundException.class),
       @ThrowsException(status = HttpStatus.CONFLICT, exception = TellerNotFoundException.class)
   })
-  String auth(@PathVariable("tellerCode") final String tellerCode,
-            @RequestBody @Valid final TellerAuthentication tellerAuthentication);
+  void unlockDrawer(@PathVariable("tellerCode") final String tellerCode,
+                    @RequestBody @Valid final UnlockDrawerCommand unlockDrawerCommand);
 
   @RequestMapping(
       value = "/teller/{tellerCode}",
diff --git a/api/src/main/java/io/mifos/teller/api/v1/domain/TellerAuthentication.java b/api/src/main/java/io/mifos/teller/api/v1/domain/UnlockDrawerCommand.java
similarity index 93%
rename from api/src/main/java/io/mifos/teller/api/v1/domain/TellerAuthentication.java
rename to api/src/main/java/io/mifos/teller/api/v1/domain/UnlockDrawerCommand.java
index 60bc7fd..afb42df 100644
--- a/api/src/main/java/io/mifos/teller/api/v1/domain/TellerAuthentication.java
+++ b/api/src/main/java/io/mifos/teller/api/v1/domain/UnlockDrawerCommand.java
@@ -15,12 +15,12 @@
  */
 package io.mifos.teller.api.v1.domain;
 
-public class TellerAuthentication {
+public class UnlockDrawerCommand {
 
   private String employeeIdentifier;
   private String password;
 
-  public TellerAuthentication() {
+  public UnlockDrawerCommand() {
     super();
   }
 
diff --git a/component-test/src/main/java/io/mifos/teller/TestTellerOperation.java b/component-test/src/main/java/io/mifos/teller/TestTellerOperation.java
index 1c6edd7..95b1774 100644
--- a/component-test/src/main/java/io/mifos/teller/TestTellerOperation.java
+++ b/component-test/src/main/java/io/mifos/teller/TestTellerOperation.java
@@ -20,7 +20,7 @@ import io.mifos.teller.api.v1.EventConstants;
 import io.mifos.teller.api.v1.client.TellerNotFoundException;
 import io.mifos.teller.api.v1.client.TellerValidationException;
 import io.mifos.teller.api.v1.domain.Teller;
-import io.mifos.teller.api.v1.domain.TellerAuthentication;
+import io.mifos.teller.api.v1.domain.UnlockDrawerCommand;
 import io.mifos.teller.api.v1.domain.TellerManagementCommand;
 import io.mifos.teller.api.v1.domain.TellerTransaction;
 import io.mifos.teller.util.TellerGenerator;
@@ -44,13 +44,11 @@ public class TestTellerOperation extends AbstractTellerTest {
   public void shouldAuthenticate() throws Exception {
     final Teller teller = this.prepareTeller();
 
-    final TellerAuthentication tellerAuthentication = new TellerAuthentication();
-    tellerAuthentication.setEmployeeIdentifier(AbstractTellerTest.TEST_USER);
-    tellerAuthentication.setPassword(teller.getPassword());
+    final UnlockDrawerCommand unlockDrawerCommand = new UnlockDrawerCommand();
+    unlockDrawerCommand.setEmployeeIdentifier(AbstractTellerTest.TEST_USER);
+    unlockDrawerCommand.setPassword(teller.getPassword());
 
-    final String auth = super.testSubject.auth(teller.getCode(), tellerAuthentication);
-
-    Assert.assertEquals(auth, teller.getCode());
+    super.testSubject.unlockDrawer(teller.getCode(), unlockDrawerCommand);
   }
 
 
@@ -58,33 +56,33 @@ public class TestTellerOperation extends AbstractTellerTest {
   public void shouldNotAuthenticateUserMismatch() throws Exception {
     final Teller teller = this.prepareTeller();
 
-    final TellerAuthentication tellerAuthentication = new TellerAuthentication();
-    tellerAuthentication.setEmployeeIdentifier("unassigneduser");
-    tellerAuthentication.setPassword(teller.getPassword());
+    final UnlockDrawerCommand unlockDrawerCommand = new UnlockDrawerCommand();
+    unlockDrawerCommand.setEmployeeIdentifier("unassigneduser");
+    unlockDrawerCommand.setPassword(teller.getPassword());
 
-    super.testSubject.auth(teller.getCode(), tellerAuthentication);
+    super.testSubject.unlockDrawer(teller.getCode(), unlockDrawerCommand);
   }
 
   @Test(expected = TellerNotFoundException.class)
   public void shouldNotAuthenticatePasswordMismatch() throws Exception {
     final Teller teller = this.prepareTeller();
 
-    final TellerAuthentication tellerAuthentication = new TellerAuthentication();
-    tellerAuthentication.setEmployeeIdentifier(AbstractTellerTest.TEST_USER);
-    tellerAuthentication.setPassword("wrongpasword");
+    final UnlockDrawerCommand unlockDrawerCommand = new UnlockDrawerCommand();
+    unlockDrawerCommand.setEmployeeIdentifier(AbstractTellerTest.TEST_USER);
+    unlockDrawerCommand.setPassword("wrongpasword");
 
-    super.testSubject.auth(teller.getCode(), tellerAuthentication);
+    super.testSubject.unlockDrawer(teller.getCode(), unlockDrawerCommand);
   }
 
   @Test
   public void shouldPauseTeller() throws Exception {
     final Teller teller = this.prepareTeller();
 
-    final TellerAuthentication tellerAuthentication = new TellerAuthentication();
-    tellerAuthentication.setEmployeeIdentifier(AbstractTellerTest.TEST_USER);
-    tellerAuthentication.setPassword(teller.getPassword());
+    final UnlockDrawerCommand unlockDrawerCommand = new UnlockDrawerCommand();
+    unlockDrawerCommand.setEmployeeIdentifier(AbstractTellerTest.TEST_USER);
+    unlockDrawerCommand.setPassword(teller.getPassword());
 
-    super.testSubject.auth(teller.getCode(), tellerAuthentication);
+    super.testSubject.unlockDrawer(teller.getCode(), unlockDrawerCommand);
 
     super.eventRecorder.wait(EventConstants.AUTHENTICATE_TELLER, teller.getCode());
 
@@ -104,11 +102,11 @@ public class TestTellerOperation extends AbstractTellerTest {
   public void shouldOpenAccount() throws Exception {
     final Teller teller = this.prepareTeller();
 
-    final TellerAuthentication tellerAuthentication = new TellerAuthentication();
-    tellerAuthentication.setEmployeeIdentifier(AbstractTellerTest.TEST_USER);
-    tellerAuthentication.setPassword(teller.getPassword());
+    final UnlockDrawerCommand unlockDrawerCommand = new UnlockDrawerCommand();
+    unlockDrawerCommand.setEmployeeIdentifier(AbstractTellerTest.TEST_USER);
+    unlockDrawerCommand.setPassword(teller.getPassword());
 
-    super.testSubject.auth(teller.getCode(), tellerAuthentication);
+    super.testSubject.unlockDrawer(teller.getCode(), unlockDrawerCommand);
 
     super.eventRecorder.wait(EventConstants.AUTHENTICATE_TELLER, teller.getCode());
 
@@ -135,11 +133,11 @@ public class TestTellerOperation extends AbstractTellerTest {
   public void shouldCloseAccount() throws Exception {
     final Teller teller = this.prepareTeller();
 
-    final TellerAuthentication tellerAuthentication = new TellerAuthentication();
-    tellerAuthentication.setEmployeeIdentifier(AbstractTellerTest.TEST_USER);
-    tellerAuthentication.setPassword(teller.getPassword());
+    final UnlockDrawerCommand unlockDrawerCommand = new UnlockDrawerCommand();
+    unlockDrawerCommand.setEmployeeIdentifier(AbstractTellerTest.TEST_USER);
+    unlockDrawerCommand.setPassword(teller.getPassword());
 
-    super.testSubject.auth(teller.getCode(), tellerAuthentication);
+    super.testSubject.unlockDrawer(teller.getCode(), unlockDrawerCommand);
 
     super.eventRecorder.wait(EventConstants.AUTHENTICATE_TELLER, teller.getCode());
 
@@ -166,11 +164,11 @@ public class TestTellerOperation extends AbstractTellerTest {
   public void shouldTransferAccountToAccount() throws Exception {
     final Teller teller = this.prepareTeller();
 
-    final TellerAuthentication tellerAuthentication = new TellerAuthentication();
-    tellerAuthentication.setEmployeeIdentifier(AbstractTellerTest.TEST_USER);
-    tellerAuthentication.setPassword(teller.getPassword());
+    final UnlockDrawerCommand unlockDrawerCommand = new UnlockDrawerCommand();
+    unlockDrawerCommand.setEmployeeIdentifier(AbstractTellerTest.TEST_USER);
+    unlockDrawerCommand.setPassword(teller.getPassword());
 
-    super.testSubject.auth(teller.getCode(), tellerAuthentication);
+    super.testSubject.unlockDrawer(teller.getCode(), unlockDrawerCommand);
 
     super.eventRecorder.wait(EventConstants.AUTHENTICATE_TELLER, teller.getCode());
 
@@ -200,11 +198,11 @@ public class TestTellerOperation extends AbstractTellerTest {
   public void shouldDeposit() throws Exception {
     final Teller teller = this.prepareTeller();
 
-    final TellerAuthentication tellerAuthentication = new TellerAuthentication();
-    tellerAuthentication.setEmployeeIdentifier(AbstractTellerTest.TEST_USER);
-    tellerAuthentication.setPassword(teller.getPassword());
+    final UnlockDrawerCommand unlockDrawerCommand = new UnlockDrawerCommand();
+    unlockDrawerCommand.setEmployeeIdentifier(AbstractTellerTest.TEST_USER);
+    unlockDrawerCommand.setPassword(teller.getPassword());
 
-    super.testSubject.auth(teller.getCode(), tellerAuthentication);
+    super.testSubject.unlockDrawer(teller.getCode(), unlockDrawerCommand);
 
     super.eventRecorder.wait(EventConstants.AUTHENTICATE_TELLER, teller.getCode());
 
@@ -231,11 +229,11 @@ public class TestTellerOperation extends AbstractTellerTest {
   public void shouldWithdraw() throws Exception {
     final Teller teller = this.prepareTeller();
 
-    final TellerAuthentication tellerAuthentication = new TellerAuthentication();
-    tellerAuthentication.setEmployeeIdentifier(AbstractTellerTest.TEST_USER);
-    tellerAuthentication.setPassword(teller.getPassword());
+    final UnlockDrawerCommand unlockDrawerCommand = new UnlockDrawerCommand();
+    unlockDrawerCommand.setEmployeeIdentifier(AbstractTellerTest.TEST_USER);
+    unlockDrawerCommand.setPassword(teller.getPassword());
 
-    super.testSubject.auth(teller.getCode(), tellerAuthentication);
+    super.testSubject.unlockDrawer(teller.getCode(), unlockDrawerCommand);
 
     super.eventRecorder.wait(EventConstants.AUTHENTICATE_TELLER, teller.getCode());
 
diff --git a/service/src/main/java/io/mifos/teller/service/internal/command/AuthenticateTellerCommand.java b/service/src/main/java/io/mifos/teller/service/internal/command/DrawerUnlockCommand.java
similarity index 66%
rename from service/src/main/java/io/mifos/teller/service/internal/command/AuthenticateTellerCommand.java
rename to service/src/main/java/io/mifos/teller/service/internal/command/DrawerUnlockCommand.java
index f1f5ce3..0b76f72 100644
--- a/service/src/main/java/io/mifos/teller/service/internal/command/AuthenticateTellerCommand.java
+++ b/service/src/main/java/io/mifos/teller/service/internal/command/DrawerUnlockCommand.java
@@ -15,23 +15,23 @@
  */
 package io.mifos.teller.service.internal.command;
 
-import io.mifos.teller.api.v1.domain.TellerAuthentication;
+import io.mifos.teller.api.v1.domain.UnlockDrawerCommand;
 
-public class AuthenticateTellerCommand {
+public class DrawerUnlockCommand {
   private final String tellerCode;
-  private final TellerAuthentication tellerAuthentication;
+  private final UnlockDrawerCommand unlockDrawerCommand;
 
-  public AuthenticateTellerCommand(final String tellerCode, final TellerAuthentication tellerAuthentication) {
+  public DrawerUnlockCommand(final String tellerCode, final UnlockDrawerCommand unlockDrawerCommand) {
     super();
     this.tellerCode = tellerCode;
-    this.tellerAuthentication = tellerAuthentication;
+    this.unlockDrawerCommand = unlockDrawerCommand;
   }
 
   public String tellerCode() {
     return this.tellerCode;
   }
 
-  public TellerAuthentication tellerAuthentication() {
-    return this.tellerAuthentication;
+  public UnlockDrawerCommand tellerAuthentication() {
+    return this.unlockDrawerCommand;
   }
 }
diff --git a/service/src/main/java/io/mifos/teller/service/internal/command/handler/TellerAggregate.java b/service/src/main/java/io/mifos/teller/service/internal/command/handler/TellerAggregate.java
index 56e5b64..fb43fbc 100644
--- a/service/src/main/java/io/mifos/teller/service/internal/command/handler/TellerAggregate.java
+++ b/service/src/main/java/io/mifos/teller/service/internal/command/handler/TellerAggregate.java
@@ -28,9 +28,9 @@ import io.mifos.core.lang.ServiceException;
 import io.mifos.teller.ServiceConstants;
 import io.mifos.teller.api.v1.EventConstants;
 import io.mifos.teller.api.v1.domain.Teller;
-import io.mifos.teller.api.v1.domain.TellerAuthentication;
+import io.mifos.teller.api.v1.domain.UnlockDrawerCommand;
 import io.mifos.teller.api.v1.domain.TellerManagementCommand;
-import io.mifos.teller.service.internal.command.AuthenticateTellerCommand;
+import io.mifos.teller.service.internal.command.DrawerUnlockCommand;
 import io.mifos.teller.service.internal.command.ChangeTellerCommand;
 import io.mifos.teller.service.internal.command.CloseTellerCommand;
 import io.mifos.teller.service.internal.command.CreateTellerCommand;
@@ -208,15 +208,14 @@ public class TellerAggregate {
   @Transactional
   @CommandHandler
   @EventEmitter(selectorName = EventConstants.SELECTOR_NAME, selectorValue = EventConstants.AUTHENTICATE_TELLER)
-  public String process(final AuthenticateTellerCommand authenticateTellerCommand) {
-    final String tellerCode = authenticateTellerCommand.tellerCode();
-    final TellerAuthentication tellerAuthentication = authenticateTellerCommand.tellerAuthentication();
+  public String process(final DrawerUnlockCommand drawerUnlockCommand) {
+    final String tellerCode = drawerUnlockCommand.tellerCode();
+    final UnlockDrawerCommand unlockDrawerCommand = drawerUnlockCommand.tellerAuthentication();
 
     final Optional<TellerEntity> optionalTeller = this.tellerRepository.findByIdentifier(tellerCode);
     if (optionalTeller.isPresent()) {
       final TellerEntity tellerEntity = optionalTeller.get();
-      if (!tellerEntity.getState().equals(Teller.State.OPEN.name())
-          && !tellerEntity.getState().equals(Teller.State.PAUSED.name())) {
+      if (tellerEntity.getState().equals(Teller.State.CLOSED.name())) {
         throw ServiceException.notFound("Teller {0} not found.", tellerCode);
       }
 
@@ -224,7 +223,7 @@ public class TellerAggregate {
         throw ServiceException.notFound("Teller {0} not found.", tellerCode);
       }
 
-      final byte[] givenPassword = this.hashGenerator.hash(tellerAuthentication.getPassword(),
+      final byte[] givenPassword = this.hashGenerator.hash(unlockDrawerCommand.getPassword(),
           Base64Utils.decodeFromString(tellerEntity.getSalt()), ServiceConstants.ITERATION_COUNT, ServiceConstants.LENGTH);
 
       if (!tellerEntity.getPassword().equals(Base64Utils.encodeToString(givenPassword))) {
diff --git a/service/src/main/java/io/mifos/teller/service/rest/TellerOperationRestController.java b/service/src/main/java/io/mifos/teller/service/rest/TellerOperationRestController.java
index 611b485..540d2c4 100644
--- a/service/src/main/java/io/mifos/teller/service/rest/TellerOperationRestController.java
+++ b/service/src/main/java/io/mifos/teller/service/rest/TellerOperationRestController.java
@@ -23,10 +23,10 @@ import io.mifos.core.lang.ServiceException;
 import io.mifos.teller.ServiceConstants;
 import io.mifos.teller.api.v1.PermittableGroupIds;
 import io.mifos.teller.api.v1.domain.Teller;
-import io.mifos.teller.api.v1.domain.TellerAuthentication;
+import io.mifos.teller.api.v1.domain.UnlockDrawerCommand;
 import io.mifos.teller.api.v1.domain.TellerTransaction;
 import io.mifos.teller.api.v1.domain.TellerTransactionCosts;
-import io.mifos.teller.service.internal.command.AuthenticateTellerCommand;
+import io.mifos.teller.service.internal.command.DrawerUnlockCommand;
 import io.mifos.teller.service.internal.command.CancelTellerTransactionCommand;
 import io.mifos.teller.service.internal.command.ConfirmTellerTransactionCommand;
 import io.mifos.teller.service.internal.command.InitializeTellerTransactionCommand;
@@ -76,26 +76,29 @@ public class TellerOperationRestController {
 
   @Permittable(value = AcceptedTokenType.TENANT, groupId = PermittableGroupIds.TELLER_OPERATION)
   @RequestMapping(
-      value = "/auth",
+      value = "/drawer",
       method = RequestMethod.POST,
       consumes = MediaType.APPLICATION_JSON_VALUE,
       produces = MediaType.APPLICATION_JSON_VALUE
   )
   @ResponseBody
-  ResponseEntity<String> auth(@PathVariable("tellerCode") final String tellerCode,
-                            @RequestBody @Valid final TellerAuthentication tellerAuthentication) {
+  ResponseEntity<Void> unlockDrawer(@PathVariable("tellerCode") final String tellerCode,
+                                    @RequestBody @Valid final UnlockDrawerCommand unlockDrawerCommand) {
     final Teller teller = this.verifyTeller(tellerCode);
 
-    if (!teller.getAssignedEmployee().equals(tellerAuthentication.getEmployeeIdentifier())) {
-      throw ServiceException.badRequest("User {0} is not assigned to teller.", tellerAuthentication.getEmployeeIdentifier());
+    if (!teller.getAssignedEmployee().equals(unlockDrawerCommand.getEmployeeIdentifier())) {
+      throw ServiceException.badRequest("User {0} is not assigned to teller.", unlockDrawerCommand.getEmployeeIdentifier());
     }
 
     this.verifyEmployee(teller);
 
     try {
-      return ResponseEntity.ok(
-          this.commandGateway.process(new AuthenticateTellerCommand(tellerCode, tellerAuthentication), String.class).get()
-      );
+      final String unlockedTeller =
+          this.commandGateway.process(new DrawerUnlockCommand(tellerCode, unlockDrawerCommand), String.class).get();
+
+      this.logger.debug("Drawer {0} unlocked", unlockedTeller);
+
+      return ResponseEntity.ok().build();
     } catch (final Exception e) {
       throw ServiceException.notFound("Teller {0} not found.", teller.getCode());
     }
diff --git a/service/src/main/resources/logback.xml b/service/src/main/resources/logback.xml
new file mode 100644
index 0000000..20128f1
--- /dev/null
+++ b/service/src/main/resources/logback.xml
@@ -0,0 +1,55 @@
+<!--
+
+    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.
+
+-->
+<configuration>
+    <appender name="FILE" class="ch.qos.logback.core.rolling.RollingFileAppender">
+        <file>logs/teller.log</file>
+        <rollingPolicy class="ch.qos.logback.core.rolling.TimeBasedRollingPolicy">
+            <fileNamePattern>logs/archive/teller.%d{yyyy-MM-dd}.log</fileNamePattern>
+            <maxHistory>7</maxHistory>
+            <totalSizeCap>2GB</totalSizeCap>
+        </rollingPolicy>
+        <encoder>
+            <pattern>%d{HH:mm:ss.SSS} [%thread] %-5level %logger{36} - %msg%n</pattern>
+        </encoder>
+    </appender>
+    <appender name="STDOUT" class="ch.qos.logback.core.ConsoleAppender">
+        <encoder>
+            <pattern>%d{HH:mm:ss.SSS} [%thread] %-5level %logger{36} - %msg%n</pattern>
+        </encoder>
+    </appender>
+
+    <logger name="com" level="WARN">
+        <appender-ref ref="STDOUT" />
+    </logger>
+
+    <logger name="org" level="WARN">
+        <appender-ref ref="STDOUT" />
+    </logger>
+
+    <logger name="io" level="WARN">
+        <appender-ref ref="STDOUT" />
+    </logger>
+
+    <logger name="net" level="WARN">
+        <appender-ref ref="STDOUT" />
+    </logger>
+
+    <root level="INFO">
+        <appender-ref ref="FILE"/>
+    </root>
+</configuration>
\ No newline at end of file

-- 
To stop receiving notification emails like this one, please contact
myrle@apache.org.

[fineract-cn-teller] 07/30: use today of last modified is not available

Posted by my...@apache.org.
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-teller.git

commit 52d94ef1b60bfdf6d961975e15552d0883563d42
Author: mgeiss <mg...@mifos.org>
AuthorDate: Mon Jun 12 06:30:22 2017 +0200

    use today of last modified is not available
---
 .../teller/service/internal/service/TellerManagementService.java      | 4 +++-
 1 file changed, 3 insertions(+), 1 deletion(-)

diff --git a/service/src/main/java/io/mifos/teller/service/internal/service/TellerManagementService.java b/service/src/main/java/io/mifos/teller/service/internal/service/TellerManagementService.java
index ceb497a..c90d2ba 100644
--- a/service/src/main/java/io/mifos/teller/service/internal/service/TellerManagementService.java
+++ b/service/src/main/java/io/mifos/teller/service/internal/service/TellerManagementService.java
@@ -31,6 +31,7 @@ import org.springframework.beans.factory.annotation.Autowired;
 import org.springframework.beans.factory.annotation.Qualifier;
 import org.springframework.stereotype.Service;
 
+import java.time.Clock;
 import java.time.LocalDateTime;
 import java.time.format.DateTimeFormatter;
 import java.util.ArrayList;
@@ -73,7 +74,8 @@ public class TellerManagementService {
     optionalTellerEntity.ifPresent(tellerEntity -> {
 
       final String accountIdentifier = tellerEntity.getTellerAccountIdentifier();
-      final LocalDateTime lastModifiedOn = tellerEntity.getLastModifiedOn();
+      final LocalDateTime lastModifiedOn =
+          tellerEntity.getLastModifiedOn() != null ? tellerEntity.getLastModifiedOn() : LocalDateTime.now(Clock.systemUTC());
       final LocalDateTime startDate = lastModifiedOn.withHour(0).withMinute(0).withSecond(0).withNano(0);
       final LocalDateTime endDate = lastModifiedOn.withHour(23).withMinute(59).withSecond(59).withNano(999);
       final String dateRange =

-- 
To stop receiving notification emails like this one, please contact
myrle@apache.org.

[fineract-cn-teller] 09/30: added teller transaction handling

Posted by my...@apache.org.
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-teller.git

commit 0230a24ec69b004d2785cd9df5cf6637923e7156
Author: mgeiss <mg...@mifos.org>
AuthorDate: Wed Jun 14 09:06:42 2017 +0200

    added teller transaction handling
---
 .../io/mifos/teller/api/v1/EventConstants.java     |  13 +
 .../mifos/teller/api/v1/client/TellerManager.java  |   8 +-
 .../java/io/mifos/teller/api/v1/domain/Charge.java |   9 +
 .../teller/api/v1/domain/TellerTransaction.java    |  10 +
 .../java/io/mifos/teller/AbstractTellerTest.java   |   2 +-
 .../java/io/mifos/teller/TestTellerManagement.java |   4 +
 .../java/io/mifos/teller/TestTellerOperation.java  | 292 +++++++++++++++++++++
 .../mifos/teller/listener/TellerEventListener.java |  22 ++
 .../java/io/mifos/teller/ServiceConstants.java     |  11 +
 .../java/io/mifos/teller/TellerConfiguration.java  |   3 +-
 .../command/AuthenticateTellerCommand.java         |  38 +--
 .../CancelTellerTransactionCommand.java}           |  15 +-
 .../ConfirmTellerTransactionCommand.java}          |  15 +-
 .../InitializeTellerTransactionCommand.java        |  38 +--
 .../PauseTellerCommand.java}                       |  15 +-
 .../internal/command/handler/TellerAggregate.java  |  83 +++++-
 .../handler/TellerTransactionAggregate.java        | 124 +++++++++
 .../service/internal/mapper/TellerMapper.java      |   1 -
 .../internal/mapper/TellerTransactionMapper.java   |  59 +++++
 .../processor/TellerTransactionProcessor.java      | 251 ++++++++++++++++++
 .../repository/TellerTransactionEntity.java        |  94 ++++---
 .../repository/TellerTransactionRepository.java    |  32 +++
 .../internal/service/TellerOperationService.java   |  53 ++++
 .../internal/service/helper/AccountingService.java |  15 ++
 .../helper/DepositAccountManagementService.java    |  52 ++++
 .../rest/TellerOperationRestController.java        | 125 +++++++--
 .../db/migrations/mariadb/V1__initial_setup.sql    |  22 +-
 27 files changed, 1280 insertions(+), 126 deletions(-)

diff --git a/api/src/main/java/io/mifos/teller/api/v1/EventConstants.java b/api/src/main/java/io/mifos/teller/api/v1/EventConstants.java
index 34b1abb..fcbd70e 100644
--- a/api/src/main/java/io/mifos/teller/api/v1/EventConstants.java
+++ b/api/src/main/java/io/mifos/teller/api/v1/EventConstants.java
@@ -33,4 +33,17 @@ public interface EventConstants {
   String SELECTOR_OPEN_TELLER = SELECTOR_NAME + " = '" + OPEN_TELLER + "'";
   String CLOSE_TELLER = "close-teller";
   String SELECTOR_CLOSE_TELLER = SELECTOR_NAME + " = '" + CLOSE_TELLER + "'";
+  String ACTIVATE_TELLER = "activate-teller";
+  String SELECTOR_ACTIVATE_TELLER = SELECTOR_NAME + " = '" + ACTIVATE_TELLER + "'";
+  String PAUSE_TELLER = "pause-teller";
+  String SELECTOR_PAUSE_TELLER = SELECTOR_NAME + " = '" + PAUSE_TELLER + "'";
+
+  String INIT_TRANSACTION = "init-transaction";
+  String SELECTOR_INIT_TRANSACTION = SELECTOR_NAME + " = '" + INIT_TRANSACTION + "'";
+  String CONFIRM_TRANSACTION = "confirm-transaction";
+  String SELECTOR_CONFIRM_TRANSACTION = SELECTOR_NAME + " = '" + CONFIRM_TRANSACTION + "'";
+  String CANCEL_TRANSACTION = "cancel-transaction";
+  String SELECTOR_CANCEL_TRANSACTION = SELECTOR_NAME + " = '" + CANCEL_TRANSACTION + "'";
+  String AUTHENTICATE_TELLER = "authenticate-teller";
+  String SELECTOR_AUTHENTICATE_TELLER = SELECTOR_NAME + " = '" + AUTHENTICATE_TELLER + "'";
 }
diff --git a/api/src/main/java/io/mifos/teller/api/v1/client/TellerManager.java b/api/src/main/java/io/mifos/teller/api/v1/client/TellerManager.java
index 0972873..18d5f55 100644
--- a/api/src/main/java/io/mifos/teller/api/v1/client/TellerManager.java
+++ b/api/src/main/java/io/mifos/teller/api/v1/client/TellerManager.java
@@ -125,9 +125,10 @@ public interface TellerManager {
   )
   @ThrowsExceptions({
       @ThrowsException(status = HttpStatus.NOT_FOUND, exception = TellerNotFoundException.class),
-      @ThrowsException(status = HttpStatus.BAD_REQUEST, exception = TellerNotFoundException.class)
+      @ThrowsException(status = HttpStatus.BAD_REQUEST, exception = TellerNotFoundException.class),
+      @ThrowsException(status = HttpStatus.CONFLICT, exception = TellerNotFoundException.class)
   })
-  void auth(@PathVariable("tellerCode") final String tellerCode,
+  String auth(@PathVariable("tellerCode") final String tellerCode,
             @RequestBody @Valid final TellerAuthentication tellerAuthentication);
 
   @RequestMapping(
@@ -137,7 +138,8 @@ public interface TellerManager {
       produces = MediaType.APPLICATION_JSON_VALUE
   )
   @ThrowsExceptions({
-      @ThrowsException(status = HttpStatus.NOT_FOUND, exception = TellerNotFoundException.class)
+      @ThrowsException(status = HttpStatus.NOT_FOUND, exception = TellerNotFoundException.class),
+      @ThrowsException(status = HttpStatus.BAD_REQUEST, exception = TellerValidationException.class)
   })
   void post(@PathVariable("tellerCode") final String tellerCode,
             @RequestParam(value = "command", required = true) final String command);
diff --git a/api/src/main/java/io/mifos/teller/api/v1/domain/Charge.java b/api/src/main/java/io/mifos/teller/api/v1/domain/Charge.java
index e576a09..4e375fe 100644
--- a/api/src/main/java/io/mifos/teller/api/v1/domain/Charge.java
+++ b/api/src/main/java/io/mifos/teller/api/v1/domain/Charge.java
@@ -18,6 +18,7 @@ package io.mifos.teller.api.v1.domain;
 public class Charge {
 
   private String code;
+  private String incomeAccountIdentifier;
   private String name;
   private Double amount;
 
@@ -33,6 +34,14 @@ public class Charge {
     this.code = code;
   }
 
+  public String getIncomeAccountIdentifier() {
+    return this.incomeAccountIdentifier;
+  }
+
+  public void setIncomeAccountIdentifier(final String incomeAccountIdentifier) {
+    this.incomeAccountIdentifier = incomeAccountIdentifier;
+  }
+
   public String getName() {
     return this.name;
   }
diff --git a/api/src/main/java/io/mifos/teller/api/v1/domain/TellerTransaction.java b/api/src/main/java/io/mifos/teller/api/v1/domain/TellerTransaction.java
index 5dc8ffa..926e48b 100644
--- a/api/src/main/java/io/mifos/teller/api/v1/domain/TellerTransaction.java
+++ b/api/src/main/java/io/mifos/teller/api/v1/domain/TellerTransaction.java
@@ -35,6 +35,8 @@ public class TellerTransaction {
   @NotNull
   private String transactionDate;
   @ValidIdentifier
+  private String customerIdentifier;
+  @ValidIdentifier
   private String productIdentifier;
   @ValidIdentifier(optional = true)
   private String productCaseIdentifier;
@@ -77,6 +79,14 @@ public class TellerTransaction {
     this.transactionDate = transactionDate;
   }
 
+  public String getCustomerIdentifier() {
+    return this.customerIdentifier;
+  }
+
+  public void setCustomerIdentifier(final String customerIdentifier) {
+    this.customerIdentifier = customerIdentifier;
+  }
+
   public String getProductIdentifier() {
     return this.productIdentifier;
   }
diff --git a/component-test/src/main/java/io/mifos/teller/AbstractTellerTest.java b/component-test/src/main/java/io/mifos/teller/AbstractTellerTest.java
index 4d60f41..9a86a73 100644
--- a/component-test/src/main/java/io/mifos/teller/AbstractTellerTest.java
+++ b/component-test/src/main/java/io/mifos/teller/AbstractTellerTest.java
@@ -80,7 +80,7 @@ public class AbstractTellerTest {
     }
   }
 
-  private static final String TEST_USER = "homer";
+  static final String TEST_USER = "homer";
 
   private final static TestEnvironment testEnvironment = new TestEnvironment(APP_NAME);
   private final static CassandraInitializer cassandraInitializer = new CassandraInitializer();
diff --git a/component-test/src/main/java/io/mifos/teller/TestTellerManagement.java b/component-test/src/main/java/io/mifos/teller/TestTellerManagement.java
index b9f703d..ca28069 100644
--- a/component-test/src/main/java/io/mifos/teller/TestTellerManagement.java
+++ b/component-test/src/main/java/io/mifos/teller/TestTellerManagement.java
@@ -361,6 +361,7 @@ public class TestTellerManagement extends AbstractTellerTest {
 
     final TellerManagementCommand command = new TellerManagementCommand();
     command.setAction(TellerManagementCommand.Action.OPEN.name());
+    command.setAdjustment(TellerManagementCommand.Adjustment.NONE.name());
     command.setAssignedEmployeeIdentifier(RandomStringUtils.randomAlphanumeric(32));
 
     Mockito.doAnswer(invocation -> true)
@@ -395,6 +396,7 @@ public class TestTellerManagement extends AbstractTellerTest {
 
     final TellerManagementCommand command = new TellerManagementCommand();
     command.setAction(TellerManagementCommand.Action.OPEN.name());
+    command.setAdjustment(TellerManagementCommand.Adjustment.NONE.name());
     command.setAssignedEmployeeIdentifier(RandomStringUtils.randomAlphanumeric(32));
 
     Mockito.doAnswer(invocation -> true)
@@ -435,6 +437,7 @@ public class TestTellerManagement extends AbstractTellerTest {
 
     final TellerManagementCommand command = new TellerManagementCommand();
     command.setAction(TellerManagementCommand.Action.CLOSE.name());
+    command.setAdjustment(TellerManagementCommand.Adjustment.NONE.name());
 
     super.testSubject.post(officeIdentifier, teller.getCode(), command);
   }
@@ -459,6 +462,7 @@ public class TestTellerManagement extends AbstractTellerTest {
 
     final TellerManagementCommand command = new TellerManagementCommand();
     command.setAction(TellerManagementCommand.Action.OPEN.name());
+    command.setAdjustment(TellerManagementCommand.Adjustment.NONE.name());
     command.setAssignedEmployeeIdentifier(RandomStringUtils.randomAlphanumeric(32));
 
     Mockito.doAnswer(invocation -> true)
diff --git a/component-test/src/main/java/io/mifos/teller/TestTellerOperation.java b/component-test/src/main/java/io/mifos/teller/TestTellerOperation.java
new file mode 100644
index 0000000..39b7ed3
--- /dev/null
+++ b/component-test/src/main/java/io/mifos/teller/TestTellerOperation.java
@@ -0,0 +1,292 @@
+/*
+ * 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.
+ */
+package io.mifos.teller;
+
+import io.mifos.core.lang.DateConverter;
+import io.mifos.teller.api.v1.EventConstants;
+import io.mifos.teller.api.v1.client.TellerNotFoundException;
+import io.mifos.teller.api.v1.client.TellerValidationException;
+import io.mifos.teller.api.v1.domain.Teller;
+import io.mifos.teller.api.v1.domain.TellerAuthentication;
+import io.mifos.teller.api.v1.domain.TellerManagementCommand;
+import io.mifos.teller.api.v1.domain.TellerTransaction;
+import io.mifos.teller.util.TellerGenerator;
+import org.apache.commons.lang3.RandomStringUtils;
+import org.junit.Assert;
+import org.junit.Test;
+import org.mockito.Matchers;
+import org.mockito.Mockito;
+
+import java.time.Clock;
+import java.time.LocalDateTime;
+import java.util.Collections;
+
+public class TestTellerOperation extends AbstractTellerTest {
+
+  public TestTellerOperation() {
+    super();
+  }
+
+  @Test
+  public void shouldAuthenticate() throws Exception {
+    final Teller teller = this.prepareTeller();
+
+    final TellerAuthentication tellerAuthentication = new TellerAuthentication();
+    tellerAuthentication.setEmployeeIdentifier(AbstractTellerTest.TEST_USER);
+    tellerAuthentication.setPassword(teller.getPassword().getBytes());
+
+    final String auth = super.testSubject.auth(teller.getCode(), tellerAuthentication);
+
+    Assert.assertEquals(auth, teller.getCode());
+  }
+
+
+  @Test(expected = TellerNotFoundException.class)
+  public void shouldNotAuthenticateUserMismatch() throws Exception {
+    final Teller teller = this.prepareTeller();
+
+    final TellerAuthentication tellerAuthentication = new TellerAuthentication();
+    tellerAuthentication.setEmployeeIdentifier("unassigneduser");
+    tellerAuthentication.setPassword(teller.getPassword().getBytes());
+
+    super.testSubject.auth(teller.getCode(), tellerAuthentication);
+  }
+
+  @Test(expected = TellerNotFoundException.class)
+  public void shouldNotAuthenticatePasswordMismatch() throws Exception {
+    final Teller teller = this.prepareTeller();
+
+    final TellerAuthentication tellerAuthentication = new TellerAuthentication();
+    tellerAuthentication.setEmployeeIdentifier(AbstractTellerTest.TEST_USER);
+    tellerAuthentication.setPassword("wrongpasword".getBytes());
+
+    super.testSubject.auth(teller.getCode(), tellerAuthentication);
+  }
+
+  @Test
+  public void shouldPauseTeller() throws Exception {
+    final Teller teller = this.prepareTeller();
+
+    final TellerAuthentication tellerAuthentication = new TellerAuthentication();
+    tellerAuthentication.setEmployeeIdentifier(AbstractTellerTest.TEST_USER);
+    tellerAuthentication.setPassword(teller.getPassword().getBytes());
+
+    super.testSubject.auth(teller.getCode(), tellerAuthentication);
+
+    super.eventRecorder.wait(EventConstants.AUTHENTICATE_TELLER, teller.getCode());
+
+    super.testSubject.post(teller.getCode(), "PAUSE");
+
+    Assert.assertTrue(super.eventRecorder.wait(EventConstants.PAUSE_TELLER, teller.getCode()));
+  }
+
+  @Test(expected = TellerValidationException.class)
+  public void shouldNotPauseTellerNotAuthenticated() throws Exception {
+    final Teller teller = this.prepareTeller();
+
+    super.testSubject.post(teller.getCode(), "PAUSE");
+  }
+
+  @Test
+  public void shouldOpenAccount() throws Exception {
+    final Teller teller = this.prepareTeller();
+
+    final TellerAuthentication tellerAuthentication = new TellerAuthentication();
+    tellerAuthentication.setEmployeeIdentifier(AbstractTellerTest.TEST_USER);
+    tellerAuthentication.setPassword(teller.getPassword().getBytes());
+
+    super.testSubject.auth(teller.getCode(), tellerAuthentication);
+
+    super.eventRecorder.wait(EventConstants.AUTHENTICATE_TELLER, teller.getCode());
+
+    final TellerTransaction tellerTransaction =  new TellerTransaction();
+    tellerTransaction.setTransactionType(ServiceConstants.TX_OPEN_ACCOUNT);
+    tellerTransaction.setTransactionDate(DateConverter.toIsoString(LocalDateTime.now(Clock.systemUTC())));
+    tellerTransaction.setProductIdentifier(RandomStringUtils.randomAlphanumeric(32));
+    tellerTransaction.setCustomerAccountIdentifier(RandomStringUtils.randomAlphanumeric(32));
+    tellerTransaction.setCustomerIdentifier(RandomStringUtils.randomAlphanumeric(32));
+    tellerTransaction.setClerk(AbstractTellerTest.TEST_USER);
+    tellerTransaction.setAmount(1234.56D);
+
+    Mockito.doAnswer(invocation -> true)
+        .when(super.accountingServiceSpy).accountExists(tellerTransaction.getCustomerAccountIdentifier());
+    Mockito.doAnswer(invocation -> Collections.emptyList())
+        .when(super.depositAccountManagementServiceSpy).getCharges(Matchers.eq(tellerTransaction));
+    Mockito.doAnswer(invocation -> Collections.emptyList())
+        .when(super.depositAccountManagementServiceSpy).getProductInstance(tellerTransaction.getCustomerIdentifier());
+
+    super.testSubject.post(teller.getCode(), tellerTransaction);
+  }
+
+  @Test
+  public void shouldCloseAccount() throws Exception {
+    final Teller teller = this.prepareTeller();
+
+    final TellerAuthentication tellerAuthentication = new TellerAuthentication();
+    tellerAuthentication.setEmployeeIdentifier(AbstractTellerTest.TEST_USER);
+    tellerAuthentication.setPassword(teller.getPassword().getBytes());
+
+    super.testSubject.auth(teller.getCode(), tellerAuthentication);
+
+    super.eventRecorder.wait(EventConstants.AUTHENTICATE_TELLER, teller.getCode());
+
+    final TellerTransaction tellerTransaction =  new TellerTransaction();
+    tellerTransaction.setTransactionType(ServiceConstants.TX_CLOSE_ACCOUNT);
+    tellerTransaction.setTransactionDate(DateConverter.toIsoString(LocalDateTime.now(Clock.systemUTC())));
+    tellerTransaction.setProductIdentifier(RandomStringUtils.randomAlphanumeric(32));
+    tellerTransaction.setCustomerAccountIdentifier(RandomStringUtils.randomAlphanumeric(32));
+    tellerTransaction.setCustomerIdentifier(RandomStringUtils.randomAlphanumeric(32));
+    tellerTransaction.setClerk(AbstractTellerTest.TEST_USER);
+    tellerTransaction.setAmount(1234.56D);
+
+    Mockito.doAnswer(invocation -> true)
+        .when(super.accountingServiceSpy).accountExists(tellerTransaction.getCustomerAccountIdentifier());
+    Mockito.doAnswer(invocation -> Collections.emptyList())
+        .when(super.depositAccountManagementServiceSpy).getCharges(Matchers.eq(tellerTransaction));
+    Mockito.doAnswer(invocation -> Collections.emptyList())
+        .when(super.depositAccountManagementServiceSpy).getProductInstance(tellerTransaction.getCustomerIdentifier());
+
+    super.testSubject.post(teller.getCode(), tellerTransaction);
+  }
+
+  @Test
+  public void shouldTransferAccountToAccount() throws Exception {
+    final Teller teller = this.prepareTeller();
+
+    final TellerAuthentication tellerAuthentication = new TellerAuthentication();
+    tellerAuthentication.setEmployeeIdentifier(AbstractTellerTest.TEST_USER);
+    tellerAuthentication.setPassword(teller.getPassword().getBytes());
+
+    super.testSubject.auth(teller.getCode(), tellerAuthentication);
+
+    super.eventRecorder.wait(EventConstants.AUTHENTICATE_TELLER, teller.getCode());
+
+    final TellerTransaction tellerTransaction =  new TellerTransaction();
+    tellerTransaction.setTransactionType(ServiceConstants.TX_ACCOUNT_TRANSFER);
+    tellerTransaction.setTransactionDate(DateConverter.toIsoString(LocalDateTime.now(Clock.systemUTC())));
+    tellerTransaction.setProductIdentifier(RandomStringUtils.randomAlphanumeric(32));
+    tellerTransaction.setCustomerAccountIdentifier(RandomStringUtils.randomAlphanumeric(32));
+    tellerTransaction.setTargetAccountIdentifier(RandomStringUtils.randomAlphanumeric(32));
+    tellerTransaction.setCustomerIdentifier(RandomStringUtils.randomAlphanumeric(32));
+    tellerTransaction.setClerk(AbstractTellerTest.TEST_USER);
+    tellerTransaction.setAmount(1234.56D);
+
+    Mockito.doAnswer(invocation -> true)
+        .when(super.accountingServiceSpy).accountExists(tellerTransaction.getCustomerAccountIdentifier());
+    Mockito.doAnswer(invocation -> true)
+        .when(super.accountingServiceSpy).accountExists(tellerTransaction.getTargetAccountIdentifier());
+    Mockito.doAnswer(invocation -> Collections.emptyList())
+        .when(super.depositAccountManagementServiceSpy).getCharges(Matchers.eq(tellerTransaction));
+    Mockito.doAnswer(invocation -> Collections.emptyList())
+        .when(super.depositAccountManagementServiceSpy).getProductInstance(tellerTransaction.getCustomerIdentifier());
+
+    super.testSubject.post(teller.getCode(), tellerTransaction);
+  }
+
+  @Test
+  public void shouldDeposit() throws Exception {
+    final Teller teller = this.prepareTeller();
+
+    final TellerAuthentication tellerAuthentication = new TellerAuthentication();
+    tellerAuthentication.setEmployeeIdentifier(AbstractTellerTest.TEST_USER);
+    tellerAuthentication.setPassword(teller.getPassword().getBytes());
+
+    super.testSubject.auth(teller.getCode(), tellerAuthentication);
+
+    super.eventRecorder.wait(EventConstants.AUTHENTICATE_TELLER, teller.getCode());
+
+    final TellerTransaction tellerTransaction =  new TellerTransaction();
+    tellerTransaction.setTransactionType(ServiceConstants.TX_CASH_DEPOSIT);
+    tellerTransaction.setTransactionDate(DateConverter.toIsoString(LocalDateTime.now(Clock.systemUTC())));
+    tellerTransaction.setProductIdentifier(RandomStringUtils.randomAlphanumeric(32));
+    tellerTransaction.setCustomerAccountIdentifier(RandomStringUtils.randomAlphanumeric(32));
+    tellerTransaction.setCustomerIdentifier(RandomStringUtils.randomAlphanumeric(32));
+    tellerTransaction.setClerk(AbstractTellerTest.TEST_USER);
+    tellerTransaction.setAmount(1234.56D);
+
+    Mockito.doAnswer(invocation -> true)
+        .when(super.accountingServiceSpy).accountExists(tellerTransaction.getCustomerAccountIdentifier());
+    Mockito.doAnswer(invocation -> Collections.emptyList())
+        .when(super.depositAccountManagementServiceSpy).getCharges(Matchers.eq(tellerTransaction));
+    Mockito.doAnswer(invocation -> Collections.emptyList())
+        .when(super.depositAccountManagementServiceSpy).getProductInstance(tellerTransaction.getCustomerIdentifier());
+
+    super.testSubject.post(teller.getCode(), tellerTransaction);
+  }
+
+  @Test
+  public void shouldWithdraw() throws Exception {
+    final Teller teller = this.prepareTeller();
+
+    final TellerAuthentication tellerAuthentication = new TellerAuthentication();
+    tellerAuthentication.setEmployeeIdentifier(AbstractTellerTest.TEST_USER);
+    tellerAuthentication.setPassword(teller.getPassword().getBytes());
+
+    super.testSubject.auth(teller.getCode(), tellerAuthentication);
+
+    super.eventRecorder.wait(EventConstants.AUTHENTICATE_TELLER, teller.getCode());
+
+    final TellerTransaction tellerTransaction =  new TellerTransaction();
+    tellerTransaction.setTransactionType(ServiceConstants.TX_CASH_WITHDRAWAL);
+    tellerTransaction.setTransactionDate(DateConverter.toIsoString(LocalDateTime.now(Clock.systemUTC())));
+    tellerTransaction.setProductIdentifier(RandomStringUtils.randomAlphanumeric(32));
+    tellerTransaction.setCustomerAccountIdentifier(RandomStringUtils.randomAlphanumeric(32));
+    tellerTransaction.setCustomerIdentifier(RandomStringUtils.randomAlphanumeric(32));
+    tellerTransaction.setClerk(AbstractTellerTest.TEST_USER);
+    tellerTransaction.setAmount(1234.56D);
+
+    Mockito.doAnswer(invocation -> true)
+        .when(super.accountingServiceSpy).accountExists(tellerTransaction.getCustomerAccountIdentifier());
+    Mockito.doAnswer(invocation -> Collections.emptyList())
+        .when(super.depositAccountManagementServiceSpy).getCharges(Matchers.eq(tellerTransaction));
+    Mockito.doAnswer(invocation -> Collections.emptyList())
+        .when(super.depositAccountManagementServiceSpy).getProductInstance(tellerTransaction.getCustomerIdentifier());
+
+    super.testSubject.post(teller.getCode(), tellerTransaction);
+  }
+
+  private Teller prepareTeller() throws Exception {
+    final String officeIdentifier = RandomStringUtils.randomAlphabetic(32);
+    final Teller teller = TellerGenerator.createRandomTeller();
+
+    Mockito.doAnswer(invocation -> true)
+        .when(super.organizationServiceSpy).officeExists(Matchers.eq(officeIdentifier));
+
+    Mockito.doAnswer(invocation -> true)
+        .when(super.accountingServiceSpy).accountExists(Matchers.eq(teller.getTellerAccountIdentifier()));
+
+    Mockito.doAnswer(invocation -> true)
+        .when(super.accountingServiceSpy).accountExists(Matchers.eq(teller.getVaultAccountIdentifier()));
+
+    super.testSubject.create(officeIdentifier, teller);
+
+    Assert.assertTrue(super.eventRecorder.wait(EventConstants.POST_TELLER, teller.getCode()));
+
+    final TellerManagementCommand command = new TellerManagementCommand();
+    command.setAction(TellerManagementCommand.Action.OPEN.name());
+    command.setAdjustment(TellerManagementCommand.Adjustment.NONE.name());
+    command.setAssignedEmployeeIdentifier(AbstractTellerTest.TEST_USER);
+
+    Mockito.doAnswer(invocation -> true)
+        .when(super.organizationServiceSpy).employeeExists(Matchers.eq(command.getAssignedEmployeeIdentifier()));
+
+    super.testSubject.post(officeIdentifier, teller.getCode(), command);
+
+    Assert.assertTrue(super.eventRecorder.wait(EventConstants.OPEN_TELLER, teller.getCode()));
+
+    return teller;
+  }
+}
diff --git a/component-test/src/main/java/io/mifos/teller/listener/TellerEventListener.java b/component-test/src/main/java/io/mifos/teller/listener/TellerEventListener.java
index ee40f75..0ad678a 100644
--- a/component-test/src/main/java/io/mifos/teller/listener/TellerEventListener.java
+++ b/component-test/src/main/java/io/mifos/teller/listener/TellerEventListener.java
@@ -81,4 +81,26 @@ public class TellerEventListener {
     this.logger.debug("Teller {} created.", payload);
     this.eventRecorder.event(tenant, EventConstants.CLOSE_TELLER, payload, String.class);
   }
+
+  @JmsListener(
+      destination = EventConstants.DESTINATION,
+      selector = EventConstants.SELECTOR_AUTHENTICATE_TELLER,
+      subscription = EventConstants.DESTINATION
+  )
+  public void onAuthenticate(@Header(TenantHeaderFilter.TENANT_HEADER) final String tenant,
+                      final String payload) {
+    this.logger.debug("Teller {} created.", payload);
+    this.eventRecorder.event(tenant, EventConstants.AUTHENTICATE_TELLER, payload, String.class);
+  }
+
+  @JmsListener(
+      destination = EventConstants.DESTINATION,
+      selector = EventConstants.SELECTOR_PAUSE_TELLER,
+      subscription = EventConstants.DESTINATION
+  )
+  public void onPause(@Header(TenantHeaderFilter.TENANT_HEADER) final String tenant,
+                             final String payload) {
+    this.logger.debug("Teller {} created.", payload);
+    this.eventRecorder.event(tenant, EventConstants.PAUSE_TELLER, payload, String.class);
+  }
 }
diff --git a/service/src/main/java/io/mifos/teller/ServiceConstants.java b/service/src/main/java/io/mifos/teller/ServiceConstants.java
index adfef4e..2d5f000 100644
--- a/service/src/main/java/io/mifos/teller/ServiceConstants.java
+++ b/service/src/main/java/io/mifos/teller/ServiceConstants.java
@@ -17,6 +17,17 @@ package io.mifos.teller;
 
 public interface ServiceConstants {
   String LOGGER_NAME = "teller-logger";
+
   int ITERATION_COUNT = 2048;
   int LENGTH = 2048;
+
+  String TX_OPEN_ACCOUNT = "ACCO";
+  String TX_CLOSE_ACCOUNT = "ACCC";
+  String TX_ACCOUNT_TRANSFER = "BACT";
+  String TX_CASH_DEPOSIT = "BCDP";
+  String TX_CASH_WITHDRAWAL = "BCWD";
+
+  String TX_DEPOSIT_ADJUSTMENT = "DAJT";
+  String TX_CREDIT_ADJUSTMENT = "CAJT";
+  String TX_CHARGES = "CHRG";
 }
diff --git a/service/src/main/java/io/mifos/teller/TellerConfiguration.java b/service/src/main/java/io/mifos/teller/TellerConfiguration.java
index 5c60d5b..e6c70f6 100644
--- a/service/src/main/java/io/mifos/teller/TellerConfiguration.java
+++ b/service/src/main/java/io/mifos/teller/TellerConfiguration.java
@@ -63,7 +63,8 @@ import org.springframework.web.servlet.config.annotation.WebMvcConfigurerAdapter
     "io.mifos.teller.service.rest",
     "io.mifos.teller.service.internal.service",
     "io.mifos.teller.service.internal.repository",
-    "io.mifos.teller.service.internal.command.handler"
+    "io.mifos.teller.service.internal.command.handler",
+    "io.mifos.teller.service.internal.processor"
 })
 @EnableJpaRepositories({
     "io.mifos.teller.service.internal.repository"
diff --git a/api/src/main/java/io/mifos/teller/api/v1/domain/Charge.java b/service/src/main/java/io/mifos/teller/service/internal/command/AuthenticateTellerCommand.java
similarity index 51%
copy from api/src/main/java/io/mifos/teller/api/v1/domain/Charge.java
copy to service/src/main/java/io/mifos/teller/service/internal/command/AuthenticateTellerCommand.java
index e576a09..f1f5ce3 100644
--- a/api/src/main/java/io/mifos/teller/api/v1/domain/Charge.java
+++ b/service/src/main/java/io/mifos/teller/service/internal/command/AuthenticateTellerCommand.java
@@ -13,39 +13,25 @@
  * See the License for the specific language governing permissions and
  * limitations under the License.
  */
-package io.mifos.teller.api.v1.domain;
+package io.mifos.teller.service.internal.command;
 
-public class Charge {
+import io.mifos.teller.api.v1.domain.TellerAuthentication;
 
-  private String code;
-  private String name;
-  private Double amount;
+public class AuthenticateTellerCommand {
+  private final String tellerCode;
+  private final TellerAuthentication tellerAuthentication;
 
-  public Charge() {
+  public AuthenticateTellerCommand(final String tellerCode, final TellerAuthentication tellerAuthentication) {
     super();
+    this.tellerCode = tellerCode;
+    this.tellerAuthentication = tellerAuthentication;
   }
 
-  public String getCode() {
-    return this.code;
+  public String tellerCode() {
+    return this.tellerCode;
   }
 
-  public void setCode(final String code) {
-    this.code = code;
-  }
-
-  public String getName() {
-    return this.name;
-  }
-
-  public void setName(final String name) {
-    this.name = name;
-  }
-
-  public Double getAmount() {
-    return this.amount;
-  }
-
-  public void setAmount(final Double amount) {
-    this.amount = amount;
+  public TellerAuthentication tellerAuthentication() {
+    return this.tellerAuthentication;
   }
 }
diff --git a/service/src/main/java/io/mifos/teller/service/internal/service/TellerOperationService.java b/service/src/main/java/io/mifos/teller/service/internal/command/CancelTellerTransactionCommand.java
similarity index 59%
copy from service/src/main/java/io/mifos/teller/service/internal/service/TellerOperationService.java
copy to service/src/main/java/io/mifos/teller/service/internal/command/CancelTellerTransactionCommand.java
index 220abb6..91508e2 100644
--- a/service/src/main/java/io/mifos/teller/service/internal/service/TellerOperationService.java
+++ b/service/src/main/java/io/mifos/teller/service/internal/command/CancelTellerTransactionCommand.java
@@ -13,10 +13,17 @@
  * See the License for the specific language governing permissions and
  * limitations under the License.
  */
-package io.mifos.teller.service.internal.service;
+package io.mifos.teller.service.internal.command;
 
-import org.springframework.stereotype.Service;
+public class CancelTellerTransactionCommand {
+  private final String tellerTransactionIdentifier;
 
-@Service
-public class TellerOperationService {
+  public CancelTellerTransactionCommand(final String tellerTransactionIdentifier) {
+    super();
+    this.tellerTransactionIdentifier = tellerTransactionIdentifier;
+  }
+
+  public String tellerTransactionIdentifier() {
+    return this.tellerTransactionIdentifier;
+  }
 }
diff --git a/service/src/main/java/io/mifos/teller/service/internal/service/TellerOperationService.java b/service/src/main/java/io/mifos/teller/service/internal/command/ConfirmTellerTransactionCommand.java
similarity index 59%
copy from service/src/main/java/io/mifos/teller/service/internal/service/TellerOperationService.java
copy to service/src/main/java/io/mifos/teller/service/internal/command/ConfirmTellerTransactionCommand.java
index 220abb6..1da91da 100644
--- a/service/src/main/java/io/mifos/teller/service/internal/service/TellerOperationService.java
+++ b/service/src/main/java/io/mifos/teller/service/internal/command/ConfirmTellerTransactionCommand.java
@@ -13,10 +13,17 @@
  * See the License for the specific language governing permissions and
  * limitations under the License.
  */
-package io.mifos.teller.service.internal.service;
+package io.mifos.teller.service.internal.command;
 
-import org.springframework.stereotype.Service;
+public class ConfirmTellerTransactionCommand {
+  private final String tellerTransactionIdentifier;
 
-@Service
-public class TellerOperationService {
+  public ConfirmTellerTransactionCommand(final String tellerTransactionIdentifier) {
+    super();
+    this.tellerTransactionIdentifier = tellerTransactionIdentifier;
+  }
+
+  public String tellerTransactionIdentifier() {
+    return this.tellerTransactionIdentifier;
+  }
 }
diff --git a/api/src/main/java/io/mifos/teller/api/v1/domain/Charge.java b/service/src/main/java/io/mifos/teller/service/internal/command/InitializeTellerTransactionCommand.java
similarity index 52%
copy from api/src/main/java/io/mifos/teller/api/v1/domain/Charge.java
copy to service/src/main/java/io/mifos/teller/service/internal/command/InitializeTellerTransactionCommand.java
index e576a09..a8040ed 100644
--- a/api/src/main/java/io/mifos/teller/api/v1/domain/Charge.java
+++ b/service/src/main/java/io/mifos/teller/service/internal/command/InitializeTellerTransactionCommand.java
@@ -13,39 +13,25 @@
  * See the License for the specific language governing permissions and
  * limitations under the License.
  */
-package io.mifos.teller.api.v1.domain;
+package io.mifos.teller.service.internal.command;
 
-public class Charge {
+import io.mifos.teller.api.v1.domain.TellerTransaction;
 
-  private String code;
-  private String name;
-  private Double amount;
+public class InitializeTellerTransactionCommand {
+  private final String tellerCode;
+  private final TellerTransaction tellerTransaction;
 
-  public Charge() {
+  public InitializeTellerTransactionCommand(final String tellerCode, final TellerTransaction tellerTransaction) {
     super();
+    this.tellerCode = tellerCode;
+    this.tellerTransaction = tellerTransaction;
   }
 
-  public String getCode() {
-    return this.code;
+  public String tellerCode() {
+    return this.tellerCode;
   }
 
-  public void setCode(final String code) {
-    this.code = code;
-  }
-
-  public String getName() {
-    return this.name;
-  }
-
-  public void setName(final String name) {
-    this.name = name;
-  }
-
-  public Double getAmount() {
-    return this.amount;
-  }
-
-  public void setAmount(final Double amount) {
-    this.amount = amount;
+  public TellerTransaction tellerTransaction() {
+    return this.tellerTransaction;
   }
 }
diff --git a/service/src/main/java/io/mifos/teller/service/internal/service/TellerOperationService.java b/service/src/main/java/io/mifos/teller/service/internal/command/PauseTellerCommand.java
similarity index 67%
copy from service/src/main/java/io/mifos/teller/service/internal/service/TellerOperationService.java
copy to service/src/main/java/io/mifos/teller/service/internal/command/PauseTellerCommand.java
index 220abb6..a218c90 100644
--- a/service/src/main/java/io/mifos/teller/service/internal/service/TellerOperationService.java
+++ b/service/src/main/java/io/mifos/teller/service/internal/command/PauseTellerCommand.java
@@ -13,10 +13,17 @@
  * See the License for the specific language governing permissions and
  * limitations under the License.
  */
-package io.mifos.teller.service.internal.service;
+package io.mifos.teller.service.internal.command;
 
-import org.springframework.stereotype.Service;
+public class PauseTellerCommand {
+  private final String tellerCode;
 
-@Service
-public class TellerOperationService {
+  public PauseTellerCommand(final String tellerCode) {
+    super();
+    this.tellerCode = tellerCode;
+  }
+
+  public String tellerCode() {
+    return this.tellerCode;
+  }
 }
diff --git a/service/src/main/java/io/mifos/teller/service/internal/command/handler/TellerAggregate.java b/service/src/main/java/io/mifos/teller/service/internal/command/handler/TellerAggregate.java
index 9fb534f..60abcb2 100644
--- a/service/src/main/java/io/mifos/teller/service/internal/command/handler/TellerAggregate.java
+++ b/service/src/main/java/io/mifos/teller/service/internal/command/handler/TellerAggregate.java
@@ -24,14 +24,18 @@ import io.mifos.core.command.annotation.Aggregate;
 import io.mifos.core.command.annotation.CommandHandler;
 import io.mifos.core.command.annotation.EventEmitter;
 import io.mifos.core.lang.DateConverter;
+import io.mifos.core.lang.ServiceException;
 import io.mifos.teller.ServiceConstants;
 import io.mifos.teller.api.v1.EventConstants;
 import io.mifos.teller.api.v1.domain.Teller;
+import io.mifos.teller.api.v1.domain.TellerAuthentication;
 import io.mifos.teller.api.v1.domain.TellerManagementCommand;
+import io.mifos.teller.service.internal.command.AuthenticateTellerCommand;
 import io.mifos.teller.service.internal.command.ChangeTellerCommand;
 import io.mifos.teller.service.internal.command.CloseTellerCommand;
 import io.mifos.teller.service.internal.command.CreateTellerCommand;
 import io.mifos.teller.service.internal.command.OpenTellerCommand;
+import io.mifos.teller.service.internal.command.PauseTellerCommand;
 import io.mifos.teller.service.internal.mapper.TellerMapper;
 import io.mifos.teller.service.internal.repository.TellerEntity;
 import io.mifos.teller.service.internal.repository.TellerRepository;
@@ -113,7 +117,9 @@ public class TellerAggregate {
       if (optionalTellerEntity.isPresent()) {
         final TellerEntity tellerEntity = optionalTellerEntity.get();
 
-        this.encryptPassword(teller, tellerEntity);
+        if (teller.getPassword() != null) {
+          this.encryptPassword(teller, tellerEntity);
+        }
 
         tellerEntity.setTellerAccountIdentifier(teller.getTellerAccountIdentifier());
         tellerEntity.setVaultAccountIdentifier(teller.getVaultAccountIdentifier());
@@ -145,7 +151,9 @@ public class TellerAggregate {
 
       if (this.checkPreconditions(tellerEntity.getOfficeIdentifier(), TellerMapper.map(tellerEntity))) {
 
-        if (tellerManagementCommand.getAmount() != null && tellerManagementCommand.getAmount() > 0.00D) {
+        if (!tellerManagementCommand.getAdjustment().equals(TellerManagementCommand.Adjustment.NONE.name())
+            && tellerManagementCommand.getAmount() != null
+            && tellerManagementCommand.getAmount() > 0.00D) {
           this.accountingService.postJournalEntry(this.createJournalEntry(tellerEntity, tellerManagementCommand));
         }
 
@@ -177,7 +185,9 @@ public class TellerAggregate {
 
       if (this.checkPreconditions(tellerEntity.getOfficeIdentifier(), TellerMapper.map(tellerEntity))) {
 
-        if (tellerManagementCommand.getAmount() != null && tellerManagementCommand.getAmount() > 0.00D) {
+        if (!tellerManagementCommand.getAdjustment().equals(TellerManagementCommand.Adjustment.NONE.name())
+            && tellerManagementCommand.getAmount() != null
+            && tellerManagementCommand.getAmount() > 0.00D) {
           this.accountingService.postJournalEntry(this.createJournalEntry(tellerEntity, tellerManagementCommand));
         }
         tellerEntity.setAssignedEmployeeIdentifier(null);
@@ -195,6 +205,69 @@ public class TellerAggregate {
     }
   }
 
+  @Transactional
+  @CommandHandler
+  @EventEmitter(selectorName = EventConstants.SELECTOR_NAME, selectorValue = EventConstants.AUTHENTICATE_TELLER)
+  public String process(final AuthenticateTellerCommand authenticateTellerCommand) {
+    final String tellerCode = authenticateTellerCommand.tellerCode();
+    final TellerAuthentication tellerAuthentication = authenticateTellerCommand.tellerAuthentication();
+
+    final Optional<TellerEntity> optionalTeller = this.tellerRepository.findByIdentifier(tellerCode);
+    if (optionalTeller.isPresent()) {
+      final TellerEntity tellerEntity = optionalTeller.get();
+      if (!tellerEntity.getState().equals(Teller.State.OPEN.name())
+          && !tellerEntity.getState().equals(Teller.State.PAUSED.name())) {
+        throw ServiceException.notFound("Teller {0} not found.", tellerCode);
+      }
+
+      if (!UserContextHolder.checkedGetUser().equals(tellerEntity.getAssignedEmployeeIdentifier())) {
+        throw ServiceException.notFound("Teller {0} not found.", tellerCode);
+      }
+
+      final byte[] givenPassword = this.hashGenerator.hash(new String(tellerAuthentication.getPassword()),
+          Base64Utils.decodeFromString(tellerEntity.getSalt()), ServiceConstants.ITERATION_COUNT, ServiceConstants.LENGTH);
+
+      if (!tellerEntity.getPassword().equals(Base64Utils.encodeToString(givenPassword))) {
+        throw ServiceException.notFound("Teller {0} not found.", tellerCode);
+      }
+
+      tellerEntity.setState(Teller.State.ACTIVE.name());
+      tellerEntity.setLastModifiedBy(UserContextHolder.checkedGetUser());
+      tellerEntity.setLastModifiedOn(LocalDateTime.now(Clock.systemUTC()));
+      this.tellerRepository.save(tellerEntity);
+
+      return tellerCode;
+    } else {
+      throw ServiceException.notFound("Teller {0} not found.", tellerCode);
+    }
+  }
+
+  @Transactional
+  @CommandHandler
+  @EventEmitter(selectorName = EventConstants.SELECTOR_NAME, selectorValue = EventConstants.PAUSE_TELLER)
+  public String process(final PauseTellerCommand pauseTellerCommand) {
+    final String tellerCode = pauseTellerCommand.tellerCode();
+
+    final Optional<TellerEntity> optionalTeller = this.tellerRepository.findByIdentifier(tellerCode);
+    if (optionalTeller.isPresent()) {
+      final TellerEntity tellerEntity = optionalTeller.get();
+      if (UserContextHolder.checkedGetUser().equals(tellerEntity.getAssignedEmployeeIdentifier())
+          && tellerEntity.getState().equals(Teller.State.ACTIVE.name())) {
+        tellerEntity.setState(Teller.State.PAUSED.name());
+        tellerEntity.setLastModifiedBy(UserContextHolder.checkedGetUser());
+        tellerEntity.setLastModifiedOn(LocalDateTime.now(Clock.systemUTC()));
+        this.tellerRepository.save(tellerEntity);
+
+        return tellerCode;
+      } else {
+        this.logger.warn("Unable to pause teller {}.", tellerCode);
+      }
+    } else {
+      this.logger.warn("Teller {} not found.", tellerCode);
+    }
+    return null;
+  }
+
   private boolean checkPreconditions(final String officeIdentifier, final Teller teller) {
     boolean pass = true;
 
@@ -245,7 +318,7 @@ public class TellerAggregate {
     final Creditor creditor = new Creditor();
     switch (adjustment) {
       case DEBIT:
-        journalEntry.setTransactionType("DAJT");
+        journalEntry.setTransactionType(ServiceConstants.TX_DEPOSIT_ADJUSTMENT);
 
         debtor.setAccountNumber(tellerEntity.getTellerAccountIdentifier());
         debtor.setAmount(tellerManagementCommand.getAmount().toString());
@@ -257,7 +330,7 @@ public class TellerAggregate {
 
         break;
       case CREDIT:
-        journalEntry.setTransactionType("CAJT");
+        journalEntry.setTransactionType(ServiceConstants.TX_CREDIT_ADJUSTMENT);
 
         debtor.setAccountNumber(tellerEntity.getVaultAccountIdentifier());
         debtor.setAmount(tellerManagementCommand.getAmount().toString());
diff --git a/service/src/main/java/io/mifos/teller/service/internal/command/handler/TellerTransactionAggregate.java b/service/src/main/java/io/mifos/teller/service/internal/command/handler/TellerTransactionAggregate.java
new file mode 100644
index 0000000..5d59db4
--- /dev/null
+++ b/service/src/main/java/io/mifos/teller/service/internal/command/handler/TellerTransactionAggregate.java
@@ -0,0 +1,124 @@
+/*
+ * 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.
+ */
+package io.mifos.teller.service.internal.command.handler;
+
+import io.mifos.core.command.annotation.Aggregate;
+import io.mifos.core.command.annotation.CommandHandler;
+import io.mifos.core.command.annotation.EventEmitter;
+import io.mifos.teller.ServiceConstants;
+import io.mifos.teller.api.v1.EventConstants;
+import io.mifos.teller.api.v1.domain.TellerTransaction;
+import io.mifos.teller.api.v1.domain.TellerTransactionCosts;
+import io.mifos.teller.service.internal.command.CancelTellerTransactionCommand;
+import io.mifos.teller.service.internal.command.ConfirmTellerTransactionCommand;
+import io.mifos.teller.service.internal.command.InitializeTellerTransactionCommand;
+import io.mifos.teller.service.internal.mapper.TellerTransactionMapper;
+import io.mifos.teller.service.internal.processor.TellerTransactionProcessor;
+import io.mifos.teller.service.internal.repository.TellerEntity;
+import io.mifos.teller.service.internal.repository.TellerRepository;
+import io.mifos.teller.service.internal.repository.TellerTransactionEntity;
+import io.mifos.teller.service.internal.repository.TellerTransactionRepository;
+import org.apache.commons.lang.RandomStringUtils;
+import org.slf4j.Logger;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.beans.factory.annotation.Qualifier;
+import org.springframework.transaction.annotation.Transactional;
+
+import java.util.Optional;
+
+@Aggregate
+public class TellerTransactionAggregate {
+
+  private final Logger logger;
+  private final TellerTransactionRepository tellerTransactionRepository;
+  private final TellerTransactionProcessor tellerTransactionProcessor;
+  private final TellerRepository tellerRepository;
+
+  @Autowired
+  public TellerTransactionAggregate(@Qualifier(ServiceConstants.LOGGER_NAME) final Logger logger,
+                                    final TellerTransactionRepository tellerTransactionRepository,
+                                    final TellerTransactionProcessor tellerTransactionProcessor,
+                                    final TellerRepository tellerRepository) {
+    super();
+    this.logger = logger;
+    this.tellerTransactionRepository = tellerTransactionRepository;
+    this.tellerTransactionProcessor = tellerTransactionProcessor;
+    this.tellerRepository = tellerRepository;
+  }
+
+  @Transactional
+  @CommandHandler
+  @EventEmitter(selectorName = EventConstants.SELECTOR_NAME, selectorValue = EventConstants.INIT_TRANSACTION)
+  public TellerTransactionCosts process(final InitializeTellerTransactionCommand initializeTellerTransactionCommand) {
+    final String tellerCode = initializeTellerTransactionCommand.tellerCode();
+    final TellerTransaction tellerTransaction = initializeTellerTransactionCommand.tellerTransaction();
+
+    final Optional<TellerEntity> optionalTeller = this.tellerRepository.findByIdentifier(tellerCode);
+    if (optionalTeller.isPresent()) {
+      tellerTransaction.setIdentifier(RandomStringUtils.randomAlphanumeric(32));
+      tellerTransaction.setState(TellerTransaction.State.PENDING.name());
+      final TellerTransactionEntity tellerTransactionEntity = TellerTransactionMapper.map(tellerTransaction);
+      tellerTransactionEntity.setTeller(optionalTeller.get());
+      this.tellerTransactionRepository.save(tellerTransactionEntity);
+      return this.tellerTransactionProcessor.getCosts(tellerTransaction);
+    } else {
+      this.logger.warn("Teller {} not found.", tellerCode);
+    }
+    return null;
+  }
+
+  @Transactional
+  @CommandHandler
+  @EventEmitter(selectorName = EventConstants.SELECTOR_NAME, selectorValue = EventConstants.CONFIRM_TRANSACTION)
+  public String process(final ConfirmTellerTransactionCommand confirmTellerTransactionCommand) {
+    final Optional<TellerTransactionEntity> optionalTellerTransaction =
+        this.tellerTransactionRepository.findByIdentifier(confirmTellerTransactionCommand.tellerTransactionIdentifier());
+
+    if (optionalTellerTransaction.isPresent()) {
+      final TellerTransactionEntity tellerTransactionEntity = optionalTellerTransaction.get();
+
+      this.tellerTransactionProcessor.process(tellerTransactionEntity.getTeller().getIdentifier(),
+          TellerTransactionMapper.map(tellerTransactionEntity));
+
+      tellerTransactionEntity.setState(TellerTransaction.State.CONFIRMED.name());
+      this.tellerTransactionRepository.save(tellerTransactionEntity);
+
+      return confirmTellerTransactionCommand.tellerTransactionIdentifier();
+    } else {
+      this.logger.warn("Teller transaction {} not found", confirmTellerTransactionCommand.tellerTransactionIdentifier());
+    }
+    return null;
+  }
+
+  @Transactional
+  @CommandHandler
+  @EventEmitter(selectorName = EventConstants.SELECTOR_NAME, selectorValue = EventConstants.CANCEL_TRANSACTION)
+  public String process(final CancelTellerTransactionCommand cancelTellerTransactionCommand) {
+    final Optional<TellerTransactionEntity> optionalTellerTransaction =
+        this.tellerTransactionRepository.findByIdentifier(cancelTellerTransactionCommand.tellerTransactionIdentifier());
+
+    if (optionalTellerTransaction.isPresent()) {
+      final TellerTransactionEntity tellerTransactionEntity = optionalTellerTransaction.get();
+      tellerTransactionEntity.setState(TellerTransaction.State.CANCELED.name());
+      this.tellerTransactionRepository.save(tellerTransactionEntity);
+
+      return cancelTellerTransactionCommand.tellerTransactionIdentifier();
+    } else {
+      this.logger.warn("Teller transaction {} not found", cancelTellerTransactionCommand.tellerTransactionIdentifier());
+    }
+    return null;
+  }
+}
diff --git a/service/src/main/java/io/mifos/teller/service/internal/mapper/TellerMapper.java b/service/src/main/java/io/mifos/teller/service/internal/mapper/TellerMapper.java
index bfb83af..d1902a4 100644
--- a/service/src/main/java/io/mifos/teller/service/internal/mapper/TellerMapper.java
+++ b/service/src/main/java/io/mifos/teller/service/internal/mapper/TellerMapper.java
@@ -28,7 +28,6 @@ public class TellerMapper {
   public static Teller map(final TellerEntity tellerEntity) {
     final Teller teller = new Teller();
     teller.setCode(tellerEntity.getIdentifier());
-    teller.setPassword(tellerEntity.getPassword());
     teller.setTellerAccountIdentifier(tellerEntity.getTellerAccountIdentifier());
     teller.setVaultAccountIdentifier(tellerEntity.getVaultAccountIdentifier());
     teller.setCashdrawLimit(tellerEntity.getCashdrawLimit());
diff --git a/service/src/main/java/io/mifos/teller/service/internal/mapper/TellerTransactionMapper.java b/service/src/main/java/io/mifos/teller/service/internal/mapper/TellerTransactionMapper.java
new file mode 100644
index 0000000..1073219
--- /dev/null
+++ b/service/src/main/java/io/mifos/teller/service/internal/mapper/TellerTransactionMapper.java
@@ -0,0 +1,59 @@
+/*
+ * 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.
+ */
+package io.mifos.teller.service.internal.mapper;
+
+import io.mifos.core.lang.DateConverter;
+import io.mifos.teller.api.v1.domain.TellerTransaction;
+import io.mifos.teller.service.internal.repository.TellerTransactionEntity;
+
+public class TellerTransactionMapper {
+
+  private TellerTransactionMapper() {
+    super();
+  }
+
+  public static TellerTransaction map(final TellerTransactionEntity tellerTransactionEntity) {
+    final TellerTransaction tellerTransaction = new TellerTransaction();
+    tellerTransaction.setIdentifier(tellerTransactionEntity.getIdentifier());
+    tellerTransaction.setTransactionType(tellerTransactionEntity.getTransactionType());
+    tellerTransaction.setTransactionDate(DateConverter.toIsoString(tellerTransactionEntity.getTransactionDate()));
+    tellerTransaction.setProductIdentifier(tellerTransactionEntity.getProductIdentifier());
+    tellerTransaction.setProductCaseIdentifier(tellerTransactionEntity.getProductCaseIdentifier());
+    tellerTransaction.setCustomerAccountIdentifier(tellerTransactionEntity.getCustomerAccountIdentifier());
+    tellerTransaction.setTargetAccountIdentifier(tellerTransactionEntity.getTargetAccountIdentifier());
+    tellerTransaction.setAmount(tellerTransactionEntity.getAmount());
+    tellerTransaction.setClerk(tellerTransactionEntity.getClerk());
+    tellerTransaction.setState(tellerTransactionEntity.getState());
+
+    return tellerTransaction;
+  }
+
+  public static TellerTransactionEntity map(final TellerTransaction tellerTransaction) {
+    final TellerTransactionEntity tellerTransactionEntity = new TellerTransactionEntity();
+    tellerTransactionEntity.setIdentifier(tellerTransaction.getIdentifier());
+    tellerTransactionEntity.setTransactionType(tellerTransaction.getTransactionType());
+    tellerTransactionEntity.setTransactionDate(DateConverter.fromIsoString(tellerTransaction.getTransactionDate()));
+    tellerTransactionEntity.setProductIdentifier(tellerTransaction.getProductIdentifier());
+    tellerTransactionEntity.setProductCaseIdentifier(tellerTransaction.getProductCaseIdentifier());
+    tellerTransactionEntity.setCustomerAccountIdentifier(tellerTransaction.getCustomerAccountIdentifier());
+    tellerTransactionEntity.setTargetAccountIdentifier(tellerTransaction.getTargetAccountIdentifier());
+    tellerTransactionEntity.setAmount(tellerTransaction.getAmount());
+    tellerTransactionEntity.setClerk(tellerTransaction.getClerk());
+    tellerTransactionEntity.setState(tellerTransaction.getState());
+
+    return tellerTransactionEntity;
+  }
+}
diff --git a/service/src/main/java/io/mifos/teller/service/internal/processor/TellerTransactionProcessor.java b/service/src/main/java/io/mifos/teller/service/internal/processor/TellerTransactionProcessor.java
new file mode 100644
index 0000000..e9c9329
--- /dev/null
+++ b/service/src/main/java/io/mifos/teller/service/internal/processor/TellerTransactionProcessor.java
@@ -0,0 +1,251 @@
+/*
+ * 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.
+ */
+package io.mifos.teller.service.internal.processor;
+
+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.core.api.util.UserContextHolder;
+import io.mifos.deposit.api.v1.instance.domain.ProductInstance;
+import io.mifos.teller.ServiceConstants;
+import io.mifos.teller.api.v1.domain.Charge;
+import io.mifos.teller.api.v1.domain.TellerTransaction;
+import io.mifos.teller.api.v1.domain.TellerTransactionCosts;
+import io.mifos.teller.service.internal.repository.TellerEntity;
+import io.mifos.teller.service.internal.repository.TellerRepository;
+import io.mifos.teller.service.internal.service.helper.AccountingService;
+import io.mifos.teller.service.internal.service.helper.DepositAccountManagementService;
+import org.slf4j.Logger;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.beans.factory.annotation.Qualifier;
+import org.springframework.stereotype.Component;
+
+import java.util.HashSet;
+import java.util.List;
+import java.util.Optional;
+import java.util.Set;
+import java.util.stream.Collectors;
+
+@Component
+public class TellerTransactionProcessor {
+
+  private final Logger logger;
+  private final AccountingService accountingService;
+  private final DepositAccountManagementService depositAccountManagementService;
+  private final TellerRepository tellerRepository;
+
+  @Autowired
+  public TellerTransactionProcessor(@Qualifier(ServiceConstants.LOGGER_NAME) final Logger logger,
+                                    final AccountingService accountingService,
+                                    final DepositAccountManagementService depositAccountManagementService,
+                                    final TellerRepository tellerRepository) {
+    super();
+    this.logger = logger;
+    this.accountingService = accountingService;
+    this.depositAccountManagementService = depositAccountManagementService;
+    this.tellerRepository = tellerRepository;
+  }
+
+  public void process(final String tellerCode, final TellerTransaction tellerTransaction) {
+    switch (tellerTransaction.getTransactionType()) {
+      case ServiceConstants.TX_OPEN_ACCOUNT:
+        this.processDepositAccountOpening(tellerCode, tellerTransaction);
+        break;
+      case ServiceConstants.TX_CLOSE_ACCOUNT:
+        this.processDepositAccountClosing(tellerCode, tellerTransaction);
+        break;
+      case ServiceConstants.TX_ACCOUNT_TRANSFER:
+        this.processTransfer(tellerTransaction);
+        break;
+      case ServiceConstants.TX_CASH_DEPOSIT:
+        this.processCashDeposit(tellerCode, tellerTransaction);
+        break;
+      case ServiceConstants.TX_CASH_WITHDRAWAL:
+        this.processCashWithdrawal(tellerCode, tellerTransaction);
+        break;
+      default:
+        throw new IllegalArgumentException("Unsupported TX type " + tellerTransaction.getTransactionType());
+    }
+  }
+
+  public TellerTransactionCosts getCosts(final TellerTransaction tellerTransaction) {
+    switch (tellerTransaction.getTransactionType()) {
+      case ServiceConstants.TX_OPEN_ACCOUNT:
+      case ServiceConstants.TX_CLOSE_ACCOUNT:
+      case ServiceConstants.TX_ACCOUNT_TRANSFER:
+      case ServiceConstants.TX_CASH_DEPOSIT:
+      case ServiceConstants.TX_CASH_WITHDRAWAL:
+        return this.depositAccountCosts(tellerTransaction);
+      default:
+        throw new IllegalArgumentException("Unsupported TX type " + tellerTransaction.getTransactionType());
+    }
+  }
+
+  private TellerTransactionCosts depositAccountCosts(final TellerTransaction tellerTransaction) {
+    final List<Charge> charges = this.depositAccountManagementService.getCharges(tellerTransaction);
+
+    final TellerTransactionCosts tellerTransactionCosts = new TellerTransactionCosts();
+    tellerTransactionCosts.setCharges(charges);
+    tellerTransactionCosts.setTellerTransactionIdentifier(tellerTransaction.getIdentifier());
+    tellerTransactionCosts.setTotalAmount(tellerTransaction.getAmount() + charges.stream().mapToDouble(Charge::getAmount).sum());
+
+    return tellerTransactionCosts;
+  }
+
+  private void processTransfer(final TellerTransaction tellerTransaction) {
+    final JournalEntry journalEntry = this.prepareJournalEntry(tellerTransaction);
+
+    final TellerTransactionCosts tellerTransactionCosts = this.depositAccountCosts(tellerTransaction);
+
+    final HashSet<Debtor> debtors = new HashSet<>();
+    journalEntry.setDebtors(debtors);
+
+    final Debtor debtor = new Debtor();
+    debtor.setAccountNumber(tellerTransaction.getCustomerAccountIdentifier());
+    debtor.setAmount(tellerTransactionCosts.getTotalAmount().toString());
+    debtors.add(debtor);
+
+    final HashSet<Creditor> creditors = new HashSet<>();
+    journalEntry.setCreditors(creditors);
+
+    final Creditor targetCreditor = new Creditor();
+    targetCreditor.setAccountNumber(tellerTransaction.getTargetAccountIdentifier());
+    targetCreditor.setAmount(tellerTransaction.getAmount().toString());
+    creditors.add(targetCreditor);
+
+    creditors.addAll(this.createChargeCreditors(tellerTransactionCosts));
+
+    this.accountingService.postJournalEntry(journalEntry);
+  }
+
+  private void processCashDeposit(final String tellerCode, final TellerTransaction tellerTransaction) {
+    final Optional<TellerEntity> optionalTeller = this.tellerRepository.findByIdentifier(tellerCode);
+    if (!optionalTeller.isPresent()) {
+      this.logger.warn("Teller {} not found.", tellerCode);
+      throw new IllegalStateException("Teller not found.");
+    }
+
+    final TellerEntity tellerEntity = optionalTeller.get();
+    final JournalEntry journalEntry = this.prepareJournalEntry(tellerTransaction);
+    final TellerTransactionCosts tellerTransactionCosts = this.depositAccountCosts(tellerTransaction);
+
+    final HashSet<Debtor> debtors = new HashSet<>();
+    journalEntry.setDebtors(debtors);
+
+    final Debtor tellerDebtor = new Debtor();
+    tellerDebtor.setAccountNumber(tellerEntity.getTellerAccountIdentifier());
+    tellerDebtor.setAmount(tellerTransaction.getAmount().toString());
+    debtors.add(tellerDebtor);
+
+    final Double chargesTotal = tellerTransactionCosts.getTotalAmount() - tellerTransaction.getAmount();
+    final Debtor customerDebtor = new Debtor();
+    customerDebtor.setAccountNumber(tellerTransaction.getCustomerAccountIdentifier());
+    customerDebtor.setAmount(chargesTotal.toString());
+
+    final HashSet<Creditor> creditors = new HashSet<>();
+    journalEntry.setCreditors(creditors);
+
+    final Creditor customerCreditor = new Creditor();
+    customerCreditor.setAccountNumber(tellerTransaction.getCustomerAccountIdentifier());
+    customerCreditor.setAmount(tellerTransaction.getAmount().toString());
+    creditors.add(customerCreditor);
+
+    creditors.addAll(this.createChargeCreditors(tellerTransactionCosts));
+
+    this.accountingService.postJournalEntry(journalEntry);
+  }
+
+  private void processCashWithdrawal(final String tellerCode, final TellerTransaction tellerTransaction) {
+    final Optional<TellerEntity> optionalTeller = this.tellerRepository.findByIdentifier(tellerCode);
+    if (!optionalTeller.isPresent()) {
+      this.logger.warn("Teller {} not found.", tellerCode);
+      throw new IllegalStateException("Teller not found.");
+    }
+
+    final TellerEntity tellerEntity = optionalTeller.get();
+    final JournalEntry journalEntry = this.prepareJournalEntry(tellerTransaction);
+    final TellerTransactionCosts tellerTransactionCosts = this.depositAccountCosts(tellerTransaction);
+
+    final HashSet<Debtor> debtors = new HashSet<>();
+    journalEntry.setDebtors(debtors);
+
+    final Debtor customerDebtor = new Debtor();
+    customerDebtor.setAccountNumber(tellerTransaction.getCustomerAccountIdentifier());
+    customerDebtor.setAmount(tellerTransactionCosts.getTotalAmount().toString());
+
+    final HashSet<Creditor> creditors = new HashSet<>();
+    journalEntry.setCreditors(creditors);
+
+    final Creditor tellerCreditor = new Creditor();
+    tellerCreditor.setAccountNumber(tellerEntity.getTellerAccountIdentifier());
+    tellerCreditor.setAmount(tellerTransaction.getAmount().toString());
+    creditors.add(tellerCreditor);
+
+    creditors.addAll(this.createChargeCreditors(tellerTransactionCosts));
+
+    this.accountingService.postJournalEntry(journalEntry);
+  }
+
+  private void processDepositAccountClosing(final String tellerCode, final TellerTransaction tellerTransaction) {
+    final List<ProductInstance> productInstances =
+        this.depositAccountManagementService.getProductInstance(tellerTransaction.getCustomerIdentifier());
+
+    this.processCashWithdrawal(tellerCode, tellerTransaction);
+
+    productInstances.forEach(productInstance -> {
+      if (productInstance.getAccountIdentifier().equals(tellerTransaction.getCustomerAccountIdentifier())) {
+        this.depositAccountManagementService.closeProductInstance(tellerTransaction.getCustomerAccountIdentifier());
+        this.accountingService.closeAccount(tellerTransaction.getCustomerAccountIdentifier());
+      }
+    });
+  }
+
+  private void processDepositAccountOpening(final String tellerCode, final TellerTransaction tellerTransaction) {
+    final List<ProductInstance> productInstances =
+        this.depositAccountManagementService.getProductInstance(tellerTransaction.getCustomerIdentifier());
+
+    this.processCashDeposit(tellerCode, tellerTransaction);
+
+    productInstances.forEach(productInstance -> {
+      if (productInstance.getAccountIdentifier().equals(tellerTransaction.getCustomerAccountIdentifier())) {
+        this.depositAccountManagementService.activateProductInstance(tellerTransaction.getCustomerAccountIdentifier());
+        this.accountingService.openAccount(tellerTransaction.getCustomerAccountIdentifier());
+      }
+    });
+  }
+
+  private JournalEntry prepareJournalEntry(final TellerTransaction tellerTransaction) {
+    final JournalEntry journalEntry = new JournalEntry();
+    journalEntry.setTransactionIdentifier(tellerTransaction.getIdentifier());
+    journalEntry.setTransactionDate(tellerTransaction.getTransactionDate());
+    journalEntry.setTransactionType(tellerTransaction.getTransactionType());
+    journalEntry.setClerk(UserContextHolder.checkedGetUser());
+
+    return journalEntry;
+  }
+
+  private Set<Creditor> createChargeCreditors(final TellerTransactionCosts tellerTransactionCosts) {
+    return tellerTransactionCosts.getCharges()
+        .stream()
+        .map(charge -> {
+          final Creditor chargeCreditor = new Creditor();
+          chargeCreditor.setAccountNumber(charge.getIncomeAccountIdentifier());
+          chargeCreditor.setAmount(charge.getAmount().toString());
+          return chargeCreditor;
+        })
+        .collect(Collectors.toSet());
+  }
+}
diff --git a/api/src/main/java/io/mifos/teller/api/v1/domain/TellerTransaction.java b/service/src/main/java/io/mifos/teller/service/internal/repository/TellerTransactionEntity.java
similarity index 55%
copy from api/src/main/java/io/mifos/teller/api/v1/domain/TellerTransaction.java
copy to service/src/main/java/io/mifos/teller/service/internal/repository/TellerTransactionEntity.java
index 5dc8ffa..f880906 100644
--- a/api/src/main/java/io/mifos/teller/api/v1/domain/TellerTransaction.java
+++ b/service/src/main/java/io/mifos/teller/service/internal/repository/TellerTransactionEntity.java
@@ -13,46 +13,76 @@
  * See the License for the specific language governing permissions and
  * limitations under the License.
  */
-package io.mifos.teller.api.v1.domain;
-
-import io.mifos.core.lang.validation.constraints.ValidIdentifier;
-
-import javax.validation.constraints.DecimalMin;
-import javax.validation.constraints.NotNull;
-
-public class TellerTransaction {
-
-  public enum State {
-    PENDING,
-    CANCELED,
-    CONFIRMED
-  }
-
-  @ValidIdentifier(optional = true)
+package io.mifos.teller.service.internal.repository;
+
+import io.mifos.core.mariadb.util.LocalDateTimeConverter;
+
+import javax.persistence.CascadeType;
+import javax.persistence.Column;
+import javax.persistence.Convert;
+import javax.persistence.Entity;
+import javax.persistence.FetchType;
+import javax.persistence.GeneratedValue;
+import javax.persistence.GenerationType;
+import javax.persistence.Id;
+import javax.persistence.JoinColumn;
+import javax.persistence.ManyToOne;
+import javax.persistence.Table;
+import java.time.LocalDateTime;
+
+@Entity
+@Table(name = "tajet_teller_transactions")
+public class TellerTransactionEntity {
+
+  @Id
+  @GeneratedValue(strategy = GenerationType.IDENTITY)
+  @Column(name = "id", nullable = false)
+  private Long id;
+  @ManyToOne(optional = false, fetch = FetchType.EAGER, cascade = CascadeType.ALL)
+  @JoinColumn(name = "teller_id")
+  private TellerEntity teller;
+  @Column(name = "identifier", nullable = false, length = 32)
   private String identifier;
-  @NotNull
+  @Column(name = "transaction_type", nullable = false, length = 32)
   private String transactionType;
-  @NotNull
-  private String transactionDate;
-  @ValidIdentifier
+  @Column(name = "transaction_date", nullable = false)
+  @Convert(converter = LocalDateTimeConverter.class)
+  private LocalDateTime transactionDate;
+  @Column(name = "product_identifier", nullable = false, length = 32)
   private String productIdentifier;
-  @ValidIdentifier(optional = true)
+  @Column(name = "product_case_identifier", nullable = true, length = 32)
   private String productCaseIdentifier;
-  @ValidIdentifier
+  @Column(name = "customer_account_identifier", nullable = false, length = 32)
   private String customerAccountIdentifier;
-  @ValidIdentifier(optional = true)
+  @Column(name = "target_account_identifier", nullable = true, length = 32)
   private String targetAccountIdentifier;
-  @ValidIdentifier
+  @Column(name = "clerk", nullable = false, length = 32)
   private String clerk;
-  @NotNull
-  @DecimalMin("0.00")
+  @Column(name = "amount", nullable = false)
   private Double amount;
-  private State state;
+  @Column(name = "a_state", nullable = false, length = 256)
+  private String state;
 
-  public TellerTransaction() {
+  public TellerTransactionEntity() {
     super();
   }
 
+  public Long getId() {
+    return this.id;
+  }
+
+  public void setId(final Long id) {
+    this.id = id;
+  }
+
+  public TellerEntity getTeller() {
+    return this.teller;
+  }
+
+  public void setTeller(final TellerEntity teller) {
+    this.teller = teller;
+  }
+
   public String getIdentifier() {
     return this.identifier;
   }
@@ -69,11 +99,11 @@ public class TellerTransaction {
     this.transactionType = transactionType;
   }
 
-  public String getTransactionDate() {
+  public LocalDateTime getTransactionDate() {
     return this.transactionDate;
   }
 
-  public void setTransactionDate(final String transactionDate) {
+  public void setTransactionDate(final LocalDateTime transactionDate) {
     this.transactionDate = transactionDate;
   }
 
@@ -126,10 +156,10 @@ public class TellerTransaction {
   }
 
   public String getState() {
-    return this.state.name();
+    return this.state;
   }
 
   public void setState(final String state) {
-    this.state = State.valueOf(state);
+    this.state = state;
   }
 }
diff --git a/service/src/main/java/io/mifos/teller/service/internal/repository/TellerTransactionRepository.java b/service/src/main/java/io/mifos/teller/service/internal/repository/TellerTransactionRepository.java
new file mode 100644
index 0000000..aea3864
--- /dev/null
+++ b/service/src/main/java/io/mifos/teller/service/internal/repository/TellerTransactionRepository.java
@@ -0,0 +1,32 @@
+/*
+ * 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.
+ */
+package io.mifos.teller.service.internal.repository;
+
+import org.springframework.data.jpa.repository.JpaRepository;
+import org.springframework.stereotype.Repository;
+
+import java.util.List;
+import java.util.Optional;
+
+@Repository
+public interface TellerTransactionRepository extends JpaRepository<TellerTransactionEntity, Long> {
+  Optional<TellerTransactionEntity> findByIdentifier(final String tellerTransactionIdentifier);
+
+  List<TellerTransactionEntity> findByTellerOrderByTransactionDateAsc(final TellerEntity teller);
+
+  List<TellerTransactionEntity> findByTellerAndStateOrderByTransactionDateAsc(final TellerEntity teller,
+                                                                              final String state);
+}
diff --git a/service/src/main/java/io/mifos/teller/service/internal/service/TellerOperationService.java b/service/src/main/java/io/mifos/teller/service/internal/service/TellerOperationService.java
index 220abb6..da7f2ae 100644
--- a/service/src/main/java/io/mifos/teller/service/internal/service/TellerOperationService.java
+++ b/service/src/main/java/io/mifos/teller/service/internal/service/TellerOperationService.java
@@ -15,8 +15,61 @@
  */
 package io.mifos.teller.service.internal.service;
 
+import io.mifos.core.lang.ServiceException;
+import io.mifos.teller.ServiceConstants;
+import io.mifos.teller.api.v1.domain.TellerTransaction;
+import io.mifos.teller.service.internal.mapper.TellerTransactionMapper;
+import io.mifos.teller.service.internal.repository.TellerEntity;
+import io.mifos.teller.service.internal.repository.TellerRepository;
+import io.mifos.teller.service.internal.repository.TellerTransactionRepository;
+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.List;
+import java.util.Optional;
+import java.util.stream.Collectors;
+
+
 @Service
 public class TellerOperationService {
+
+  private final Logger logger;
+  private final TellerRepository tellerRepository;
+  private final TellerTransactionRepository tellerTransactionRepository;
+
+  @Autowired
+  public TellerOperationService(@Qualifier(ServiceConstants.LOGGER_NAME) final Logger logger,
+                                final TellerRepository tellerRepository,
+                                final TellerTransactionRepository tellerTransactionRepository) {
+    super();
+    this.logger = logger;
+    this.tellerRepository = tellerRepository;
+    this.tellerTransactionRepository = tellerTransactionRepository;
+  }
+
+  public boolean tellerTransactionExists(final String tellerTransactionIdentifier) {
+    return this.tellerTransactionRepository.findByIdentifier(tellerTransactionIdentifier).isPresent();
+  }
+
+  public List<TellerTransaction> fetchTellerTransactions(final String tellerCode, final String state) {
+    final Optional<TellerEntity> optionalTellerEntity = this.tellerRepository.findByIdentifier(tellerCode);
+    if (optionalTellerEntity.isPresent()) {
+      final TellerEntity tellerEntity = optionalTellerEntity.get();
+      if (state != null) {
+        return this.tellerTransactionRepository.findByTellerAndStateOrderByTransactionDateAsc(tellerEntity, state)
+            .stream()
+            .map(TellerTransactionMapper::map)
+            .collect(Collectors.toList());
+      } else {
+        return this.tellerTransactionRepository.findByTellerOrderByTransactionDateAsc(tellerEntity)
+            .stream()
+            .map(TellerTransactionMapper::map)
+            .collect(Collectors.toList());
+      }
+    } else {
+      throw ServiceException.notFound("Teller {0} not found.", tellerCode);
+    }
+  }
 }
diff --git a/service/src/main/java/io/mifos/teller/service/internal/service/helper/AccountingService.java b/service/src/main/java/io/mifos/teller/service/internal/service/helper/AccountingService.java
index d64decb..2926910 100644
--- a/service/src/main/java/io/mifos/teller/service/internal/service/helper/AccountingService.java
+++ b/service/src/main/java/io/mifos/teller/service/internal/service/helper/AccountingService.java
@@ -17,6 +17,7 @@ package io.mifos.teller.service.internal.service.helper;
 
 import io.mifos.accounting.api.v1.client.AccountNotFoundException;
 import io.mifos.accounting.api.v1.client.LedgerManager;
+import io.mifos.accounting.api.v1.domain.AccountCommand;
 import io.mifos.accounting.api.v1.domain.AccountEntryPage;
 import io.mifos.accounting.api.v1.domain.JournalEntry;
 import io.mifos.teller.ServiceConstants;
@@ -59,4 +60,18 @@ public class AccountingService {
   public void postJournalEntry(final JournalEntry journalEntry) {
     this.ledgerManager.createJournalEntry(journalEntry);
   }
+
+  public void closeAccount(final String accountIdentifier) {
+    final AccountCommand accountCommand = new AccountCommand();
+    accountCommand.setAction(AccountCommand.Action.CLOSE.name());
+    accountCommand.setComment(ServiceConstants.TX_CLOSE_ACCOUNT);
+    this.ledgerManager.accountCommand(accountIdentifier, accountCommand);
+  }
+
+  public void openAccount(final String accountIdentifier) {
+    final AccountCommand accountCommand = new AccountCommand();
+    accountCommand.setAction(AccountCommand.Action.REOPEN.name());
+    accountCommand.setComment(ServiceConstants.TX_OPEN_ACCOUNT);
+    this.ledgerManager.accountCommand(accountIdentifier, accountCommand);
+  }
 }
diff --git a/service/src/main/java/io/mifos/teller/service/internal/service/helper/DepositAccountManagementService.java b/service/src/main/java/io/mifos/teller/service/internal/service/helper/DepositAccountManagementService.java
index 4d0a458..5c8a0aa 100644
--- a/service/src/main/java/io/mifos/teller/service/internal/service/helper/DepositAccountManagementService.java
+++ b/service/src/main/java/io/mifos/teller/service/internal/service/helper/DepositAccountManagementService.java
@@ -15,13 +15,23 @@
  */
 package io.mifos.teller.service.internal.service.helper;
 
+import io.mifos.deposit.api.v1.EventConstants;
 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.ProductDefinition;
+import io.mifos.deposit.api.v1.instance.domain.ProductInstance;
 import io.mifos.teller.ServiceConstants;
+import io.mifos.teller.api.v1.domain.Charge;
+import io.mifos.teller.api.v1.domain.TellerTransaction;
 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.ArrayList;
+import java.util.HashMap;
+import java.util.List;
+
 @Service
 public class DepositAccountManagementService {
 
@@ -35,4 +45,46 @@ public class DepositAccountManagementService {
     this.logger = logger;
     this.depositAccountManager = depositAccountManager;
   }
+
+  public List<ProductInstance> getProductInstance(final String customerIdentifier) {
+    return this.depositAccountManager.fetchProductInstances(customerIdentifier);
+  }
+
+  public List<Charge> getCharges(final TellerTransaction tellerTransaction) {
+    final List<Charge> charges = new ArrayList<>();
+    final ProductDefinition productDefinition =
+        this.depositAccountManager.findProductDefinition(tellerTransaction.getProductIdentifier());
+    final List<Action> actions = this.depositAccountManager.fetchActions();
+
+    final HashMap<String, Action> mappedActions = new HashMap<>(actions.size());
+    actions.forEach(action -> mappedActions.put(action.getIdentifier(), action));
+
+    final List<io.mifos.deposit.api.v1.definition.domain.Charge> productCharges = productDefinition.getCharges();
+    productCharges.forEach(productCharge -> {
+      final Action action = mappedActions.get(productCharge.getActionIdentifier());
+      if (action != null
+          && action.getTransactionType().equals(tellerTransaction.getTransactionType())) {
+        final Charge charge = new Charge();
+        charge.setCode(productCharge.getActionIdentifier());
+        charge.setIncomeAccountIdentifier(productCharge.getIncomeAccountIdentifier());
+        charge.setName(productCharge.getName());
+        if (productCharge.getProportional()) {
+          final Double amount = tellerTransaction.getAmount();
+          charge.setAmount(amount / 100.0D * productCharge.getAmount());
+        } else {
+          charge.setAmount(productCharge.getAmount());
+        }
+        charges.add(charge);
+      }
+    });
+    return charges;
+  }
+
+  public void activateProductInstance(final String customerAccountIdentifier) {
+    this.depositAccountManager.postProductInstanceCommand(customerAccountIdentifier, EventConstants.ACTIVATE_PRODUCT_INSTANCE);
+  }
+
+  public void closeProductInstance(final String customerAccountIdentifier) {
+    this.depositAccountManager.postProductInstanceCommand(customerAccountIdentifier, EventConstants.CLOSE_PRODUCT_INSTANCE);
+  }
 }
diff --git a/service/src/main/java/io/mifos/teller/service/rest/TellerOperationRestController.java b/service/src/main/java/io/mifos/teller/service/rest/TellerOperationRestController.java
index 303428d..611b485 100644
--- a/service/src/main/java/io/mifos/teller/service/rest/TellerOperationRestController.java
+++ b/service/src/main/java/io/mifos/teller/service/rest/TellerOperationRestController.java
@@ -15,20 +15,25 @@
  */
 package io.mifos.teller.service.rest;
 
-import io.mifos.accounting.api.v1.client.LedgerManager;
 import io.mifos.anubis.annotation.AcceptedTokenType;
 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.deposit.api.v1.client.DepositAccountManager;
-import io.mifos.portfolio.api.v1.client.PortfolioManager;
 import io.mifos.teller.ServiceConstants;
 import io.mifos.teller.api.v1.PermittableGroupIds;
+import io.mifos.teller.api.v1.domain.Teller;
 import io.mifos.teller.api.v1.domain.TellerAuthentication;
 import io.mifos.teller.api.v1.domain.TellerTransaction;
 import io.mifos.teller.api.v1.domain.TellerTransactionCosts;
+import io.mifos.teller.service.internal.command.AuthenticateTellerCommand;
+import io.mifos.teller.service.internal.command.CancelTellerTransactionCommand;
+import io.mifos.teller.service.internal.command.ConfirmTellerTransactionCommand;
+import io.mifos.teller.service.internal.command.InitializeTellerTransactionCommand;
+import io.mifos.teller.service.internal.command.PauseTellerCommand;
 import io.mifos.teller.service.internal.service.TellerManagementService;
 import io.mifos.teller.service.internal.service.TellerOperationService;
+import io.mifos.teller.service.internal.service.helper.AccountingService;
 import org.slf4j.Logger;
 import org.springframework.beans.factory.annotation.Autowired;
 import org.springframework.beans.factory.annotation.Qualifier;
@@ -43,8 +48,8 @@ import org.springframework.web.bind.annotation.ResponseBody;
 import org.springframework.web.bind.annotation.RestController;
 
 import javax.validation.Valid;
-import java.util.Collections;
 import java.util.List;
+import java.util.Optional;
 
 @RestController
 @RequestMapping("/teller/{tellerCode}")
@@ -54,25 +59,19 @@ public class TellerOperationRestController {
   private final CommandGateway commandGateway;
   private final TellerOperationService tellerOperationService;
   private final TellerManagementService tellerManagementService;
-  private final LedgerManager ledgerManager;
-  private final DepositAccountManager depositAccountManager;
-  private final PortfolioManager portfolioManager;
+  private final AccountingService accountingService;
 
   @Autowired
   public TellerOperationRestController(@Qualifier(ServiceConstants.LOGGER_NAME) final Logger logger,
                                        final CommandGateway commandGateway,
                                        final TellerOperationService tellerOperationService,
                                        final TellerManagementService tellerManagementService,
-                                       final LedgerManager ledgerManager,
-                                       final DepositAccountManager depositAccountManager,
-                                       final PortfolioManager portfolioManager) {
+                                       final AccountingService accountingService) {
     this.logger = logger;
     this.commandGateway = commandGateway;
     this.tellerOperationService = tellerOperationService;
     this.tellerManagementService = tellerManagementService;
-    this.ledgerManager = ledgerManager;
-    this.depositAccountManager = depositAccountManager;
-    this.portfolioManager = portfolioManager;
+    this.accountingService = accountingService;
   }
 
   @Permittable(value = AcceptedTokenType.TENANT, groupId = PermittableGroupIds.TELLER_OPERATION)
@@ -83,9 +82,23 @@ public class TellerOperationRestController {
       produces = MediaType.APPLICATION_JSON_VALUE
   )
   @ResponseBody
-  ResponseEntity<Void> auth(@PathVariable("tellerCode") final String tellerCode,
+  ResponseEntity<String> auth(@PathVariable("tellerCode") final String tellerCode,
                             @RequestBody @Valid final TellerAuthentication tellerAuthentication) {
-    return ResponseEntity.accepted().build();
+    final Teller teller = this.verifyTeller(tellerCode);
+
+    if (!teller.getAssignedEmployee().equals(tellerAuthentication.getEmployeeIdentifier())) {
+      throw ServiceException.badRequest("User {0} is not assigned to teller.", tellerAuthentication.getEmployeeIdentifier());
+    }
+
+    this.verifyEmployee(teller);
+
+    try {
+      return ResponseEntity.ok(
+          this.commandGateway.process(new AuthenticateTellerCommand(tellerCode, tellerAuthentication), String.class).get()
+      );
+    } catch (final Exception e) {
+      throw ServiceException.notFound("Teller {0} not found.", teller.getCode());
+    }
   }
 
   @Permittable(value = AcceptedTokenType.TENANT, groupId = PermittableGroupIds.TELLER_OPERATION)
@@ -98,6 +111,22 @@ public class TellerOperationRestController {
   @ResponseBody
   ResponseEntity<Void> post(@PathVariable("tellerCode") final String tellerCode,
                             @RequestParam(value = "command", required = true) final String command) {
+
+    final Teller teller = this.verifyTeller(tellerCode);
+
+    this.verifyEmployee(teller);
+
+    switch (command.toUpperCase()) {
+      case "PAUSE":
+        if (!teller.getState().equals(Teller.State.ACTIVE.name())) {
+          throw ServiceException.badRequest("Teller {0} is not active.", tellerCode);
+        }
+
+        this.commandGateway.process(new PauseTellerCommand(tellerCode));
+        break;
+      default :
+        throw ServiceException.badRequest("Unknonw command {0}", command);
+    }
     return ResponseEntity.accepted().build();
   }
 
@@ -111,7 +140,31 @@ public class TellerOperationRestController {
   @ResponseBody
   ResponseEntity<TellerTransactionCosts> post(@PathVariable("tellerCode") final String tellerCode,
                                               @RequestBody @Valid final TellerTransaction tellerTransaction) {
-    throw ServiceException.notFound("Teller {0} not found.", tellerCode);
+    final Teller teller = this.verifyTeller(tellerCode);
+
+    this.verifyEmployee(teller);
+
+    if (!teller.getState().equals(Teller.State.ACTIVE.name())) {
+      throw ServiceException.conflict("Teller {0} ist not active.", tellerCode);
+    }
+
+    if (!this.accountingService.accountExists(tellerTransaction.getCustomerAccountIdentifier())) {
+      throw ServiceException.badRequest("Customer account {0} not found.");
+    }
+
+    if (tellerTransaction.getTargetAccountIdentifier() != null &&
+        !this.accountingService.accountExists(tellerTransaction.getTargetAccountIdentifier())) {
+      throw ServiceException.badRequest("Target account {0} not found.");
+    }
+
+    try {
+      return ResponseEntity.ok(
+          this.commandGateway.process(
+              new InitializeTellerTransactionCommand(tellerCode, tellerTransaction), TellerTransactionCosts.class).get()
+      );
+    } catch (final Exception e) {
+      throw ServiceException.badRequest("Transaction for teller {0} not valid.", tellerCode);
+    }
   }
 
   @Permittable(value = AcceptedTokenType.TENANT, groupId = PermittableGroupIds.TELLER_OPERATION)
@@ -125,6 +178,25 @@ public class TellerOperationRestController {
   ResponseEntity<Void> confirm(@PathVariable("tellerCode") final String tellerCode,
                                @PathVariable("identifier") final String tellerTransactionIdentifier,
                                @RequestParam(value = "command", required = true) final String command) {
+    final Teller teller = this.verifyTeller(tellerCode);
+
+    this.verifyEmployee(teller);
+
+    if (!this.tellerOperationService.tellerTransactionExists(tellerTransactionIdentifier)) {
+      throw ServiceException.notFound("Transaction {0} not found.", tellerTransactionIdentifier);
+    }
+
+    switch (command.toUpperCase()) {
+      case "CONFIRM" :
+        this.commandGateway.process(new ConfirmTellerTransactionCommand(tellerTransactionIdentifier));
+        break;
+      case "CANCEL" :
+        this.commandGateway.process(new CancelTellerTransactionCommand(tellerTransactionIdentifier));
+        break;
+      default :
+        throw ServiceException.badRequest("Unsupported teller transaction command {0}.", command);
+    }
+
     return ResponseEntity.accepted().build();
   }
 
@@ -138,6 +210,25 @@ public class TellerOperationRestController {
   @ResponseBody
   ResponseEntity<List<TellerTransaction>> fetch(@PathVariable("tellerCode") final String tellerCode,
                                                 @RequestParam(value = "status", required = false) final String status) {
-    return ResponseEntity.ok(Collections.emptyList());
+    this.verifyTeller(tellerCode);
+    return ResponseEntity.ok(
+        this.tellerOperationService.fetchTellerTransactions(tellerCode, status)
+    );
+  }
+
+  private Teller verifyTeller(final String tellerCode) {
+    final Optional<Teller> optionalTeller = this.tellerManagementService.findByIdentifier(tellerCode);
+    if (!optionalTeller.isPresent()) {
+      throw ServiceException.notFound("Teller {0} not found.", tellerCode);
+    } else {
+      return optionalTeller.get();
+    }
+  }
+
+  private void verifyEmployee(final Teller teller) {
+    final String currentUser = UserContextHolder.checkedGetUser();
+    if (!currentUser.equals(teller.getAssignedEmployee())) {
+      throw ServiceException.badRequest("User {0} is not assigned to teller {1}", currentUser, teller.getCode());
+    }
   }
 }
diff --git a/service/src/main/resources/db/migrations/mariadb/V1__initial_setup.sql b/service/src/main/resources/db/migrations/mariadb/V1__initial_setup.sql
index 717b5da..5b4556d 100644
--- a/service/src/main/resources/db/migrations/mariadb/V1__initial_setup.sql
+++ b/service/src/main/resources/db/migrations/mariadb/V1__initial_setup.sql
@@ -15,8 +15,8 @@
 --
 
 CREATE TABLE tajet_teller (
-  id BIGINT NOT NULL AUTO_INCREMENT,
-  identifier                   VARCHAR(32)     NOT NULL,
+  id                           BIGINT         NOT NULL AUTO_INCREMENT,
+  identifier                   VARCHAR(32)    NOT NULL,
   a_password                   VARCHAR(4096)  NOT NULL,
   a_salt                       VARCHAR(4069)  NOT NULL,
   office_identifier            VARCHAR(32)    NOT NULL,
@@ -32,3 +32,21 @@ CREATE TABLE tajet_teller (
   CONSTRAINT tajet_teller_pk PRIMARY KEY (id),
   CONSTRAINT tajet_teller_identifier_uq UNIQUE (identifier)
 );
+
+CREATE TABLE tajet_teller_transactions (
+  id                          BIGINT         NOT NULL AUTO_INCREMENT,
+  teller_id                   BIGINT         NOT NULL,
+  identifier                  VARCHAR(32)    NOT NULL,
+  transaction_type            VARCHAR(32)    NOT NULL,
+  transaction_date            TIMESTAMP(3)   NOT NULL,
+  product_identifier          VARCHAR(32)    NOT NULL,
+  product_case_identifier     VARCHAR(32)    NULL,
+  customer_account_identifier VARCHAR(32)    NOT NULL,
+  target_account_identifier   VARCHAR(32)    NULL,
+  clerk                       VARCHAR(32)    NOT NULL,
+  amount                      NUMERIC(15, 5) NOT NULL,
+  a_state                     VARCHAR(256)   NOT NULL,
+  CONSTRAINT tajet_teller_transaction PRIMARY KEY (id),
+  CONSTRAINT tajet_teller_identifier_uq UNIQUE (identifier),
+  CONSTRAINT tajet_teller_transaction_fk FOREIGN KEY (teller_id) REFERENCES tajet_teller (id)
+);

-- 
To stop receiving notification emails like this one, please contact
myrle@apache.org.

[fineract-cn-teller] 23/30: fixed new return type for charges list to set

Posted by my...@apache.org.
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-teller.git

commit bc8748686492142fba387bcfbaceecc8bb8b2f53
Author: mgeiss <mg...@mifos.org>
AuthorDate: Wed Jun 28 17:53:04 2017 +0200

    fixed new return type for charges list to set
---
 .../internal/service/helper/DepositAccountManagementService.java       | 3 ++-
 1 file changed, 2 insertions(+), 1 deletion(-)

diff --git a/service/src/main/java/io/mifos/teller/service/internal/service/helper/DepositAccountManagementService.java b/service/src/main/java/io/mifos/teller/service/internal/service/helper/DepositAccountManagementService.java
index 2843195..913361e 100644
--- a/service/src/main/java/io/mifos/teller/service/internal/service/helper/DepositAccountManagementService.java
+++ b/service/src/main/java/io/mifos/teller/service/internal/service/helper/DepositAccountManagementService.java
@@ -31,6 +31,7 @@ import org.springframework.stereotype.Service;
 import java.util.ArrayList;
 import java.util.HashMap;
 import java.util.List;
+import java.util.Set;
 
 @Service
 public class DepositAccountManagementService {
@@ -63,7 +64,7 @@ public class DepositAccountManagementService {
     final HashMap<String, Action> mappedActions = new HashMap<>(actions.size());
     actions.forEach(action -> mappedActions.put(action.getIdentifier(), action));
 
-    final List<io.mifos.deposit.api.v1.definition.domain.Charge> productCharges = productDefinition.getCharges();
+    final Set<io.mifos.deposit.api.v1.definition.domain.Charge> productCharges = productDefinition.getCharges();
     productCharges.forEach(productCharge -> {
       final Action action = mappedActions.get(productCharge.getActionIdentifier());
       if (action != null

-- 
To stop receiving notification emails like this one, please contact
myrle@apache.org.

[fineract-cn-teller] 04/30: first iteration for teller management

Posted by my...@apache.org.
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-teller.git

commit 55ce69bf7b01e39635b1d4718f87220a2f9fd664
Author: mgeiss <mg...@mifos.org>
AuthorDate: Sun Jun 11 13:41:10 2017 +0200

    first iteration for teller management
---
 .../mifos/teller/{ => api/v1}/EventConstants.java  |   8 +-
 .../teller/{ => api/v1}/PermittableGroupIds.java   |   2 +-
 .../v1/client/TellerAlreadyExistsException.java    |   5 +-
 .../teller/{ => api/v1}/client/TellerManager.java  |  37 +-
 .../api/v1/client/TellerNotFoundException.java     |   5 +-
 .../TellerTransactionValidationException.java      |   5 +-
 .../api/v1/client/TellerValidationException.java   |   5 +-
 .../v1/domain/Charge.java}                         |  39 +-
 .../mifos/teller/{ => api/v1}/domain/Teller.java   |  42 +-
 .../v1/domain/TellerAuthentication.java}           |  30 +-
 .../teller/api/v1/domain/TellerBalanceSheet.java   |  53 +++
 .../teller/{ => api/v1}/domain/TellerEntry.java    |  26 +-
 .../v1}/domain/TellerManagementCommand.java        |  17 +-
 .../{ => api/v1}/domain/TellerTransaction.java     |  37 +-
 .../v1}/domain/TellerTransactionCosts.java         |  17 +-
 .../client/TellerAlreadyExistsException.java       |   4 -
 .../teller/client/TellerNotFoundException.java     |   4 -
 .../TellerTransactionValidationException.java      |   4 -
 .../teller/client/TellerValidationException.java   |   4 -
 .../main/java/io/mifos/teller/domain/Charge.java   |  36 --
 .../mifos/teller/domain/TellerAuthentication.java  |  27 --
 .../io/mifos/teller/domain/TellerBalanceSheet.java |  38 --
 .../java/io/mifos/teller/AbstractTellerTest.java   | 150 +++++++
 .../java/io/mifos/teller/TestTellerManagement.java | 481 +++++++++++++++++++++
 .../teller/listener/MigrationEventListener.java    |  53 +++
 .../mifos/teller/listener/TellerEventListener.java |  84 ++++
 .../java/io/mifos/teller/util/TellerGenerator.java |  37 ++
 component-test/src/main/resources/logback-test.xml |   4 +-
 service/build.gradle                               |   5 +
 .../java/io/mifos/teller/ServiceConstants.java     |   2 +
 .../java/io/mifos/teller/TellerConfiguration.java  |  15 +
 .../internal/command/ChangeTellerCommand.java      |  26 +-
 .../internal/command/CloseTellerCommand.java       |  38 ++
 .../internal/command/CreateTellerCommand.java      |  26 +-
 .../internal/command/MigrationCommand.java}        |   9 +-
 .../internal/command/OpenTellerCommand.java        |  38 ++
 .../command/handler/MigrationAggregate.java        |  63 +++
 .../internal/command/handler/TellerAggregate.java  | 278 ++++++++++++
 .../service/internal/mapper/TellerEntryMapper.java |  36 ++
 .../service/internal/mapper/TellerMapper.java      |  71 +++
 .../service/internal/repository/TellerEntity.java  | 181 ++++++++
 .../internal/repository/TellerRepository.java      |  18 +-
 .../internal/service/TellerManagementService.java  | 106 +++++
 .../internal/service/TellerOperationService.java}  |   8 +-
 .../internal/service/helper/AccountingService.java |  62 +++
 .../helper/DepositAccountManagementService.java    |  38 ++
 .../service/helper/OrganizationService.java        |  59 +++
 .../internal/service/helper/PortfolioService.java  |  40 ++
 .../rest/TellerManagementRestController.java       | 236 ++++++++++
 .../rest/TellerOperationRestController.java        | 143 ++++++
 .../teller/service/rest/TellerRestController.java  |  59 +++
 .../db/migrations/mariadb/V1__initial_setup.sql    |  20 +-
 shared.gradle                                      |   5 +
 53 files changed, 2618 insertions(+), 218 deletions(-)

diff --git a/api/src/main/java/io/mifos/teller/EventConstants.java b/api/src/main/java/io/mifos/teller/api/v1/EventConstants.java
similarity index 72%
copy from api/src/main/java/io/mifos/teller/EventConstants.java
copy to api/src/main/java/io/mifos/teller/api/v1/EventConstants.java
index f2a0d0b..34b1abb 100644
--- a/api/src/main/java/io/mifos/teller/EventConstants.java
+++ b/api/src/main/java/io/mifos/teller/api/v1/EventConstants.java
@@ -13,7 +13,7 @@
  * See the License for the specific language governing permissions and
  * limitations under the License.
  */
-package io.mifos.teller;
+package io.mifos.teller.api.v1;
 
 @SuppressWarnings("unused")
 public interface EventConstants {
@@ -27,4 +27,10 @@ public interface EventConstants {
 
   String POST_TELLER = "post-teller";
   String SELECTOR_POST_TELLER = SELECTOR_NAME + " = '" + POST_TELLER + "'";
+  String PUT_TELLER = "put-teller";
+  String SELECTOR_PUT_TELLER = SELECTOR_NAME + " = '" + PUT_TELLER + "'";
+  String OPEN_TELLER = "open-teller";
+  String SELECTOR_OPEN_TELLER = SELECTOR_NAME + " = '" + OPEN_TELLER + "'";
+  String CLOSE_TELLER = "close-teller";
+  String SELECTOR_CLOSE_TELLER = SELECTOR_NAME + " = '" + CLOSE_TELLER + "'";
 }
diff --git a/api/src/main/java/io/mifos/teller/PermittableGroupIds.java b/api/src/main/java/io/mifos/teller/api/v1/PermittableGroupIds.java
similarity index 96%
rename from api/src/main/java/io/mifos/teller/PermittableGroupIds.java
rename to api/src/main/java/io/mifos/teller/api/v1/PermittableGroupIds.java
index aff0c79..08fd7ea 100644
--- a/api/src/main/java/io/mifos/teller/PermittableGroupIds.java
+++ b/api/src/main/java/io/mifos/teller/api/v1/PermittableGroupIds.java
@@ -13,7 +13,7 @@
  * See the License for the specific language governing permissions and
  * limitations under the License.
  */
-package io.mifos.teller;
+package io.mifos.teller.api.v1;
 
 @SuppressWarnings("unused")
 public interface PermittableGroupIds {
diff --git a/service/src/main/java/io/mifos/teller/ServiceConstants.java b/api/src/main/java/io/mifos/teller/api/v1/client/TellerAlreadyExistsException.java
similarity index 84%
copy from service/src/main/java/io/mifos/teller/ServiceConstants.java
copy to api/src/main/java/io/mifos/teller/api/v1/client/TellerAlreadyExistsException.java
index 98de3be..3674d5f 100644
--- a/service/src/main/java/io/mifos/teller/ServiceConstants.java
+++ b/api/src/main/java/io/mifos/teller/api/v1/client/TellerAlreadyExistsException.java
@@ -13,8 +13,7 @@
  * See the License for the specific language governing permissions and
  * limitations under the License.
  */
-package io.mifos.teller;
+package io.mifos.teller.api.v1.client;
 
-public interface ServiceConstants {
-  String LOGGER_NAME = "teller-logger";
+public class TellerAlreadyExistsException extends RuntimeException {
 }
diff --git a/api/src/main/java/io/mifos/teller/client/TellerManager.java b/api/src/main/java/io/mifos/teller/api/v1/client/TellerManager.java
similarity index 84%
rename from api/src/main/java/io/mifos/teller/client/TellerManager.java
rename to api/src/main/java/io/mifos/teller/api/v1/client/TellerManager.java
index 2b9b0b4..0972873 100644
--- a/api/src/main/java/io/mifos/teller/client/TellerManager.java
+++ b/api/src/main/java/io/mifos/teller/api/v1/client/TellerManager.java
@@ -1,14 +1,29 @@
-package io.mifos.teller.client;
+/*
+ * 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.
+ */
+package io.mifos.teller.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.teller.domain.Teller;
-import io.mifos.teller.domain.TellerAuthentication;
-import io.mifos.teller.domain.TellerBalanceSheet;
-import io.mifos.teller.domain.TellerManagementCommand;
-import io.mifos.teller.domain.TellerTransaction;
-import io.mifos.teller.domain.TellerTransactionCosts;
+import io.mifos.teller.api.v1.domain.Teller;
+import io.mifos.teller.api.v1.domain.TellerAuthentication;
+import io.mifos.teller.api.v1.domain.TellerBalanceSheet;
+import io.mifos.teller.api.v1.domain.TellerManagementCommand;
+import io.mifos.teller.api.v1.domain.TellerTransaction;
+import io.mifos.teller.api.v1.domain.TellerTransactionCosts;
 import org.springframework.cloud.netflix.feign.FeignClient;
 import org.springframework.http.HttpStatus;
 import org.springframework.http.MediaType;
@@ -25,7 +40,7 @@ import java.util.List;
 public interface TellerManager {
 
   @RequestMapping(
-      value = "/offices/{officeIdentifier}",
+      value = "/offices/{officeIdentifier}/teller",
       method = RequestMethod.POST,
       consumes = MediaType.APPLICATION_JSON_VALUE,
       produces = MediaType.APPLICATION_JSON_VALUE
@@ -44,7 +59,8 @@ public interface TellerManager {
       produces = MediaType.ALL_VALUE
   )
   @ThrowsExceptions({
-      @ThrowsException(status = HttpStatus.NOT_FOUND, exception = TellerNotFoundException.class)
+      @ThrowsException(status = HttpStatus.NOT_FOUND, exception = TellerNotFoundException.class),
+      @ThrowsException(status = HttpStatus.BAD_REQUEST, exception = TellerValidationException.class)
   })
   Teller find(@PathVariable("officeIdentifier") final String officeIdentifier,
               @PathVariable("tellerCode") final String tellerCode);
@@ -56,7 +72,8 @@ public interface TellerManager {
       produces = MediaType.ALL_VALUE
   )
   @ThrowsExceptions({
-      @ThrowsException(status = HttpStatus.NOT_FOUND, exception = TellerNotFoundException.class)
+      @ThrowsException(status = HttpStatus.NOT_FOUND, exception = TellerNotFoundException.class),
+      @ThrowsException(status = HttpStatus.BAD_REQUEST, exception = TellerValidationException.class)
   })
   List<Teller> fetch(@PathVariable("officeIdentifier") final String officeIdentifier);
 
diff --git a/service/src/main/java/io/mifos/teller/ServiceConstants.java b/api/src/main/java/io/mifos/teller/api/v1/client/TellerNotFoundException.java
similarity index 85%
copy from service/src/main/java/io/mifos/teller/ServiceConstants.java
copy to api/src/main/java/io/mifos/teller/api/v1/client/TellerNotFoundException.java
index 98de3be..335273f 100644
--- a/service/src/main/java/io/mifos/teller/ServiceConstants.java
+++ b/api/src/main/java/io/mifos/teller/api/v1/client/TellerNotFoundException.java
@@ -13,8 +13,7 @@
  * See the License for the specific language governing permissions and
  * limitations under the License.
  */
-package io.mifos.teller;
+package io.mifos.teller.api.v1.client;
 
-public interface ServiceConstants {
-  String LOGGER_NAME = "teller-logger";
+public class TellerNotFoundException extends RuntimeException {
 }
diff --git a/service/src/main/java/io/mifos/teller/ServiceConstants.java b/api/src/main/java/io/mifos/teller/api/v1/client/TellerTransactionValidationException.java
similarity index 83%
copy from service/src/main/java/io/mifos/teller/ServiceConstants.java
copy to api/src/main/java/io/mifos/teller/api/v1/client/TellerTransactionValidationException.java
index 98de3be..b46b30b 100644
--- a/service/src/main/java/io/mifos/teller/ServiceConstants.java
+++ b/api/src/main/java/io/mifos/teller/api/v1/client/TellerTransactionValidationException.java
@@ -13,8 +13,7 @@
  * See the License for the specific language governing permissions and
  * limitations under the License.
  */
-package io.mifos.teller;
+package io.mifos.teller.api.v1.client;
 
-public interface ServiceConstants {
-  String LOGGER_NAME = "teller-logger";
+public class TellerTransactionValidationException extends RuntimeException {
 }
diff --git a/service/src/main/java/io/mifos/teller/ServiceConstants.java b/api/src/main/java/io/mifos/teller/api/v1/client/TellerValidationException.java
similarity index 85%
copy from service/src/main/java/io/mifos/teller/ServiceConstants.java
copy to api/src/main/java/io/mifos/teller/api/v1/client/TellerValidationException.java
index 98de3be..e726612 100644
--- a/service/src/main/java/io/mifos/teller/ServiceConstants.java
+++ b/api/src/main/java/io/mifos/teller/api/v1/client/TellerValidationException.java
@@ -13,8 +13,7 @@
  * See the License for the specific language governing permissions and
  * limitations under the License.
  */
-package io.mifos.teller;
+package io.mifos.teller.api.v1.client;
 
-public interface ServiceConstants {
-  String LOGGER_NAME = "teller-logger";
+public class TellerValidationException extends RuntimeException {
 }
diff --git a/api/src/main/java/io/mifos/teller/EventConstants.java b/api/src/main/java/io/mifos/teller/api/v1/domain/Charge.java
similarity index 52%
copy from api/src/main/java/io/mifos/teller/EventConstants.java
copy to api/src/main/java/io/mifos/teller/api/v1/domain/Charge.java
index f2a0d0b..e576a09 100644
--- a/api/src/main/java/io/mifos/teller/EventConstants.java
+++ b/api/src/main/java/io/mifos/teller/api/v1/domain/Charge.java
@@ -13,18 +13,39 @@
  * See the License for the specific language governing permissions and
  * limitations under the License.
  */
-package io.mifos.teller;
+package io.mifos.teller.api.v1.domain;
 
-@SuppressWarnings("unused")
-public interface EventConstants {
+public class Charge {
 
-  String DESTINATION = "teller-v1";
+  private String code;
+  private String name;
+  private Double amount;
 
-  String SELECTOR_NAME = "operation";
+  public Charge() {
+    super();
+  }
 
-  String INITIALIZE = "initialize";
-  String SELECTOR_INITIALIZE = SELECTOR_NAME + " = '" + INITIALIZE + "'";
+  public String getCode() {
+    return this.code;
+  }
 
-  String POST_TELLER = "post-teller";
-  String SELECTOR_POST_TELLER = SELECTOR_NAME + " = '" + POST_TELLER + "'";
+  public void setCode(final String code) {
+    this.code = code;
+  }
+
+  public String getName() {
+    return this.name;
+  }
+
+  public void setName(final String name) {
+    this.name = name;
+  }
+
+  public Double getAmount() {
+    return this.amount;
+  }
+
+  public void setAmount(final Double amount) {
+    this.amount = amount;
+  }
 }
diff --git a/api/src/main/java/io/mifos/teller/domain/Teller.java b/api/src/main/java/io/mifos/teller/api/v1/domain/Teller.java
similarity index 67%
rename from api/src/main/java/io/mifos/teller/domain/Teller.java
rename to api/src/main/java/io/mifos/teller/api/v1/domain/Teller.java
index b1fa3b4..6d5f7b6 100644
--- a/api/src/main/java/io/mifos/teller/domain/Teller.java
+++ b/api/src/main/java/io/mifos/teller/api/v1/domain/Teller.java
@@ -1,4 +1,19 @@
-package io.mifos.teller.domain;
+/*
+ * 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.
+ */
+package io.mifos.teller.api.v1.domain;
 
 import io.mifos.core.lang.validation.constraints.ValidIdentifier;
 import org.hibernate.validator.constraints.NotEmpty;
@@ -8,7 +23,7 @@ import javax.validation.constraints.NotNull;
 
 public class Teller {
 
-  public enum Status {
+  public enum State {
     ACTIVE,
     CLOSED,
     OPEN,
@@ -26,7 +41,8 @@ public class Teller {
   private String tellerAccountIdentifier;
   @ValidIdentifier
   private String vaultAccountIdentifier;
-  private Status status;
+  private String assignedEmployee;
+  private State state;
   private String createdBy;
   private String createdOn;
   private String lastModifiedBy;
@@ -76,12 +92,24 @@ public class Teller {
     this.vaultAccountIdentifier = vaultAccountIdentifier;
   }
 
-  public String getStatus() {
-    return this.status.name();
+  public String getAssignedEmployee() {
+    return this.assignedEmployee;
   }
 
-  public void setStatus(final String status) {
-    this.status = Status.valueOf(status);
+  public void setAssignedEmployee(final String assignedEmployee) {
+    this.assignedEmployee = assignedEmployee;
+  }
+
+  public String getState() {
+    if (this.state != null) {
+      return this.state.name();
+    } else {
+      return null;
+    }
+  }
+
+  public void setState(final String state) {
+    this.state = State.valueOf(state);
   }
 
   public String getCreatedBy() {
diff --git a/api/src/main/java/io/mifos/teller/EventConstants.java b/api/src/main/java/io/mifos/teller/api/v1/domain/TellerAuthentication.java
similarity index 52%
copy from api/src/main/java/io/mifos/teller/EventConstants.java
copy to api/src/main/java/io/mifos/teller/api/v1/domain/TellerAuthentication.java
index f2a0d0b..dbd6bc4 100644
--- a/api/src/main/java/io/mifos/teller/EventConstants.java
+++ b/api/src/main/java/io/mifos/teller/api/v1/domain/TellerAuthentication.java
@@ -13,18 +13,30 @@
  * See the License for the specific language governing permissions and
  * limitations under the License.
  */
-package io.mifos.teller;
+package io.mifos.teller.api.v1.domain;
 
-@SuppressWarnings("unused")
-public interface EventConstants {
+public class TellerAuthentication {
 
-  String DESTINATION = "teller-v1";
+  private String employeeIdentifier;
+  private byte[] password;
 
-  String SELECTOR_NAME = "operation";
+  public TellerAuthentication() {
+    super();
+  }
 
-  String INITIALIZE = "initialize";
-  String SELECTOR_INITIALIZE = SELECTOR_NAME + " = '" + INITIALIZE + "'";
+  public String getEmployeeIdentifier() {
+    return this.employeeIdentifier;
+  }
 
-  String POST_TELLER = "post-teller";
-  String SELECTOR_POST_TELLER = SELECTOR_NAME + " = '" + POST_TELLER + "'";
+  public void setEmployeeIdentifier(final String employeeIdentifier) {
+    this.employeeIdentifier = employeeIdentifier;
+  }
+
+  public byte[] getPassword() {
+    return this.password;
+  }
+
+  public void setPassword(final byte[] password) {
+    this.password = password;
+  }
 }
diff --git a/api/src/main/java/io/mifos/teller/api/v1/domain/TellerBalanceSheet.java b/api/src/main/java/io/mifos/teller/api/v1/domain/TellerBalanceSheet.java
new file mode 100644
index 0000000..253354a
--- /dev/null
+++ b/api/src/main/java/io/mifos/teller/api/v1/domain/TellerBalanceSheet.java
@@ -0,0 +1,53 @@
+/*
+ * 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.
+ */
+package io.mifos.teller.api.v1.domain;
+
+import java.util.List;
+
+public class TellerBalanceSheet {
+
+  private String day;
+  private Double balance;
+  private List<TellerEntry> entries;
+
+  public TellerBalanceSheet() {
+    super();
+  }
+
+  public String getDay() {
+    return this.day;
+  }
+
+  public void setDay(final String day) {
+    this.day = day;
+  }
+
+  public Double getBalance() {
+    return this.balance;
+  }
+
+  public void setBalance(final Double balance) {
+    this.balance = balance;
+  }
+
+  public List<TellerEntry> getEntries() {
+    return this.entries;
+  }
+
+  public void setEntries(final List<TellerEntry> entries) {
+    this.entries = entries;
+  }
+}
diff --git a/api/src/main/java/io/mifos/teller/domain/TellerEntry.java b/api/src/main/java/io/mifos/teller/api/v1/domain/TellerEntry.java
similarity index 56%
rename from api/src/main/java/io/mifos/teller/domain/TellerEntry.java
rename to api/src/main/java/io/mifos/teller/api/v1/domain/TellerEntry.java
index 72535d3..b74e344 100644
--- a/api/src/main/java/io/mifos/teller/domain/TellerEntry.java
+++ b/api/src/main/java/io/mifos/teller/api/v1/domain/TellerEntry.java
@@ -1,4 +1,19 @@
-package io.mifos.teller.domain;
+/*
+ * 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.
+ */
+package io.mifos.teller.api.v1.domain;
 
 public class TellerEntry {
 
@@ -11,7 +26,6 @@ public class TellerEntry {
   private String transactionDate;
   private String message;
   private Double amount;
-  private Double balance;
 
   public TellerEntry() {
     super();
@@ -48,12 +62,4 @@ public class TellerEntry {
   public void setAmount(final Double amount) {
     this.amount = amount;
   }
-
-  public Double getBalance() {
-    return this.balance;
-  }
-
-  public void setBalance(final Double balance) {
-    this.balance = balance;
-  }
 }
diff --git a/api/src/main/java/io/mifos/teller/domain/TellerManagementCommand.java b/api/src/main/java/io/mifos/teller/api/v1/domain/TellerManagementCommand.java
similarity index 65%
rename from api/src/main/java/io/mifos/teller/domain/TellerManagementCommand.java
rename to api/src/main/java/io/mifos/teller/api/v1/domain/TellerManagementCommand.java
index c974451..01194eb 100644
--- a/api/src/main/java/io/mifos/teller/domain/TellerManagementCommand.java
+++ b/api/src/main/java/io/mifos/teller/api/v1/domain/TellerManagementCommand.java
@@ -1,4 +1,19 @@
-package io.mifos.teller.domain;
+/*
+ * 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.
+ */
+package io.mifos.teller.api.v1.domain;
 
 import io.mifos.core.lang.validation.constraints.ValidIdentifier;
 
diff --git a/api/src/main/java/io/mifos/teller/domain/TellerTransaction.java b/api/src/main/java/io/mifos/teller/api/v1/domain/TellerTransaction.java
similarity index 62%
rename from api/src/main/java/io/mifos/teller/domain/TellerTransaction.java
rename to api/src/main/java/io/mifos/teller/api/v1/domain/TellerTransaction.java
index e3d3a81..5dc8ffa 100644
--- a/api/src/main/java/io/mifos/teller/domain/TellerTransaction.java
+++ b/api/src/main/java/io/mifos/teller/api/v1/domain/TellerTransaction.java
@@ -1,4 +1,19 @@
-package io.mifos.teller.domain;
+/*
+ * 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.
+ */
+package io.mifos.teller.api.v1.domain;
 
 import io.mifos.core.lang.validation.constraints.ValidIdentifier;
 
@@ -21,8 +36,12 @@ public class TellerTransaction {
   private String transactionDate;
   @ValidIdentifier
   private String productIdentifier;
+  @ValidIdentifier(optional = true)
+  private String productCaseIdentifier;
   @ValidIdentifier
   private String customerAccountIdentifier;
+  @ValidIdentifier(optional = true)
+  private String targetAccountIdentifier;
   @ValidIdentifier
   private String clerk;
   @NotNull
@@ -66,6 +85,14 @@ public class TellerTransaction {
     this.productIdentifier = productIdentifier;
   }
 
+  public String getProductCaseIdentifier() {
+    return this.productCaseIdentifier;
+  }
+
+  public void setProductCaseIdentifier(final String productCaseIdentifier) {
+    this.productCaseIdentifier = productCaseIdentifier;
+  }
+
   public String getCustomerAccountIdentifier() {
     return this.customerAccountIdentifier;
   }
@@ -74,6 +101,14 @@ public class TellerTransaction {
     this.customerAccountIdentifier = customerAccountIdentifier;
   }
 
+  public String getTargetAccountIdentifier() {
+    return this.targetAccountIdentifier;
+  }
+
+  public void setTargetAccountIdentifier(final String targetAccountIdentifier) {
+    this.targetAccountIdentifier = targetAccountIdentifier;
+  }
+
   public String getClerk() {
     return this.clerk;
   }
diff --git a/api/src/main/java/io/mifos/teller/domain/TellerTransactionCosts.java b/api/src/main/java/io/mifos/teller/api/v1/domain/TellerTransactionCosts.java
similarity index 55%
rename from api/src/main/java/io/mifos/teller/domain/TellerTransactionCosts.java
rename to api/src/main/java/io/mifos/teller/api/v1/domain/TellerTransactionCosts.java
index ceb7348..2ba3cfa 100644
--- a/api/src/main/java/io/mifos/teller/domain/TellerTransactionCosts.java
+++ b/api/src/main/java/io/mifos/teller/api/v1/domain/TellerTransactionCosts.java
@@ -1,4 +1,19 @@
-package io.mifos.teller.domain;
+/*
+ * 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.
+ */
+package io.mifos.teller.api.v1.domain;
 
 import java.util.List;
 
diff --git a/api/src/main/java/io/mifos/teller/client/TellerAlreadyExistsException.java b/api/src/main/java/io/mifos/teller/client/TellerAlreadyExistsException.java
deleted file mode 100644
index 28cf9aa..0000000
--- a/api/src/main/java/io/mifos/teller/client/TellerAlreadyExistsException.java
+++ /dev/null
@@ -1,4 +0,0 @@
-package io.mifos.teller.client;
-
-public class TellerAlreadyExistsException extends RuntimeException {
-}
diff --git a/api/src/main/java/io/mifos/teller/client/TellerNotFoundException.java b/api/src/main/java/io/mifos/teller/client/TellerNotFoundException.java
deleted file mode 100644
index 4334646..0000000
--- a/api/src/main/java/io/mifos/teller/client/TellerNotFoundException.java
+++ /dev/null
@@ -1,4 +0,0 @@
-package io.mifos.teller.client;
-
-public class TellerNotFoundException extends RuntimeException {
-}
diff --git a/api/src/main/java/io/mifos/teller/client/TellerTransactionValidationException.java b/api/src/main/java/io/mifos/teller/client/TellerTransactionValidationException.java
deleted file mode 100644
index 453b5d2..0000000
--- a/api/src/main/java/io/mifos/teller/client/TellerTransactionValidationException.java
+++ /dev/null
@@ -1,4 +0,0 @@
-package io.mifos.teller.client;
-
-public class TellerTransactionValidationException extends RuntimeException {
-}
diff --git a/api/src/main/java/io/mifos/teller/client/TellerValidationException.java b/api/src/main/java/io/mifos/teller/client/TellerValidationException.java
deleted file mode 100644
index 07f0be8..0000000
--- a/api/src/main/java/io/mifos/teller/client/TellerValidationException.java
+++ /dev/null
@@ -1,4 +0,0 @@
-package io.mifos.teller.client;
-
-public class TellerValidationException extends RuntimeException {
-}
diff --git a/api/src/main/java/io/mifos/teller/domain/Charge.java b/api/src/main/java/io/mifos/teller/domain/Charge.java
deleted file mode 100644
index 8f71964..0000000
--- a/api/src/main/java/io/mifos/teller/domain/Charge.java
+++ /dev/null
@@ -1,36 +0,0 @@
-package io.mifos.teller.domain;
-
-public class Charge {
-
-  private String code;
-  private String name;
-  private Double amount;
-
-  public Charge() {
-    super();
-  }
-
-  public String getCode() {
-    return this.code;
-  }
-
-  public void setCode(final String code) {
-    this.code = code;
-  }
-
-  public String getName() {
-    return this.name;
-  }
-
-  public void setName(final String name) {
-    this.name = name;
-  }
-
-  public Double getAmount() {
-    return this.amount;
-  }
-
-  public void setAmount(final Double amount) {
-    this.amount = amount;
-  }
-}
diff --git a/api/src/main/java/io/mifos/teller/domain/TellerAuthentication.java b/api/src/main/java/io/mifos/teller/domain/TellerAuthentication.java
deleted file mode 100644
index e6578c8..0000000
--- a/api/src/main/java/io/mifos/teller/domain/TellerAuthentication.java
+++ /dev/null
@@ -1,27 +0,0 @@
-package io.mifos.teller.domain;
-
-public class TellerAuthentication {
-
-  private String employeeIdentifier;
-  private byte[] password;
-
-  public TellerAuthentication() {
-    super();
-  }
-
-  public String getEmployeeIdentifier() {
-    return this.employeeIdentifier;
-  }
-
-  public void setEmployeeIdentifier(final String employeeIdentifier) {
-    this.employeeIdentifier = employeeIdentifier;
-  }
-
-  public byte[] getPassword() {
-    return this.password;
-  }
-
-  public void setPassword(final byte[] password) {
-    this.password = password;
-  }
-}
diff --git a/api/src/main/java/io/mifos/teller/domain/TellerBalanceSheet.java b/api/src/main/java/io/mifos/teller/domain/TellerBalanceSheet.java
deleted file mode 100644
index f46478c..0000000
--- a/api/src/main/java/io/mifos/teller/domain/TellerBalanceSheet.java
+++ /dev/null
@@ -1,38 +0,0 @@
-package io.mifos.teller.domain;
-
-import java.util.List;
-
-public class TellerBalanceSheet {
-
-  private String day;
-  private Double balance;
-  private List<TellerEntry> entries;
-
-  public TellerBalanceSheet() {
-    super();
-  }
-
-  public String getDay() {
-    return this.day;
-  }
-
-  public void setDay(final String day) {
-    this.day = day;
-  }
-
-  public Double getBalance() {
-    return this.balance;
-  }
-
-  public void setBalance(final Double balance) {
-    this.balance = balance;
-  }
-
-  public List<TellerEntry> getEntries() {
-    return this.entries;
-  }
-
-  public void setEntries(final List<TellerEntry> entries) {
-    this.entries = entries;
-  }
-}
diff --git a/component-test/src/main/java/io/mifos/teller/AbstractTellerTest.java b/component-test/src/main/java/io/mifos/teller/AbstractTellerTest.java
new file mode 100644
index 0000000..4d60f41
--- /dev/null
+++ b/component-test/src/main/java/io/mifos/teller/AbstractTellerTest.java
@@ -0,0 +1,150 @@
+/*
+ * 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.
+ */
+package io.mifos.teller;
+
+import io.mifos.anubis.test.v1.TenantApplicationSecurityEnvironmentTestRule;
+import io.mifos.core.api.context.AutoUserContext;
+import io.mifos.core.lang.ApplicationName;
+import io.mifos.core.test.env.TestEnvironment;
+import io.mifos.core.test.fixture.TenantDataStoreContextTestRule;
+import io.mifos.core.test.fixture.cassandra.CassandraInitializer;
+import io.mifos.core.test.fixture.mariadb.MariaDBInitializer;
+import io.mifos.core.test.listener.EnableEventRecording;
+import io.mifos.core.test.listener.EventRecorder;
+import io.mifos.teller.api.v1.EventConstants;
+import io.mifos.teller.api.v1.client.TellerManager;
+import io.mifos.teller.service.internal.service.helper.AccountingService;
+import io.mifos.teller.service.internal.service.helper.DepositAccountManagementService;
+import io.mifos.teller.service.internal.service.helper.OrganizationService;
+import io.mifos.teller.service.internal.service.helper.PortfolioService;
+import org.junit.After;
+import org.junit.Before;
+import org.junit.ClassRule;
+import org.junit.Rule;
+import org.junit.rules.RuleChain;
+import org.junit.rules.TestRule;
+import org.junit.runner.RunWith;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.beans.factory.annotation.Qualifier;
+import org.springframework.boot.test.context.SpringBootTest;
+import org.springframework.boot.test.mock.mockito.MockBean;
+import org.springframework.cloud.netflix.feign.EnableFeignClients;
+import org.springframework.cloud.netflix.ribbon.RibbonClient;
+import org.springframework.context.annotation.Bean;
+import org.springframework.context.annotation.ComponentScan;
+import org.springframework.context.annotation.Configuration;
+import org.springframework.context.annotation.Import;
+import org.springframework.test.context.junit4.SpringRunner;
+
+import java.security.interfaces.RSAPrivateKey;
+
+@RunWith(SpringRunner.class)
+@SpringBootTest(
+    webEnvironment = SpringBootTest.WebEnvironment.DEFINED_PORT,
+    classes = {AbstractTellerTest.TestConfiguration.class}
+)
+public class AbstractTellerTest {
+
+  private static final String APP_NAME = "teller-v1";
+  public static final String LOGGER_NAME = "test-logger";
+
+  @Configuration
+  @EnableEventRecording
+  @EnableFeignClients(basePackages = {"io.mifos.teller.api.v1.client"})
+  @RibbonClient(name = APP_NAME)
+  @Import({TellerConfiguration.class})
+  @ComponentScan("io.mifos.teller.listener")
+  public static class TestConfiguration {
+    public TestConfiguration() {
+      super();
+    }
+
+    @Bean(name = LOGGER_NAME)
+    public Logger logger() {
+      return LoggerFactory.getLogger(LOGGER_NAME);
+    }
+  }
+
+  private static final String TEST_USER = "homer";
+
+  private final static TestEnvironment testEnvironment = new TestEnvironment(APP_NAME);
+  private final static CassandraInitializer cassandraInitializer = new CassandraInitializer();
+  private final static MariaDBInitializer mariaDBInitializer = new MariaDBInitializer();
+  final static TenantDataStoreContextTestRule tenantDataStoreContext = TenantDataStoreContextTestRule.forRandomTenantName(cassandraInitializer, mariaDBInitializer);
+
+  @ClassRule
+  public static TestRule orderClassRules = RuleChain
+      .outerRule(testEnvironment)
+      .around(cassandraInitializer)
+      .around(mariaDBInitializer)
+      .around(tenantDataStoreContext);
+
+  @Rule
+  public final TenantApplicationSecurityEnvironmentTestRule tenantApplicationSecurityEnvironment
+      = new TenantApplicationSecurityEnvironmentTestRule(testEnvironment, this::waitForInitialize);
+
+  private AutoUserContext userContext;
+
+  @Autowired
+  TellerManager testSubject;
+
+  @Autowired
+  EventRecorder eventRecorder;
+
+  @MockBean
+  OrganizationService organizationServiceSpy;
+
+  @MockBean
+  AccountingService accountingServiceSpy;
+
+  @MockBean
+  DepositAccountManagementService depositAccountManagementServiceSpy;
+
+  @MockBean
+  PortfolioService portfolioServiceSpy;
+
+  @Autowired
+  private ApplicationName applicationName;
+
+  @Autowired
+  @Qualifier(LOGGER_NAME)
+  Logger logger;
+
+  @Before
+  public void prepTest() {
+    userContext = tenantApplicationSecurityEnvironment.createAutoUserContext(TEST_USER);
+    final RSAPrivateKey tenantPrivateKey = tenantApplicationSecurityEnvironment.getSystemSecurityEnvironment().tenantPrivateKey();
+    logger.info("tenantPrivateKey = {}", tenantPrivateKey);
+  }
+
+  @After
+  public void cleanTest() {
+    userContext.close();
+    eventRecorder.clear();
+  }
+
+  public boolean waitForInitialize() {
+    try {
+      final String version = this.applicationName.getVersionString();
+      this.logger.info("Waiting on initialize event for version: {}.", version);
+      return this.eventRecorder.wait(EventConstants.INITIALIZE, version);
+    } catch (final InterruptedException e) {
+      throw new IllegalStateException(e);
+    }
+  }
+}
diff --git a/component-test/src/main/java/io/mifos/teller/TestTellerManagement.java b/component-test/src/main/java/io/mifos/teller/TestTellerManagement.java
new file mode 100644
index 0000000..b9f703d
--- /dev/null
+++ b/component-test/src/main/java/io/mifos/teller/TestTellerManagement.java
@@ -0,0 +1,481 @@
+/*
+ * 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.
+ */
+package io.mifos.teller;
+
+import io.mifos.teller.api.v1.EventConstants;
+import io.mifos.teller.api.v1.client.TellerAlreadyExistsException;
+import io.mifos.teller.api.v1.client.TellerNotFoundException;
+import io.mifos.teller.api.v1.client.TellerValidationException;
+import io.mifos.teller.api.v1.domain.Teller;
+import io.mifos.teller.api.v1.domain.TellerManagementCommand;
+import io.mifos.teller.util.TellerGenerator;
+import org.apache.commons.lang3.RandomStringUtils;
+import org.junit.Assert;
+import org.junit.Test;
+import org.mockito.Matchers;
+import org.mockito.Mockito;
+
+import java.util.Arrays;
+import java.util.List;
+
+public class TestTellerManagement extends AbstractTellerTest {
+
+  public TestTellerManagement() {
+    super();
+  }
+
+  @Test
+  public void shouldCreateTeller() throws Exception {
+    final String officeIdentifier = RandomStringUtils.randomAlphabetic(32);
+    final Teller teller = TellerGenerator.createRandomTeller();
+
+    Mockito.doAnswer(invocation -> true)
+        .when(super.organizationServiceSpy).officeExists(Matchers.eq(officeIdentifier));
+
+    Mockito.doAnswer(invocation -> true)
+        .when(super.accountingServiceSpy).accountExists(Matchers.eq(teller.getTellerAccountIdentifier()));
+
+    Mockito.doAnswer(invocation -> true)
+        .when(super.accountingServiceSpy).accountExists(Matchers.eq(teller.getVaultAccountIdentifier()));
+
+    super.testSubject.create(officeIdentifier, teller);
+
+    Assert.assertTrue(super.eventRecorder.wait(EventConstants.POST_TELLER, teller.getCode()));
+  }
+
+  @Test(expected = TellerValidationException.class)
+  public void shouldNotCreateTellerUnknownOffice() throws Exception {
+    final String officeIdentifier = RandomStringUtils.randomAlphabetic(32);
+    final Teller teller = TellerGenerator.createRandomTeller();
+
+    Mockito.doAnswer(invocation -> false)
+        .when(super.organizationServiceSpy).officeExists(Matchers.eq(officeIdentifier));
+
+    super.testSubject.create(officeIdentifier, teller);
+  }
+
+  @Test(expected = TellerValidationException.class)
+  public void shouldNotCreateTellerUnknownTellerAccount() throws Exception {
+    final String officeIdentifier = RandomStringUtils.randomAlphabetic(32);
+    final Teller teller = TellerGenerator.createRandomTeller();
+
+    Mockito.doAnswer(invocation -> false)
+        .when(super.accountingServiceSpy).accountExists(Matchers.eq(teller.getTellerAccountIdentifier()));
+
+    super.testSubject.create(officeIdentifier, teller);
+  }
+
+  @Test(expected = TellerValidationException.class)
+  public void shouldNotCreateTellerUnknownVaultAccount() throws Exception {
+    final String officeIdentifier = RandomStringUtils.randomAlphabetic(32);
+    final Teller teller = TellerGenerator.createRandomTeller();
+
+    Mockito.doAnswer(invocation -> false)
+        .when(super.accountingServiceSpy).accountExists(Matchers.eq(teller.getVaultAccountIdentifier()));
+
+    super.testSubject.create(officeIdentifier, teller);
+  }
+
+
+  @Test(expected = TellerAlreadyExistsException.class)
+  public void shouldCreateTellerAlreadyExists() throws Exception {
+    final String officeIdentifier = RandomStringUtils.randomAlphabetic(32);
+    final Teller teller = TellerGenerator.createRandomTeller();
+
+    Mockito.doAnswer(invocation -> true)
+        .when(super.organizationServiceSpy).officeExists(Matchers.eq(officeIdentifier));
+
+    Mockito.doAnswer(invocation -> true)
+        .when(super.accountingServiceSpy).accountExists(Matchers.eq(teller.getTellerAccountIdentifier()));
+
+    Mockito.doAnswer(invocation -> true)
+        .when(super.accountingServiceSpy).accountExists(Matchers.eq(teller.getVaultAccountIdentifier()));
+
+    super.testSubject.create(officeIdentifier, teller);
+
+    Assert.assertTrue(super.eventRecorder.wait(EventConstants.POST_TELLER, teller.getCode()));
+
+    super.testSubject.create(officeIdentifier, teller);
+  }
+
+  @Test
+  public void shouldFindTeller() throws Exception {
+    final String officeIdentifier = RandomStringUtils.randomAlphabetic(32);
+    final Teller teller = TellerGenerator.createRandomTeller();
+
+    Mockito.doAnswer(invocation -> true)
+        .when(super.organizationServiceSpy).officeExists(Matchers.eq(officeIdentifier));
+
+    Mockito.doAnswer(invocation -> true)
+        .when(super.accountingServiceSpy).accountExists(Matchers.eq(teller.getTellerAccountIdentifier()));
+
+    Mockito.doAnswer(invocation -> true)
+        .when(super.accountingServiceSpy).accountExists(Matchers.eq(teller.getVaultAccountIdentifier()));
+
+    super.testSubject.create(officeIdentifier, teller);
+
+    Assert.assertTrue(super.eventRecorder.wait(EventConstants.POST_TELLER, teller.getCode()));
+
+    final Teller foundTeller = super.testSubject.find(officeIdentifier, teller.getCode());
+    Assert.assertNotNull(foundTeller);
+
+    this.compareTeller(teller, foundTeller);
+  }
+
+  @Test(expected = TellerValidationException.class)
+  public void shouldNotFindTellerUnknownOffice() throws Exception {
+    final String officeIdentifier = RandomStringUtils.randomAlphabetic(32);
+    final String tellerCode = RandomStringUtils.randomAlphabetic(32);
+
+    Mockito.doAnswer(invocation -> false)
+        .when(super.organizationServiceSpy).officeExists(Matchers.eq(officeIdentifier));
+
+    super.testSubject.find(officeIdentifier, tellerCode);
+  }
+
+  @Test(expected = TellerNotFoundException.class)
+  public void shouldNotFindTellerUnknownTeller() throws Exception {
+    final String officeIdentifier = RandomStringUtils.randomAlphabetic(32);
+    final String tellerCode = RandomStringUtils.randomAlphabetic(32);
+
+    Mockito.doAnswer(invocation -> true)
+        .when(super.organizationServiceSpy).officeExists(Matchers.eq(officeIdentifier));
+
+    super.testSubject.find(officeIdentifier, tellerCode);
+  }
+
+  @Test
+  public void shouldFetchTeller() throws Exception {
+    final String officeIdentifier = RandomStringUtils.randomAlphabetic(32);
+    final List<Teller> tellerToCreate = Arrays.asList(
+        TellerGenerator.createRandomTeller(),
+        TellerGenerator.createRandomTeller(),
+        TellerGenerator.createRandomTeller(),
+        TellerGenerator.createRandomTeller(),
+        TellerGenerator.createRandomTeller()
+    );
+
+    Mockito.doAnswer(invocation -> true)
+        .when(super.organizationServiceSpy).officeExists(Matchers.eq(officeIdentifier));
+
+    tellerToCreate.forEach(teller -> {
+      Mockito.doAnswer(invocation -> true)
+          .when(super.accountingServiceSpy).accountExists(Matchers.eq(teller.getTellerAccountIdentifier()));
+
+      Mockito.doAnswer(invocation -> true)
+          .when(super.accountingServiceSpy).accountExists(Matchers.eq(teller.getVaultAccountIdentifier()));
+
+      super.testSubject.create(officeIdentifier, teller);
+
+      try {
+        Assert.assertTrue(super.eventRecorder.wait(EventConstants.POST_TELLER, teller.getCode()));
+      } catch (final InterruptedException e) {
+        throw new IllegalStateException(e);
+      }
+    });
+
+    final List<Teller> fetchedTeller = super.testSubject.fetch(officeIdentifier);
+
+    Assert.assertTrue(fetchedTeller.size() >= tellerToCreate.size());
+  }
+
+  @Test(expected = TellerValidationException.class)
+  public void shouldNotFetchTellerUnknownOffice() {
+    final String officeIdentifier = RandomStringUtils.randomAlphabetic(32);
+
+    Mockito.doAnswer(invocation -> false)
+        .when(super.organizationServiceSpy).officeExists(Matchers.eq(officeIdentifier));
+
+    super.testSubject.fetch(officeIdentifier);
+  }
+
+  @Test
+  public void shouldUpdateTeller() throws Exception {
+    final String officeIdentifier = RandomStringUtils.randomAlphabetic(32);
+    final Teller teller = TellerGenerator.createRandomTeller();
+
+    Mockito.doAnswer(invocation -> true)
+        .when(super.organizationServiceSpy).officeExists(Matchers.eq(officeIdentifier));
+
+    Mockito.doAnswer(invocation -> true)
+        .when(super.accountingServiceSpy).accountExists(Matchers.eq(teller.getTellerAccountIdentifier()));
+
+    Mockito.doAnswer(invocation -> true)
+        .when(super.accountingServiceSpy).accountExists(Matchers.eq(teller.getVaultAccountIdentifier()));
+
+    super.testSubject.create(officeIdentifier, teller);
+
+    super.eventRecorder.wait(EventConstants.POST_TELLER, teller.getCode());
+
+    teller.setCashdrawLimit(15000.00D);
+
+    super.testSubject.change(officeIdentifier, teller.getCode(), teller);
+
+    Assert.assertTrue(super.eventRecorder.wait(EventConstants.PUT_TELLER, teller.getCode()));
+
+    final Teller changedTeller = super.testSubject.find(officeIdentifier, teller.getCode());
+    Assert.assertNotNull(changedTeller);
+
+    this.compareTeller(teller, changedTeller);
+  }
+
+  @Test(expected = TellerValidationException.class)
+  public void shouldNotUpdateTellerUnknownOffice() throws Exception {
+    final String officeIdentifier = RandomStringUtils.randomAlphabetic(32);
+    final Teller teller = TellerGenerator.createRandomTeller();
+
+    Mockito.doAnswer(invocation -> true)
+        .when(super.organizationServiceSpy).officeExists(Matchers.eq(officeIdentifier));
+
+    Mockito.doAnswer(invocation -> true)
+        .when(super.accountingServiceSpy).accountExists(Matchers.eq(teller.getTellerAccountIdentifier()));
+
+    Mockito.doAnswer(invocation -> true)
+        .when(super.accountingServiceSpy).accountExists(Matchers.eq(teller.getVaultAccountIdentifier()));
+
+    super.testSubject.create(officeIdentifier, teller);
+
+    super.eventRecorder.wait(EventConstants.POST_TELLER, teller.getCode());
+
+    Mockito.doAnswer(invocation -> false)
+        .when(super.organizationServiceSpy).officeExists(Matchers.eq(officeIdentifier));
+
+    super.testSubject.change(officeIdentifier, teller.getCode(), teller);
+  }
+
+  @Test(expected = TellerValidationException.class)
+  public void shouldNotUpdateTellerUnknownTellerAccount() throws Exception {
+    final String officeIdentifier = RandomStringUtils.randomAlphabetic(32);
+    final Teller teller = TellerGenerator.createRandomTeller();
+
+    Mockito.doAnswer(invocation -> true)
+        .when(super.organizationServiceSpy).officeExists(Matchers.eq(officeIdentifier));
+
+    Mockito.doAnswer(invocation -> true)
+        .when(super.accountingServiceSpy).accountExists(Matchers.eq(teller.getTellerAccountIdentifier()));
+
+    Mockito.doAnswer(invocation -> true)
+        .when(super.accountingServiceSpy).accountExists(Matchers.eq(teller.getVaultAccountIdentifier()));
+
+    super.testSubject.create(officeIdentifier, teller);
+
+    super.eventRecorder.wait(EventConstants.POST_TELLER, teller.getCode());
+
+    teller.setTellerAccountIdentifier(RandomStringUtils.randomAlphanumeric(32));
+
+    Mockito.doAnswer(invocation -> false)
+        .when(super.accountingServiceSpy).accountExists(Matchers.eq(teller.getTellerAccountIdentifier()));
+
+    super.testSubject.change(officeIdentifier, teller.getCode(), teller);
+  }
+
+  @Test(expected = TellerValidationException.class)
+  public void shouldNotUpdateTellerUnknownVaultAccount() throws Exception {
+    final String officeIdentifier = RandomStringUtils.randomAlphabetic(32);
+    final Teller teller = TellerGenerator.createRandomTeller();
+
+    Mockito.doAnswer(invocation -> true)
+        .when(super.organizationServiceSpy).officeExists(Matchers.eq(officeIdentifier));
+
+    Mockito.doAnswer(invocation -> true)
+        .when(super.accountingServiceSpy).accountExists(Matchers.eq(teller.getTellerAccountIdentifier()));
+
+    Mockito.doAnswer(invocation -> true)
+        .when(super.accountingServiceSpy).accountExists(Matchers.eq(teller.getVaultAccountIdentifier()));
+
+    super.testSubject.create(officeIdentifier, teller);
+
+    super.eventRecorder.wait(EventConstants.POST_TELLER, teller.getCode());
+
+    teller.setVaultAccountIdentifier(RandomStringUtils.randomAlphanumeric(32));
+
+    Mockito.doAnswer(invocation -> false)
+        .when(super.accountingServiceSpy).accountExists(Matchers.eq(teller.getVaultAccountIdentifier()));
+
+    super.testSubject.change(officeIdentifier, teller.getCode(), teller);
+  }
+
+  @Test(expected = TellerValidationException.class)
+  public void shouldNotUpdateTellerMismatch() throws Exception {
+    final String officeIdentifier = RandomStringUtils.randomAlphabetic(32);
+    final String tellerCode = RandomStringUtils.randomAlphanumeric(32);
+    final Teller teller = TellerGenerator.createRandomTeller();
+    teller.setCode(tellerCode);
+
+    Mockito.doAnswer(invocation -> true)
+        .when(super.organizationServiceSpy).officeExists(Matchers.eq(officeIdentifier));
+
+    Mockito.doAnswer(invocation -> true)
+        .when(super.accountingServiceSpy).accountExists(Matchers.eq(teller.getTellerAccountIdentifier()));
+
+    Mockito.doAnswer(invocation -> true)
+        .when(super.accountingServiceSpy).accountExists(Matchers.eq(teller.getVaultAccountIdentifier()));
+
+    super.testSubject.create(officeIdentifier, teller);
+
+    super.eventRecorder.wait(EventConstants.POST_TELLER, teller.getCode());
+
+    teller.setCode(RandomStringUtils.randomAlphanumeric(32));
+
+    super.testSubject.change(officeIdentifier, tellerCode, teller);
+  }
+
+  @Test(expected = TellerNotFoundException.class)
+  public void shouldNotUpdateTellerUnknownTeller() {
+    final String officeIdentifier = RandomStringUtils.randomAlphabetic(32);
+    final Teller teller = TellerGenerator.createRandomTeller();
+
+    super.testSubject.change(officeIdentifier, teller.getCode(), teller);
+  }
+
+  @Test
+  public void shouldOpenTeller() throws Exception {
+    final String officeIdentifier = RandomStringUtils.randomAlphabetic(32);
+    final Teller teller = TellerGenerator.createRandomTeller();
+
+    Mockito.doAnswer(invocation -> true)
+        .when(super.organizationServiceSpy).officeExists(Matchers.eq(officeIdentifier));
+
+    Mockito.doAnswer(invocation -> true)
+        .when(super.accountingServiceSpy).accountExists(Matchers.eq(teller.getTellerAccountIdentifier()));
+
+    Mockito.doAnswer(invocation -> true)
+        .when(super.accountingServiceSpy).accountExists(Matchers.eq(teller.getVaultAccountIdentifier()));
+
+    super.testSubject.create(officeIdentifier, teller);
+
+    super.eventRecorder.wait(EventConstants.POST_TELLER, teller.getCode());
+
+    final TellerManagementCommand command = new TellerManagementCommand();
+    command.setAction(TellerManagementCommand.Action.OPEN.name());
+    command.setAssignedEmployeeIdentifier(RandomStringUtils.randomAlphanumeric(32));
+
+    Mockito.doAnswer(invocation -> true)
+        .when(super.organizationServiceSpy).employeeExists(Matchers.eq(command.getAssignedEmployeeIdentifier()));
+
+    super.testSubject.post(officeIdentifier, teller.getCode(), command);
+
+    Assert.assertTrue(super.eventRecorder.wait(EventConstants.OPEN_TELLER, teller.getCode()));
+
+    final Teller openedTeller = super.testSubject.find(officeIdentifier, teller.getCode());
+    Assert.assertEquals(Teller.State.OPEN.name(), openedTeller.getState());
+    Assert.assertEquals(command.getAssignedEmployeeIdentifier(), openedTeller.getAssignedEmployee());
+  }
+
+  @Test
+  public void shouldCloseTeller() throws Exception {
+    final String officeIdentifier = RandomStringUtils.randomAlphabetic(32);
+    final Teller teller = TellerGenerator.createRandomTeller();
+
+    Mockito.doAnswer(invocation -> true)
+        .when(super.organizationServiceSpy).officeExists(Matchers.eq(officeIdentifier));
+
+    Mockito.doAnswer(invocation -> true)
+        .when(super.accountingServiceSpy).accountExists(Matchers.eq(teller.getTellerAccountIdentifier()));
+
+    Mockito.doAnswer(invocation -> true)
+        .when(super.accountingServiceSpy).accountExists(Matchers.eq(teller.getVaultAccountIdentifier()));
+
+    super.testSubject.create(officeIdentifier, teller);
+
+    super.eventRecorder.wait(EventConstants.POST_TELLER, teller.getCode());
+
+    final TellerManagementCommand command = new TellerManagementCommand();
+    command.setAction(TellerManagementCommand.Action.OPEN.name());
+    command.setAssignedEmployeeIdentifier(RandomStringUtils.randomAlphanumeric(32));
+
+    Mockito.doAnswer(invocation -> true)
+        .when(super.organizationServiceSpy).employeeExists(Matchers.eq(command.getAssignedEmployeeIdentifier()));
+
+    super.testSubject.post(officeIdentifier, teller.getCode(), command);
+
+    super.eventRecorder.wait(EventConstants.OPEN_TELLER, teller.getCode());
+
+    command.setAction(TellerManagementCommand.Action.CLOSE.name());
+    command.setAssignedEmployeeIdentifier(null);
+    super.testSubject.post(officeIdentifier, teller.getCode(), command);
+
+    Assert.assertTrue(super.eventRecorder.wait(EventConstants.CLOSE_TELLER, teller.getCode()));
+
+    final Teller openedTeller = super.testSubject.find(officeIdentifier, teller.getCode());
+    Assert.assertEquals(Teller.State.CLOSED.name(), openedTeller.getState());
+    Assert.assertNull(openedTeller.getAssignedEmployee());
+  }
+
+  @Test(expected = TellerValidationException.class)
+  public void shouldNotCloseTellerAlreadyClosed() throws Exception {
+    final String officeIdentifier = RandomStringUtils.randomAlphabetic(32);
+    final Teller teller = TellerGenerator.createRandomTeller();
+
+    Mockito.doAnswer(invocation -> true)
+        .when(super.organizationServiceSpy).officeExists(Matchers.eq(officeIdentifier));
+
+    Mockito.doAnswer(invocation -> true)
+        .when(super.accountingServiceSpy).accountExists(Matchers.eq(teller.getTellerAccountIdentifier()));
+
+    Mockito.doAnswer(invocation -> true)
+        .when(super.accountingServiceSpy).accountExists(Matchers.eq(teller.getVaultAccountIdentifier()));
+
+    super.testSubject.create(officeIdentifier, teller);
+
+    super.eventRecorder.wait(EventConstants.POST_TELLER, teller.getCode());
+
+    final TellerManagementCommand command = new TellerManagementCommand();
+    command.setAction(TellerManagementCommand.Action.CLOSE.name());
+
+    super.testSubject.post(officeIdentifier, teller.getCode(), command);
+  }
+
+  @Test(expected = TellerValidationException.class)
+  public void shouldNotOpenTellerAlreadyOpen() throws Exception {
+    final String officeIdentifier = RandomStringUtils.randomAlphabetic(32);
+    final Teller teller = TellerGenerator.createRandomTeller();
+
+    Mockito.doAnswer(invocation -> true)
+        .when(super.organizationServiceSpy).officeExists(Matchers.eq(officeIdentifier));
+
+    Mockito.doAnswer(invocation -> true)
+        .when(super.accountingServiceSpy).accountExists(Matchers.eq(teller.getTellerAccountIdentifier()));
+
+    Mockito.doAnswer(invocation -> true)
+        .when(super.accountingServiceSpy).accountExists(Matchers.eq(teller.getVaultAccountIdentifier()));
+
+    super.testSubject.create(officeIdentifier, teller);
+
+    super.eventRecorder.wait(EventConstants.POST_TELLER, teller.getCode());
+
+    final TellerManagementCommand command = new TellerManagementCommand();
+    command.setAction(TellerManagementCommand.Action.OPEN.name());
+    command.setAssignedEmployeeIdentifier(RandomStringUtils.randomAlphanumeric(32));
+
+    Mockito.doAnswer(invocation -> true)
+        .when(super.organizationServiceSpy).employeeExists(Matchers.eq(command.getAssignedEmployeeIdentifier()));
+
+    super.testSubject.post(officeIdentifier, teller.getCode(), command);
+
+    super.eventRecorder.wait(EventConstants.OPEN_TELLER, teller.getCode());
+
+    // and again ...
+    super.testSubject.post(officeIdentifier, teller.getCode(), command);
+  }
+
+  private void compareTeller(final Teller expected, final Teller actual) {
+    Assert.assertEquals(expected.getCode(), actual.getCode());
+    Assert.assertEquals(expected.getTellerAccountIdentifier(), actual.getTellerAccountIdentifier());
+    Assert.assertEquals(expected.getVaultAccountIdentifier(), actual.getVaultAccountIdentifier());
+    Assert.assertEquals(expected.getCashdrawLimit(), actual.getCashdrawLimit());
+  }
+}
diff --git a/component-test/src/main/java/io/mifos/teller/listener/MigrationEventListener.java b/component-test/src/main/java/io/mifos/teller/listener/MigrationEventListener.java
new file mode 100644
index 0000000..30de7c1
--- /dev/null
+++ b/component-test/src/main/java/io/mifos/teller/listener/MigrationEventListener.java
@@ -0,0 +1,53 @@
+/*
+ * 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.
+ */
+package io.mifos.teller.listener;
+
+import io.mifos.core.lang.config.TenantHeaderFilter;
+import io.mifos.core.test.listener.EventRecorder;
+import io.mifos.teller.AbstractTellerTest;
+import io.mifos.teller.api.v1.EventConstants;
+import org.slf4j.Logger;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.beans.factory.annotation.Qualifier;
+import org.springframework.jms.annotation.JmsListener;
+import org.springframework.messaging.handler.annotation.Header;
+import org.springframework.stereotype.Component;
+
+@Component
+public class MigrationEventListener {
+
+  private final Logger logger;
+  private final EventRecorder eventRecorder;
+
+  @Autowired
+  public MigrationEventListener(@Qualifier(AbstractTellerTest.LOGGER_NAME) final Logger logger,
+                                final EventRecorder eventRecorder) {
+    super();
+    this.logger = logger;
+    this.eventRecorder = eventRecorder;
+  }
+
+  @JmsListener(
+      destination = EventConstants.DESTINATION,
+      selector = EventConstants.SELECTOR_INITIALIZE,
+      subscription = EventConstants.DESTINATION
+  )
+  public void onInitialize(@Header(TenantHeaderFilter.TENANT_HEADER) final String tenant,
+                           final String payload) {
+    this.logger.debug("Service initialized.");
+    this.eventRecorder.event(tenant, EventConstants.INITIALIZE, payload, String.class);
+  }
+}
diff --git a/component-test/src/main/java/io/mifos/teller/listener/TellerEventListener.java b/component-test/src/main/java/io/mifos/teller/listener/TellerEventListener.java
new file mode 100644
index 0000000..ee40f75
--- /dev/null
+++ b/component-test/src/main/java/io/mifos/teller/listener/TellerEventListener.java
@@ -0,0 +1,84 @@
+/*
+ * 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.
+ */
+package io.mifos.teller.listener;
+
+import io.mifos.core.lang.config.TenantHeaderFilter;
+import io.mifos.core.test.listener.EventRecorder;
+import io.mifos.teller.AbstractTellerTest;
+import io.mifos.teller.api.v1.EventConstants;
+import org.slf4j.Logger;
+import org.springframework.beans.factory.annotation.Qualifier;
+import org.springframework.jms.annotation.JmsListener;
+import org.springframework.messaging.handler.annotation.Header;
+import org.springframework.stereotype.Component;
+
+@Component
+public class TellerEventListener {
+
+  private final Logger logger;
+  private final EventRecorder eventRecorder;
+
+  public TellerEventListener(@Qualifier(AbstractTellerTest.LOGGER_NAME) final Logger logger,
+                             final EventRecorder eventRecorder) {
+    super();
+    this.logger = logger;
+    this.eventRecorder = eventRecorder;
+  }
+
+  @JmsListener(
+      destination = EventConstants.DESTINATION,
+      selector = EventConstants.SELECTOR_POST_TELLER,
+      subscription = EventConstants.DESTINATION
+  )
+  public void onCreate(@Header(TenantHeaderFilter.TENANT_HEADER) final String tenant,
+                           final String payload) {
+    this.logger.debug("Teller {} created.", payload);
+    this.eventRecorder.event(tenant, EventConstants.POST_TELLER, payload, String.class);
+  }
+
+  @JmsListener(
+      destination = EventConstants.DESTINATION,
+      selector = EventConstants.SELECTOR_PUT_TELLER,
+      subscription = EventConstants.DESTINATION
+  )
+  public void onChange(@Header(TenantHeaderFilter.TENANT_HEADER) final String tenant,
+                           final String payload) {
+    this.logger.debug("Teller {} created.", payload);
+    this.eventRecorder.event(tenant, EventConstants.PUT_TELLER, payload, String.class);
+  }
+
+  @JmsListener(
+      destination = EventConstants.DESTINATION,
+      selector = EventConstants.SELECTOR_OPEN_TELLER,
+      subscription = EventConstants.DESTINATION
+  )
+  public void onOpen(@Header(TenantHeaderFilter.TENANT_HEADER) final String tenant,
+                       final String payload) {
+    this.logger.debug("Teller {} created.", payload);
+    this.eventRecorder.event(tenant, EventConstants.OPEN_TELLER, payload, String.class);
+  }
+
+  @JmsListener(
+      destination = EventConstants.DESTINATION,
+      selector = EventConstants.SELECTOR_CLOSE_TELLER,
+      subscription = EventConstants.DESTINATION
+  )
+  public void onClose(@Header(TenantHeaderFilter.TENANT_HEADER) final String tenant,
+                     final String payload) {
+    this.logger.debug("Teller {} created.", payload);
+    this.eventRecorder.event(tenant, EventConstants.CLOSE_TELLER, payload, String.class);
+  }
+}
diff --git a/component-test/src/main/java/io/mifos/teller/util/TellerGenerator.java b/component-test/src/main/java/io/mifos/teller/util/TellerGenerator.java
new file mode 100644
index 0000000..baec507
--- /dev/null
+++ b/component-test/src/main/java/io/mifos/teller/util/TellerGenerator.java
@@ -0,0 +1,37 @@
+/*
+ * 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.
+ */
+package io.mifos.teller.util;
+
+import io.mifos.teller.api.v1.domain.Teller;
+import org.apache.commons.lang3.RandomStringUtils;
+
+public class TellerGenerator {
+
+  public TellerGenerator() {
+    super();
+  }
+
+  public static Teller createRandomTeller() {
+    final Teller teller = new Teller();
+    teller.setCode(RandomStringUtils.randomAlphanumeric(32));
+    teller.setPassword(RandomStringUtils.randomAlphanumeric(12));
+    teller.setTellerAccountIdentifier(RandomStringUtils.randomAlphanumeric(32));
+    teller.setVaultAccountIdentifier(RandomStringUtils.randomAlphanumeric(32));
+    teller.setCashdrawLimit(10000.00D);
+
+    return teller;
+  }
+}
diff --git a/component-test/src/main/resources/logback-test.xml b/component-test/src/main/resources/logback-test.xml
index 1d5c4e7..57424f0 100644
--- a/component-test/src/main/resources/logback-test.xml
+++ b/component-test/src/main/resources/logback-test.xml
@@ -22,11 +22,11 @@
         </encoder>
     </appender>
 
-    <logger name="org" level="OFF"/>
+    <logger name="org" level="INFO"/>
     <logger name="com" level="OFF"/>
     <logger name="ch" level="OFF"/>
 
-    <root level="DEBUG">
+    <root level="INFO">
         <appender-ref ref="STDOUT"/>
     </root>
 </configuration>
\ No newline at end of file
diff --git a/service/build.gradle b/service/build.gradle
index a00147c..dad52d3 100644
--- a/service/build.gradle
+++ b/service/build.gradle
@@ -31,6 +31,10 @@ dependencies {
             [group: 'org.springframework.cloud', name: 'spring-cloud-starter-eureka'],
             [group: 'org.springframework.boot', name: 'spring-boot-starter-jetty'],
             [group: 'io.mifos.teller', name: 'api', version: project.version],
+            [group: 'io.mifos.office', name: 'api', version: versions.frameworkoffice],
+            [group: 'io.mifos.accounting', name: 'api', version: versions.frameworkaccounting],
+            [group: 'io.mifos.deposit-account-management', name: 'api', version: versions.frameworkdeposit],
+            [group: 'io.mifos.portfolio', name: 'api', version: versions.frameworkportfolio],
             [group: 'io.mifos.anubis', name: 'library', version: versions.frameworkanubis],
             [group: 'com.google.code.gson', name: 'gson'],
             [group: 'io.mifos.core', name: 'lang', version: versions.frameworklang],
@@ -38,6 +42,7 @@ dependencies {
             [group: 'io.mifos.core', name: 'cassandra', version: versions.frameworkcassandra],
             [group: 'io.mifos.core', name: 'mariadb', version: versions.frameworkmariadb],
             [group: 'io.mifos.core', name: 'command', version: versions.frameworkcommand],
+            [group: 'io.mifos.tools', name: 'crypto', version: versions.frameworkcrypto],
             [group: 'org.hibernate', name: 'hibernate-validator', version: versions.validator]
     )
 }
diff --git a/service/src/main/java/io/mifos/teller/ServiceConstants.java b/service/src/main/java/io/mifos/teller/ServiceConstants.java
index 98de3be..adfef4e 100644
--- a/service/src/main/java/io/mifos/teller/ServiceConstants.java
+++ b/service/src/main/java/io/mifos/teller/ServiceConstants.java
@@ -17,4 +17,6 @@ package io.mifos.teller;
 
 public interface ServiceConstants {
   String LOGGER_NAME = "teller-logger";
+  int ITERATION_COUNT = 2048;
+  int LENGTH = 2048;
 }
diff --git a/service/src/main/java/io/mifos/teller/TellerConfiguration.java b/service/src/main/java/io/mifos/teller/TellerConfiguration.java
index 42b730a..5c60d5b 100644
--- a/service/src/main/java/io/mifos/teller/TellerConfiguration.java
+++ b/service/src/main/java/io/mifos/teller/TellerConfiguration.java
@@ -15,6 +15,7 @@
  */
 package io.mifos.teller;
 
+import io.mifos.accounting.api.v1.client.LedgerManager;
 import io.mifos.anubis.config.EnableAnubis;
 import io.mifos.core.async.config.EnableAsync;
 import io.mifos.core.cassandra.config.EnableCassandra;
@@ -22,10 +23,15 @@ 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.deposit.api.v1.client.DepositAccountManager;
+import io.mifos.office.api.v1.client.OrganizationManager;
+import io.mifos.portfolio.api.v1.client.PortfolioManager;
+import io.mifos.tool.crypto.config.EnableCrypto;
 import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
 import org.springframework.boot.autoconfigure.EnableAutoConfiguration;
 import org.springframework.cloud.client.discovery.EnableDiscoveryClient;
+import org.springframework.cloud.netflix.feign.EnableFeignClients;
 import org.springframework.context.annotation.Bean;
 import org.springframework.context.annotation.ComponentScan;
 import org.springframework.context.annotation.Configuration;
@@ -44,6 +50,15 @@ import org.springframework.web.servlet.config.annotation.WebMvcConfigurerAdapter
 @EnableCommandProcessing
 @EnableAnubis
 @EnableServiceException
+@EnableCrypto
+@EnableFeignClients(
+    clients = {
+        OrganizationManager.class,
+        LedgerManager.class,
+        DepositAccountManager.class,
+        PortfolioManager.class
+    }
+)
 @ComponentScan({
     "io.mifos.teller.service.rest",
     "io.mifos.teller.service.internal.service",
diff --git a/api/src/main/java/io/mifos/teller/EventConstants.java b/service/src/main/java/io/mifos/teller/service/internal/command/ChangeTellerCommand.java
similarity index 54%
copy from api/src/main/java/io/mifos/teller/EventConstants.java
copy to service/src/main/java/io/mifos/teller/service/internal/command/ChangeTellerCommand.java
index f2a0d0b..795bf2d 100644
--- a/api/src/main/java/io/mifos/teller/EventConstants.java
+++ b/service/src/main/java/io/mifos/teller/service/internal/command/ChangeTellerCommand.java
@@ -13,18 +13,26 @@
  * See the License for the specific language governing permissions and
  * limitations under the License.
  */
-package io.mifos.teller;
+package io.mifos.teller.service.internal.command;
 
-@SuppressWarnings("unused")
-public interface EventConstants {
+import io.mifos.teller.api.v1.domain.Teller;
 
-  String DESTINATION = "teller-v1";
+public class ChangeTellerCommand {
 
-  String SELECTOR_NAME = "operation";
+  private final String officeIdentifier;
+  private final Teller teller;
 
-  String INITIALIZE = "initialize";
-  String SELECTOR_INITIALIZE = SELECTOR_NAME + " = '" + INITIALIZE + "'";
+  public ChangeTellerCommand(final String officeIdentifier, final Teller teller) {
+    super();
+    this.officeIdentifier = officeIdentifier;
+    this.teller = teller;
+  }
 
-  String POST_TELLER = "post-teller";
-  String SELECTOR_POST_TELLER = SELECTOR_NAME + " = '" + POST_TELLER + "'";
+  public String officeIdentifier() {
+    return this.officeIdentifier;
+  }
+
+  public Teller teller() {
+    return this.teller;
+  }
 }
diff --git a/service/src/main/java/io/mifos/teller/service/internal/command/CloseTellerCommand.java b/service/src/main/java/io/mifos/teller/service/internal/command/CloseTellerCommand.java
new file mode 100644
index 0000000..c3825e7
--- /dev/null
+++ b/service/src/main/java/io/mifos/teller/service/internal/command/CloseTellerCommand.java
@@ -0,0 +1,38 @@
+/*
+ * 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.
+ */
+package io.mifos.teller.service.internal.command;
+
+import io.mifos.teller.api.v1.domain.TellerManagementCommand;
+
+public class CloseTellerCommand {
+
+  private final String tellerCode;
+  private final TellerManagementCommand tellerManagementCommand;
+
+  public CloseTellerCommand(final String tellerCode, final TellerManagementCommand tellerManagementCommand) {
+    super();
+    this.tellerCode = tellerCode;
+    this.tellerManagementCommand = tellerManagementCommand;
+  }
+
+  public String tellerCode() {
+    return this.tellerCode;
+  }
+
+  public TellerManagementCommand tellerManagementCommand() {
+    return this.tellerManagementCommand;
+  }
+}
diff --git a/api/src/main/java/io/mifos/teller/EventConstants.java b/service/src/main/java/io/mifos/teller/service/internal/command/CreateTellerCommand.java
similarity index 54%
copy from api/src/main/java/io/mifos/teller/EventConstants.java
copy to service/src/main/java/io/mifos/teller/service/internal/command/CreateTellerCommand.java
index f2a0d0b..dd2f12e 100644
--- a/api/src/main/java/io/mifos/teller/EventConstants.java
+++ b/service/src/main/java/io/mifos/teller/service/internal/command/CreateTellerCommand.java
@@ -13,18 +13,26 @@
  * See the License for the specific language governing permissions and
  * limitations under the License.
  */
-package io.mifos.teller;
+package io.mifos.teller.service.internal.command;
 
-@SuppressWarnings("unused")
-public interface EventConstants {
+import io.mifos.teller.api.v1.domain.Teller;
 
-  String DESTINATION = "teller-v1";
+public class CreateTellerCommand {
 
-  String SELECTOR_NAME = "operation";
+  private final String officeIdentifier;
+  private final Teller teller;
 
-  String INITIALIZE = "initialize";
-  String SELECTOR_INITIALIZE = SELECTOR_NAME + " = '" + INITIALIZE + "'";
+  public CreateTellerCommand(final String officeIdentifier, final Teller teller) {
+    super();
+    this.officeIdentifier = officeIdentifier;
+    this.teller = teller;
+  }
 
-  String POST_TELLER = "post-teller";
-  String SELECTOR_POST_TELLER = SELECTOR_NAME + " = '" + POST_TELLER + "'";
+  public String officeIdentifier() {
+    return this.officeIdentifier;
+  }
+
+  public Teller teller() {
+    return this.teller;
+  }
 }
diff --git a/service/src/main/java/io/mifos/teller/ServiceConstants.java b/service/src/main/java/io/mifos/teller/service/internal/command/MigrationCommand.java
similarity index 82%
copy from service/src/main/java/io/mifos/teller/ServiceConstants.java
copy to service/src/main/java/io/mifos/teller/service/internal/command/MigrationCommand.java
index 98de3be..6729c89 100644
--- a/service/src/main/java/io/mifos/teller/ServiceConstants.java
+++ b/service/src/main/java/io/mifos/teller/service/internal/command/MigrationCommand.java
@@ -13,8 +13,11 @@
  * See the License for the specific language governing permissions and
  * limitations under the License.
  */
-package io.mifos.teller;
+package io.mifos.teller.service.internal.command;
 
-public interface ServiceConstants {
-  String LOGGER_NAME = "teller-logger";
+public class MigrationCommand {
+
+  public MigrationCommand() {
+    super();
+  }
 }
diff --git a/service/src/main/java/io/mifos/teller/service/internal/command/OpenTellerCommand.java b/service/src/main/java/io/mifos/teller/service/internal/command/OpenTellerCommand.java
new file mode 100644
index 0000000..f28d09e
--- /dev/null
+++ b/service/src/main/java/io/mifos/teller/service/internal/command/OpenTellerCommand.java
@@ -0,0 +1,38 @@
+/*
+ * 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.
+ */
+package io.mifos.teller.service.internal.command;
+
+import io.mifos.teller.api.v1.domain.TellerManagementCommand;
+
+public class OpenTellerCommand {
+
+  private final String tellerCode;
+  private final TellerManagementCommand tellerManagementCommand;
+
+  public OpenTellerCommand(final String tellerCode, final TellerManagementCommand tellerManagementCommand) {
+    super();
+    this.tellerCode = tellerCode;
+    this.tellerManagementCommand = tellerManagementCommand;
+  }
+
+  public String tellerCode() {
+    return this.tellerCode;
+  }
+
+  public TellerManagementCommand tellerManagementCommand() {
+    return this.tellerManagementCommand;
+  }
+}
diff --git a/service/src/main/java/io/mifos/teller/service/internal/command/handler/MigrationAggregate.java b/service/src/main/java/io/mifos/teller/service/internal/command/handler/MigrationAggregate.java
new file mode 100644
index 0000000..a48c686
--- /dev/null
+++ b/service/src/main/java/io/mifos/teller/service/internal/command/handler/MigrationAggregate.java
@@ -0,0 +1,63 @@
+/*
+ * 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.
+ */
+package io.mifos.teller.service.internal.command.handler;
+
+import io.mifos.core.command.annotation.Aggregate;
+import io.mifos.core.command.annotation.CommandHandler;
+import io.mifos.core.command.annotation.EventEmitter;
+import io.mifos.core.lang.ApplicationName;
+import io.mifos.core.mariadb.domain.FlywayFactoryBean;
+import io.mifos.teller.ServiceConstants;
+import io.mifos.teller.api.v1.EventConstants;
+import io.mifos.teller.service.internal.command.MigrationCommand;
+import org.slf4j.Logger;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.beans.factory.annotation.Qualifier;
+import org.springframework.transaction.annotation.Transactional;
+
+import javax.sql.DataSource;
+
+@Aggregate
+public class MigrationAggregate {
+
+  private final Logger logger;
+  private final DataSource dataSource;
+  private final FlywayFactoryBean flywayFactoryBean;
+  private final ApplicationName applicationName;
+
+  @Autowired
+  public MigrationAggregate(@Qualifier(ServiceConstants.LOGGER_NAME) final Logger logger,
+                            final DataSource dataSource,
+                            final FlywayFactoryBean flywayFactoryBean,
+                            final ApplicationName applicationName) {
+    super();
+    this.logger = logger;
+    this.dataSource = dataSource;
+    this.flywayFactoryBean = flywayFactoryBean;
+    this.applicationName = applicationName;
+  }
+
+  @CommandHandler
+  @EventEmitter(selectorName = EventConstants.SELECTOR_NAME, selectorValue = EventConstants.INITIALIZE)
+  @Transactional
+  public String process(final MigrationCommand migrationCommand) {
+    this.logger.info("Starting migration for teller version: {}.", applicationName.getVersionString());
+    this.flywayFactoryBean.create(this.dataSource).migrate();
+
+    this.logger.info("Migration finished.");
+    return this.applicationName.getVersionString();
+  }
+}
diff --git a/service/src/main/java/io/mifos/teller/service/internal/command/handler/TellerAggregate.java b/service/src/main/java/io/mifos/teller/service/internal/command/handler/TellerAggregate.java
new file mode 100644
index 0000000..9fb534f
--- /dev/null
+++ b/service/src/main/java/io/mifos/teller/service/internal/command/handler/TellerAggregate.java
@@ -0,0 +1,278 @@
+/*
+ * 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.
+ */
+package io.mifos.teller.service.internal.command.handler;
+
+import com.google.common.collect.Sets;
+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.core.api.util.UserContextHolder;
+import io.mifos.core.command.annotation.Aggregate;
+import io.mifos.core.command.annotation.CommandHandler;
+import io.mifos.core.command.annotation.EventEmitter;
+import io.mifos.core.lang.DateConverter;
+import io.mifos.teller.ServiceConstants;
+import io.mifos.teller.api.v1.EventConstants;
+import io.mifos.teller.api.v1.domain.Teller;
+import io.mifos.teller.api.v1.domain.TellerManagementCommand;
+import io.mifos.teller.service.internal.command.ChangeTellerCommand;
+import io.mifos.teller.service.internal.command.CloseTellerCommand;
+import io.mifos.teller.service.internal.command.CreateTellerCommand;
+import io.mifos.teller.service.internal.command.OpenTellerCommand;
+import io.mifos.teller.service.internal.mapper.TellerMapper;
+import io.mifos.teller.service.internal.repository.TellerEntity;
+import io.mifos.teller.service.internal.repository.TellerRepository;
+import io.mifos.teller.service.internal.service.helper.AccountingService;
+import io.mifos.teller.service.internal.service.helper.OrganizationService;
+import io.mifos.tool.crypto.HashGenerator;
+import io.mifos.tool.crypto.SaltGenerator;
+import org.apache.commons.lang.RandomStringUtils;
+import org.slf4j.Logger;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.beans.factory.annotation.Qualifier;
+import org.springframework.transaction.annotation.Transactional;
+import org.springframework.util.Base64Utils;
+
+import java.time.Clock;
+import java.time.LocalDateTime;
+import java.util.Optional;
+
+@Aggregate
+public class TellerAggregate {
+
+  private final Logger logger;
+  private final TellerRepository tellerRepository;
+  private final OrganizationService organizationService;
+  private final AccountingService accountingService;
+  private final HashGenerator hashGenerator;
+  private final SaltGenerator saltGenerator;
+
+  @Autowired
+  public TellerAggregate(@Qualifier(ServiceConstants.LOGGER_NAME) final Logger logger,
+                         final TellerRepository tellerRepository,
+                         final OrganizationService organizationService,
+                         final AccountingService accountingService,
+                         final HashGenerator hashGenerator,
+                         final SaltGenerator saltGenerator) {
+    super();
+    this.logger = logger;
+    this.tellerRepository = tellerRepository;
+    this.organizationService = organizationService;
+    this.accountingService = accountingService;
+    this.hashGenerator = hashGenerator;
+    this.saltGenerator = saltGenerator;
+  }
+
+  @Transactional
+  @CommandHandler
+  @EventEmitter(selectorName = EventConstants.SELECTOR_NAME, selectorValue = EventConstants.POST_TELLER)
+  public String process(final CreateTellerCommand createTellerCommand) {
+    final String officeIdentifier = createTellerCommand.officeIdentifier();
+    final Teller teller = createTellerCommand.teller();
+
+    if (this.checkPreconditions(officeIdentifier, teller)) {
+
+      final TellerEntity tellerEntity = TellerMapper.map(officeIdentifier, teller);
+
+      this.encryptPassword(teller, tellerEntity);
+
+      tellerEntity.setState(Teller.State.CLOSED.name());
+      tellerEntity.setCreatedBy(UserContextHolder.checkedGetUser());
+      tellerEntity.setCreatedOn(LocalDateTime.now(Clock.systemUTC()));
+
+      this.tellerRepository.save(tellerEntity);
+
+      return teller.getCode();
+    } else {
+      throw new IllegalStateException("Preconditions not met, see log file for further information.");
+    }
+  }
+
+  @Transactional
+  @CommandHandler
+  @EventEmitter(selectorName = EventConstants.SELECTOR_NAME, selectorValue = EventConstants.PUT_TELLER)
+  public String process(final ChangeTellerCommand changeTellerCommand) {
+    final String officeIdentifier = changeTellerCommand.officeIdentifier();
+    final Teller teller = changeTellerCommand.teller();
+
+    if (this.checkPreconditions(officeIdentifier, teller)) {
+      final Optional<TellerEntity> optionalTellerEntity = this.tellerRepository.findByIdentifier(teller.getCode());
+      if (optionalTellerEntity.isPresent()) {
+        final TellerEntity tellerEntity = optionalTellerEntity.get();
+
+        this.encryptPassword(teller, tellerEntity);
+
+        tellerEntity.setTellerAccountIdentifier(teller.getTellerAccountIdentifier());
+        tellerEntity.setVaultAccountIdentifier(teller.getVaultAccountIdentifier());
+        tellerEntity.setCashdrawLimit(teller.getCashdrawLimit());
+        tellerEntity.setLastModifiedBy(UserContextHolder.checkedGetUser());
+        tellerEntity.setLastModifiedOn(LocalDateTime.now(Clock.systemUTC()));
+
+        this.tellerRepository.save(tellerEntity);
+
+        return teller.getCode();
+      } else {
+        throw new IllegalStateException("Teller " + teller.getCode() + " not found.");
+      }
+    } else {
+      throw new IllegalStateException("Preconditions not met, see log file for further information.");
+    }
+  }
+
+  @Transactional
+  @CommandHandler
+  @EventEmitter(selectorName = EventConstants.SELECTOR_NAME, selectorValue = EventConstants.OPEN_TELLER)
+  public String process(final OpenTellerCommand openTellerCommand) {
+    final String tellerCode = openTellerCommand.tellerCode();
+    final TellerManagementCommand tellerManagementCommand = openTellerCommand.tellerManagementCommand();
+
+    final Optional<TellerEntity> optionalTellerEntity = this.tellerRepository.findByIdentifier(tellerCode);
+    if (optionalTellerEntity.isPresent()) {
+      final TellerEntity tellerEntity = optionalTellerEntity.get();
+
+      if (this.checkPreconditions(tellerEntity.getOfficeIdentifier(), TellerMapper.map(tellerEntity))) {
+
+        if (tellerManagementCommand.getAmount() != null && tellerManagementCommand.getAmount() > 0.00D) {
+          this.accountingService.postJournalEntry(this.createJournalEntry(tellerEntity, tellerManagementCommand));
+        }
+
+        tellerEntity.setAssignedEmployeeIdentifier(tellerManagementCommand.getAssignedEmployeeIdentifier());
+        tellerEntity.setState(Teller.State.OPEN.name());
+        tellerEntity.setLastModifiedBy(UserContextHolder.checkedGetUser());
+        tellerEntity.setLastModifiedOn(LocalDateTime.now(Clock.systemUTC()));
+
+        this.tellerRepository.save(tellerEntity);
+        return tellerCode;
+      } else {
+        throw new IllegalStateException("Preconditions not met, see log file for further information.");
+      }
+    } else {
+      throw new IllegalStateException("Teller " + tellerCode + " not found.");
+    }
+  }
+
+  @Transactional
+  @CommandHandler
+  @EventEmitter(selectorName = EventConstants.SELECTOR_NAME, selectorValue = EventConstants.CLOSE_TELLER)
+  public String process(final CloseTellerCommand closeTellerCommand) {
+    final String tellerCode = closeTellerCommand.tellerCode();
+    final TellerManagementCommand tellerManagementCommand = closeTellerCommand.tellerManagementCommand();
+
+    final Optional<TellerEntity> optionalTellerEntity = this.tellerRepository.findByIdentifier(tellerCode);
+    if (optionalTellerEntity.isPresent()) {
+      final TellerEntity tellerEntity = optionalTellerEntity.get();
+
+      if (this.checkPreconditions(tellerEntity.getOfficeIdentifier(), TellerMapper.map(tellerEntity))) {
+
+        if (tellerManagementCommand.getAmount() != null && tellerManagementCommand.getAmount() > 0.00D) {
+          this.accountingService.postJournalEntry(this.createJournalEntry(tellerEntity, tellerManagementCommand));
+        }
+        tellerEntity.setAssignedEmployeeIdentifier(null);
+        tellerEntity.setState(Teller.State.CLOSED.name());
+        tellerEntity.setLastModifiedBy(UserContextHolder.checkedGetUser());
+        tellerEntity.setLastModifiedOn(LocalDateTime.now(Clock.systemUTC()));
+
+        this.tellerRepository.save(tellerEntity);
+        return tellerCode;
+      } else {
+        throw new IllegalStateException("Preconditions not met, see log file for further information.");
+      }
+    } else {
+      throw new IllegalStateException("Teller " + tellerCode + " not found.");
+    }
+  }
+
+  private boolean checkPreconditions(final String officeIdentifier, final Teller teller) {
+    boolean pass = true;
+
+    if (!this.organizationService.officeExists(officeIdentifier)) {
+      this.logger.warn("Office {} not found.", officeIdentifier);
+      pass = false;
+    }
+
+    if (!this.accountingService.accountExists(teller.getTellerAccountIdentifier())) {
+      this.logger.warn("Teller account {} not found.", teller.getTellerAccountIdentifier());
+      pass = false;
+    }
+
+    if (!this.accountingService.accountExists(teller.getVaultAccountIdentifier())) {
+      this.logger.warn("Vault account {} not found.", teller.getVaultAccountIdentifier());
+      pass = false;
+    }
+
+    return pass;
+  }
+
+  private void encryptPassword(final Teller teller, final TellerEntity tellerEntity) {
+    final byte[] salt = this.saltGenerator.createRandomSalt();
+    final byte[] newPassword = this.hashGenerator.hash(teller.getPassword(), salt, ServiceConstants.ITERATION_COUNT,
+        ServiceConstants.LENGTH);
+    tellerEntity.setSalt(Base64Utils.encodeToString(salt));
+    tellerEntity.setPassword(Base64Utils.encodeToString(newPassword));
+  }
+
+  private JournalEntry createJournalEntry(final TellerEntity tellerEntity, final TellerManagementCommand tellerManagementCommand) {
+
+    if (tellerManagementCommand.getAmount() > tellerEntity.getCashdrawLimit()) {
+      this.logger.warn("Adjustment {} exceeds cashdraw limit {}.", tellerManagementCommand.getAmount(),
+          tellerEntity.getCashdrawLimit());
+      throw new IllegalArgumentException("Adjustment exceeds cashdraw limit.");
+    }
+
+    final JournalEntry journalEntry = new JournalEntry();
+    journalEntry.setTransactionIdentifier(RandomStringUtils.randomNumeric(32));
+    journalEntry.setTransactionDate(DateConverter.toIsoString(LocalDateTime.now(Clock.systemUTC())));
+    journalEntry.setClerk(UserContextHolder.checkedGetUser());
+    journalEntry.setMessage("Teller adjustment.");
+
+    final TellerManagementCommand.Adjustment adjustment =
+        TellerManagementCommand.Adjustment.valueOf(tellerManagementCommand.getAdjustment());
+
+    final Debtor debtor = new Debtor();
+    final Creditor creditor = new Creditor();
+    switch (adjustment) {
+      case DEBIT:
+        journalEntry.setTransactionType("DAJT");
+
+        debtor.setAccountNumber(tellerEntity.getTellerAccountIdentifier());
+        debtor.setAmount(tellerManagementCommand.getAmount().toString());
+        journalEntry.setDebtors(Sets.newHashSet(debtor));
+
+        creditor.setAccountNumber(tellerEntity.getVaultAccountIdentifier());
+        creditor.setAmount(tellerManagementCommand.getAmount().toString());
+        journalEntry.setCreditors(Sets.newHashSet(creditor));
+
+        break;
+      case CREDIT:
+        journalEntry.setTransactionType("CAJT");
+
+        debtor.setAccountNumber(tellerEntity.getVaultAccountIdentifier());
+        debtor.setAmount(tellerManagementCommand.getAmount().toString());
+        journalEntry.setDebtors(Sets.newHashSet(debtor));
+
+        creditor.setAccountNumber(tellerEntity.getTellerAccountIdentifier());
+        creditor.setAmount(tellerManagementCommand.getAmount().toString());
+        journalEntry.setCreditors(Sets.newHashSet(creditor));
+
+        break;
+      default:
+        this.logger.warn("Unsupported adjustment type {}.", tellerManagementCommand.getAdjustment());
+    }
+
+    return journalEntry;
+  }
+}
+
diff --git a/service/src/main/java/io/mifos/teller/service/internal/mapper/TellerEntryMapper.java b/service/src/main/java/io/mifos/teller/service/internal/mapper/TellerEntryMapper.java
new file mode 100644
index 0000000..eef8674
--- /dev/null
+++ b/service/src/main/java/io/mifos/teller/service/internal/mapper/TellerEntryMapper.java
@@ -0,0 +1,36 @@
+/*
+ * 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.
+ */
+package io.mifos.teller.service.internal.mapper;
+
+import io.mifos.accounting.api.v1.domain.AccountEntry;
+import io.mifos.teller.api.v1.domain.TellerEntry;
+
+public class TellerEntryMapper {
+
+  private TellerEntryMapper() {
+    super();
+  }
+
+  public static TellerEntry map(final AccountEntry accountEntry) {
+    final TellerEntry tellerEntry = new TellerEntry();
+    tellerEntry.setType(accountEntry.getType());
+    tellerEntry.setTransactionDate(accountEntry.getTransactionDate());
+    tellerEntry.setMessage(accountEntry.getMessage());
+    tellerEntry.setAmount(accountEntry.getAmount());
+
+    return tellerEntry;
+  }
+}
diff --git a/service/src/main/java/io/mifos/teller/service/internal/mapper/TellerMapper.java b/service/src/main/java/io/mifos/teller/service/internal/mapper/TellerMapper.java
new file mode 100644
index 0000000..bfb83af
--- /dev/null
+++ b/service/src/main/java/io/mifos/teller/service/internal/mapper/TellerMapper.java
@@ -0,0 +1,71 @@
+/*
+ * 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.
+ */
+package io.mifos.teller.service.internal.mapper;
+
+import io.mifos.core.lang.DateConverter;
+import io.mifos.teller.api.v1.domain.Teller;
+import io.mifos.teller.service.internal.repository.TellerEntity;
+
+public class TellerMapper {
+
+  private TellerMapper() {
+    super();
+  }
+
+  public static Teller map(final TellerEntity tellerEntity) {
+    final Teller teller = new Teller();
+    teller.setCode(tellerEntity.getIdentifier());
+    teller.setPassword(tellerEntity.getPassword());
+    teller.setTellerAccountIdentifier(tellerEntity.getTellerAccountIdentifier());
+    teller.setVaultAccountIdentifier(tellerEntity.getVaultAccountIdentifier());
+    teller.setCashdrawLimit(tellerEntity.getCashdrawLimit());
+    teller.setAssignedEmployee(tellerEntity.getAssignedEmployeeIdentifier());
+    teller.setState(tellerEntity.getState());
+    if (tellerEntity.getCreatedBy() != null) {
+      teller.setCreatedBy(tellerEntity.getCreatedBy());
+      teller.setCreatedOn(DateConverter.toIsoString(tellerEntity.getCreatedOn()));
+    }
+    if (tellerEntity.getLastModifiedBy() != null) {
+      teller.setLastModifiedBy(tellerEntity.getLastModifiedBy());
+      teller.setLastModifiedOn(DateConverter.toIsoString(tellerEntity.getLastModifiedOn()));
+    }
+
+    return teller;
+  }
+
+  public static TellerEntity map(final String officeIdentifier, final Teller teller) {
+    final TellerEntity tellerEntity = new TellerEntity();
+    tellerEntity.setIdentifier(teller.getCode());
+    tellerEntity.setPassword(teller.getPassword());
+    tellerEntity.setOfficeIdentifier(officeIdentifier);
+    tellerEntity.setTellerAccountIdentifier(teller.getTellerAccountIdentifier());
+    tellerEntity.setVaultAccountIdentifier(teller.getVaultAccountIdentifier());
+    tellerEntity.setCashdrawLimit(teller.getCashdrawLimit());
+    tellerEntity.setAssignedEmployeeIdentifier(teller.getAssignedEmployee());
+    if (teller.getState() != null) {
+      tellerEntity.setState(teller.getState());
+    }
+    if (teller.getCreatedBy() != null) {
+      tellerEntity.setCreatedBy(teller.getCreatedBy());
+      tellerEntity.setCreatedOn(DateConverter.fromIsoString(teller.getCreatedOn()));
+    }
+    if (teller.getLastModifiedBy() != null) {
+      tellerEntity.setLastModifiedBy(teller.getLastModifiedBy());
+      tellerEntity.setLastModifiedOn(DateConverter.fromIsoString(teller.getLastModifiedOn()));
+    }
+    return tellerEntity;
+  }
+}
diff --git a/service/src/main/java/io/mifos/teller/service/internal/repository/TellerEntity.java b/service/src/main/java/io/mifos/teller/service/internal/repository/TellerEntity.java
new file mode 100644
index 0000000..00abbe2
--- /dev/null
+++ b/service/src/main/java/io/mifos/teller/service/internal/repository/TellerEntity.java
@@ -0,0 +1,181 @@
+/*
+ * 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.
+ */
+package io.mifos.teller.service.internal.repository;
+
+import io.mifos.core.mariadb.util.LocalDateTimeConverter;
+
+import javax.persistence.Column;
+import javax.persistence.Convert;
+import javax.persistence.Entity;
+import javax.persistence.GeneratedValue;
+import javax.persistence.GenerationType;
+import javax.persistence.Id;
+import javax.persistence.Table;
+import java.time.LocalDateTime;
+
+@Entity
+@Table(name = "tajet_teller")
+public class TellerEntity {
+
+  @Id
+  @GeneratedValue(strategy = GenerationType.IDENTITY)
+  @Column(name = "id", nullable = false)
+  private Long id;
+  @Column(name = "identifier", nullable = false, length = 32)
+  private String identifier;
+  @Column(name = "a_password", nullable = false, length = 4096)
+  private String password;
+  @Column(name = "a_salt", nullable = false, length = 4096)
+  private String salt;
+  @Column(name = "office_identifier", nullable = false, length = 32)
+  private String officeIdentifier;
+  @Column(name = "cashdraw_limit", nullable = false)
+  private Double cashdrawLimit;
+  @Column(name = "teller_account_identifier", nullable = false, length = 32)
+  private String tellerAccountIdentifier;
+  @Column(name = "vault_account_identifier", nullable = false, length = 32)
+  private String vaultAccountIdentifier;
+  @Column(name = "assigned_employee_identifier", nullable = true, length = 32)
+  private String assignedEmployeeIdentifier;
+  @Column(name = "a_state", nullable = false, length = 256)
+  private String state;
+  @Column(name = "created_by", nullable = false, length = 32)
+  private String createdBy;
+  @Column(name = "created_on", nullable = false)
+  @Convert(converter = LocalDateTimeConverter.class)
+  private LocalDateTime createdOn;
+  @Column(name = "last_modified_by", nullable = true, length = 32)
+  private String lastModifiedBy;
+  @Column(name = "last_modified_on", nullable = true)
+  @Convert(converter = LocalDateTimeConverter.class)
+  private LocalDateTime lastModifiedOn;
+
+  public TellerEntity() {
+    super();
+  }
+
+  public Long getId() {
+    return this.id;
+  }
+
+  public void setId(final Long id) {
+    this.id = id;
+  }
+
+  public String getIdentifier() {
+    return this.identifier;
+  }
+
+  public void setIdentifier(final String identifier) {
+    this.identifier = identifier;
+  }
+
+  public String getPassword() {
+    return this.password;
+  }
+
+  public void setPassword(final String password) {
+    this.password = password;
+  }
+
+  public String getSalt() {
+    return this.salt;
+  }
+
+  public void setSalt(final String salt) {
+    this.salt = salt;
+  }
+
+  public String getOfficeIdentifier() {
+    return this.officeIdentifier;
+  }
+
+  public void setOfficeIdentifier(final String officeIdentifier) {
+    this.officeIdentifier = officeIdentifier;
+  }
+
+  public Double getCashdrawLimit() {
+    return this.cashdrawLimit;
+  }
+
+  public void setCashdrawLimit(final Double cashdrawLimit) {
+    this.cashdrawLimit = cashdrawLimit;
+  }
+
+  public String getTellerAccountIdentifier() {
+    return this.tellerAccountIdentifier;
+  }
+
+  public void setTellerAccountIdentifier(final String tellerAccountIdentifier) {
+    this.tellerAccountIdentifier = tellerAccountIdentifier;
+  }
+
+  public String getVaultAccountIdentifier() {
+    return this.vaultAccountIdentifier;
+  }
+
+  public void setVaultAccountIdentifier(final String vaultAccountIdentifier) {
+    this.vaultAccountIdentifier = vaultAccountIdentifier;
+  }
+
+  public String getAssignedEmployeeIdentifier() {
+    return this.assignedEmployeeIdentifier;
+  }
+
+  public void setAssignedEmployeeIdentifier(final String assignedEmployeeIdentifier) {
+    this.assignedEmployeeIdentifier = assignedEmployeeIdentifier;
+  }
+
+  public String getState() {
+    return this.state;
+  }
+
+  public void setState(final String state) {
+    this.state = state;
+  }
+
+  public String getCreatedBy() {
+    return this.createdBy;
+  }
+
+  public void setCreatedBy(final String createdBy) {
+    this.createdBy = createdBy;
+  }
+
+  public LocalDateTime getCreatedOn() {
+    return this.createdOn;
+  }
+
+  public void setCreatedOn(final LocalDateTime createdOn) {
+    this.createdOn = createdOn;
+  }
+
+  public String getLastModifiedBy() {
+    return this.lastModifiedBy;
+  }
+
+  public void setLastModifiedBy(final String lastModifiedBy) {
+    this.lastModifiedBy = lastModifiedBy;
+  }
+
+  public LocalDateTime getLastModifiedOn() {
+    return this.lastModifiedOn;
+  }
+
+  public void setLastModifiedOn(final LocalDateTime lastModifiedOn) {
+    this.lastModifiedOn = lastModifiedOn;
+  }
+}
diff --git a/api/src/main/java/io/mifos/teller/EventConstants.java b/service/src/main/java/io/mifos/teller/service/internal/repository/TellerRepository.java
similarity index 57%
rename from api/src/main/java/io/mifos/teller/EventConstants.java
rename to service/src/main/java/io/mifos/teller/service/internal/repository/TellerRepository.java
index f2a0d0b..530cb19 100644
--- a/api/src/main/java/io/mifos/teller/EventConstants.java
+++ b/service/src/main/java/io/mifos/teller/service/internal/repository/TellerRepository.java
@@ -13,18 +13,18 @@
  * See the License for the specific language governing permissions and
  * limitations under the License.
  */
-package io.mifos.teller;
+package io.mifos.teller.service.internal.repository;
 
-@SuppressWarnings("unused")
-public interface EventConstants {
+import org.springframework.data.jpa.repository.JpaRepository;
+import org.springframework.stereotype.Repository;
 
-  String DESTINATION = "teller-v1";
+import java.util.List;
+import java.util.Optional;
 
-  String SELECTOR_NAME = "operation";
+@Repository
+public interface TellerRepository extends JpaRepository<TellerEntity, Long> {
 
-  String INITIALIZE = "initialize";
-  String SELECTOR_INITIALIZE = SELECTOR_NAME + " = '" + INITIALIZE + "'";
+  Optional<TellerEntity> findByIdentifier(final String identifier);
 
-  String POST_TELLER = "post-teller";
-  String SELECTOR_POST_TELLER = SELECTOR_NAME + " = '" + POST_TELLER + "'";
+  List<TellerEntity> findByOfficeIdentifier(final String officeIdentifier);
 }
diff --git a/service/src/main/java/io/mifos/teller/service/internal/service/TellerManagementService.java b/service/src/main/java/io/mifos/teller/service/internal/service/TellerManagementService.java
new file mode 100644
index 0000000..e2b4ac3
--- /dev/null
+++ b/service/src/main/java/io/mifos/teller/service/internal/service/TellerManagementService.java
@@ -0,0 +1,106 @@
+/*
+ * 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.
+ */
+package io.mifos.teller.service.internal.service;
+
+import io.mifos.accounting.api.v1.domain.AccountEntryPage;
+import io.mifos.teller.ServiceConstants;
+import io.mifos.teller.api.v1.domain.Teller;
+import io.mifos.teller.api.v1.domain.TellerBalanceSheet;
+import io.mifos.teller.api.v1.domain.TellerEntry;
+import io.mifos.teller.service.internal.mapper.TellerEntryMapper;
+import io.mifos.teller.service.internal.mapper.TellerMapper;
+import io.mifos.teller.service.internal.repository.TellerEntity;
+import io.mifos.teller.service.internal.repository.TellerRepository;
+import io.mifos.teller.service.internal.service.helper.AccountingService;
+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.time.LocalDateTime;
+import java.time.format.DateTimeFormatter;
+import java.util.ArrayList;
+import java.util.List;
+import java.util.Optional;
+import java.util.stream.Collectors;
+
+@Service
+public class TellerManagementService {
+
+  private final Logger logger;
+  private final TellerRepository tellerRepository;
+  private final AccountingService accountingService;
+
+  @Autowired
+  public TellerManagementService(@Qualifier(ServiceConstants.LOGGER_NAME) final Logger logger,
+                                 final TellerRepository tellerRepository,
+                                 final AccountingService accountingService) {
+    super();
+    this.logger = logger;
+    this.tellerRepository = tellerRepository;
+    this.accountingService = accountingService;
+  }
+
+  public Optional<Teller> findByIdentifier(final String code) {
+    return this.tellerRepository.findByIdentifier(code).map(TellerMapper::map);
+  }
+
+  public List<Teller> findByOfficeIdentifier(final String officeIdentifier) {
+    return this.tellerRepository.findByOfficeIdentifier(officeIdentifier)
+        .stream()
+        .map(TellerMapper::map)
+        .collect(Collectors.toList());
+  }
+
+  public TellerBalanceSheet getBalance(final String tellerCode) {
+    final TellerBalanceSheet tellerBalanceSheet = new TellerBalanceSheet();
+
+    final Optional<TellerEntity> optionalTellerEntity = this.tellerRepository.findByIdentifier(tellerCode);
+    optionalTellerEntity.ifPresent(tellerEntity -> {
+
+      final String accountIdentifier = tellerEntity.getTellerAccountIdentifier();
+      final LocalDateTime lastModifiedOn = tellerEntity.getLastModifiedOn();
+      final LocalDateTime startDate = lastModifiedOn.withHour(0).withMinute(0).withSecond(0).withNano(0);
+      final LocalDateTime endDate = lastModifiedOn.withHour(23).withMinute(59).withSecond(59).withNano(999);
+      final String dateRange =
+          startDate.format(DateTimeFormatter.BASIC_ISO_DATE) + ".." + endDate.format(DateTimeFormatter.BASIC_ISO_DATE);
+
+      final List<TellerEntry> tellerEntries = this.fetchTellerEntries(accountIdentifier, dateRange, 0);
+
+      tellerBalanceSheet.setDay(startDate.format(DateTimeFormatter.BASIC_ISO_DATE));
+      tellerBalanceSheet.setBalance(tellerEntries.stream().mapToDouble(TellerEntry::getAmount).sum());
+      tellerBalanceSheet.setEntries(tellerEntries);
+    });
+    return tellerBalanceSheet;
+  }
+
+  private List<TellerEntry> fetchTellerEntries(final String accountIdentifier, final String dateRange, final Integer pageIndex) {
+    final ArrayList<TellerEntry> tellerEntries = new ArrayList<>();
+
+    final AccountEntryPage accountEntryPage =
+        this.accountingService.fetchAccountEntries(accountIdentifier, dateRange, pageIndex, 250);
+    tellerEntries.addAll(
+        accountEntryPage.getAccountEntries().stream().map(TellerEntryMapper::map).collect(Collectors.toList())
+    );
+
+    final Integer nextPage = pageIndex + 1;
+    if (nextPage < accountEntryPage.getTotalPages()) {
+      tellerEntries.addAll(this.fetchTellerEntries(accountIdentifier, dateRange, nextPage));
+    }
+
+    return tellerEntries;
+  }
+}
diff --git a/service/src/main/java/io/mifos/teller/ServiceConstants.java b/service/src/main/java/io/mifos/teller/service/internal/service/TellerOperationService.java
similarity index 80%
copy from service/src/main/java/io/mifos/teller/ServiceConstants.java
copy to service/src/main/java/io/mifos/teller/service/internal/service/TellerOperationService.java
index 98de3be..220abb6 100644
--- a/service/src/main/java/io/mifos/teller/ServiceConstants.java
+++ b/service/src/main/java/io/mifos/teller/service/internal/service/TellerOperationService.java
@@ -13,8 +13,10 @@
  * See the License for the specific language governing permissions and
  * limitations under the License.
  */
-package io.mifos.teller;
+package io.mifos.teller.service.internal.service;
 
-public interface ServiceConstants {
-  String LOGGER_NAME = "teller-logger";
+import org.springframework.stereotype.Service;
+
+@Service
+public class TellerOperationService {
 }
diff --git a/service/src/main/java/io/mifos/teller/service/internal/service/helper/AccountingService.java b/service/src/main/java/io/mifos/teller/service/internal/service/helper/AccountingService.java
new file mode 100644
index 0000000..d64decb
--- /dev/null
+++ b/service/src/main/java/io/mifos/teller/service/internal/service/helper/AccountingService.java
@@ -0,0 +1,62 @@
+/*
+ * 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.
+ */
+package io.mifos.teller.service.internal.service.helper;
+
+import io.mifos.accounting.api.v1.client.AccountNotFoundException;
+import io.mifos.accounting.api.v1.client.LedgerManager;
+import io.mifos.accounting.api.v1.domain.AccountEntryPage;
+import io.mifos.accounting.api.v1.domain.JournalEntry;
+import io.mifos.teller.ServiceConstants;
+import org.slf4j.Logger;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.beans.factory.annotation.Qualifier;
+import org.springframework.data.domain.Sort;
+import org.springframework.stereotype.Service;
+
+@Service
+public class AccountingService {
+
+  private final Logger logger;
+  private final LedgerManager ledgerManager;
+
+  @Autowired
+  public AccountingService(@Qualifier(ServiceConstants.LOGGER_NAME) final Logger logger,
+                           final LedgerManager ledgerManager) {
+    super();
+    this.logger = logger;
+    this.ledgerManager = ledgerManager;
+  }
+
+  public boolean accountExists(final String accountIdentifier) {
+    try {
+      this.ledgerManager.findAccount(accountIdentifier);
+      return true;
+    } catch (final AccountNotFoundException anfex) {
+      this.logger.warn("Account {} not found.", accountIdentifier);
+      return false;
+    }
+  }
+
+  public AccountEntryPage fetchAccountEntries(final String accountIdentifier, final String dateRange, final Integer pageIndex,
+                                              final Integer pageSize) {
+    return this.ledgerManager.fetchAccountEntries(accountIdentifier, dateRange, pageIndex, pageSize, "identifier",
+        Sort.Direction.DESC.name());
+  }
+
+  public void postJournalEntry(final JournalEntry journalEntry) {
+    this.ledgerManager.createJournalEntry(journalEntry);
+  }
+}
diff --git a/service/src/main/java/io/mifos/teller/service/internal/service/helper/DepositAccountManagementService.java b/service/src/main/java/io/mifos/teller/service/internal/service/helper/DepositAccountManagementService.java
new file mode 100644
index 0000000..4d0a458
--- /dev/null
+++ b/service/src/main/java/io/mifos/teller/service/internal/service/helper/DepositAccountManagementService.java
@@ -0,0 +1,38 @@
+/*
+ * 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.
+ */
+package io.mifos.teller.service.internal.service.helper;
+
+import io.mifos.deposit.api.v1.client.DepositAccountManager;
+import io.mifos.teller.ServiceConstants;
+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 DepositAccountManagementService {
+
+  private final Logger logger;
+  private final DepositAccountManager depositAccountManager;
+
+  @Autowired
+  public DepositAccountManagementService(@Qualifier(ServiceConstants.LOGGER_NAME) final Logger logger,
+                                         final DepositAccountManager depositAccountManager) {
+    super();
+    this.logger = logger;
+    this.depositAccountManager = depositAccountManager;
+  }
+}
diff --git a/service/src/main/java/io/mifos/teller/service/internal/service/helper/OrganizationService.java b/service/src/main/java/io/mifos/teller/service/internal/service/helper/OrganizationService.java
new file mode 100644
index 0000000..cb68e22
--- /dev/null
+++ b/service/src/main/java/io/mifos/teller/service/internal/service/helper/OrganizationService.java
@@ -0,0 +1,59 @@
+/*
+ * 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.
+ */
+package io.mifos.teller.service.internal.service.helper;
+
+import io.mifos.office.api.v1.client.NotFoundException;
+import io.mifos.office.api.v1.client.OrganizationManager;
+import io.mifos.teller.ServiceConstants;
+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 OrganizationService {
+
+  private final Logger logger;
+  private final OrganizationManager organizationManager;
+
+  @Autowired
+  public OrganizationService(@Qualifier(ServiceConstants.LOGGER_NAME) final Logger logger,
+                             final OrganizationManager organizationManager) {
+    super();
+    this.logger = logger;
+    this.organizationManager = organizationManager;
+  }
+
+  public boolean officeExists(final String officeIdentifier) {
+    try {
+      this.organizationManager.findOfficeByIdentifier(officeIdentifier);
+      return true;
+    } catch (final NotFoundException nfex) {
+      this.logger.warn("Office {} not found.", officeIdentifier);
+      return false;
+    }
+  }
+
+  public boolean employeeExists(final String employeeIdentifier) {
+    try {
+      this.organizationManager.findEmployee(employeeIdentifier);
+      return true;
+    } catch (final NotFoundException nfex) {
+      this.logger.warn("Employee {} not found.", employeeIdentifier);
+      return false;
+    }
+  }
+}
diff --git a/service/src/main/java/io/mifos/teller/service/internal/service/helper/PortfolioService.java b/service/src/main/java/io/mifos/teller/service/internal/service/helper/PortfolioService.java
new file mode 100644
index 0000000..6076c58
--- /dev/null
+++ b/service/src/main/java/io/mifos/teller/service/internal/service/helper/PortfolioService.java
@@ -0,0 +1,40 @@
+/*
+ * 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.
+ */
+package io.mifos.teller.service.internal.service.helper;
+
+import io.mifos.portfolio.api.v1.client.PortfolioManager;
+import io.mifos.teller.ServiceConstants;
+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 PortfolioService {
+
+  private final Logger logger;
+  private final PortfolioManager portfolioManager;
+
+  @Autowired
+  public PortfolioService(@Qualifier(ServiceConstants.LOGGER_NAME) final Logger logger,
+                          final PortfolioManager portfolioManager) {
+    super();
+    this.logger = logger;
+    this.portfolioManager = portfolioManager;
+  }
+
+
+}
diff --git a/service/src/main/java/io/mifos/teller/service/rest/TellerManagementRestController.java b/service/src/main/java/io/mifos/teller/service/rest/TellerManagementRestController.java
new file mode 100644
index 0000000..feef72a
--- /dev/null
+++ b/service/src/main/java/io/mifos/teller/service/rest/TellerManagementRestController.java
@@ -0,0 +1,236 @@
+/*
+ * 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.
+ */
+package io.mifos.teller.service.rest;
+
+import io.mifos.anubis.annotation.AcceptedTokenType;
+import io.mifos.anubis.annotation.Permittable;
+import io.mifos.core.command.gateway.CommandGateway;
+import io.mifos.core.lang.ServiceException;
+import io.mifos.teller.ServiceConstants;
+import io.mifos.teller.api.v1.PermittableGroupIds;
+import io.mifos.teller.api.v1.domain.Teller;
+import io.mifos.teller.api.v1.domain.TellerBalanceSheet;
+import io.mifos.teller.api.v1.domain.TellerManagementCommand;
+import io.mifos.teller.service.internal.command.ChangeTellerCommand;
+import io.mifos.teller.service.internal.command.CloseTellerCommand;
+import io.mifos.teller.service.internal.command.CreateTellerCommand;
+import io.mifos.teller.service.internal.command.OpenTellerCommand;
+import io.mifos.teller.service.internal.service.TellerManagementService;
+import io.mifos.teller.service.internal.service.helper.AccountingService;
+import io.mifos.teller.service.internal.service.helper.OrganizationService;
+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.RequestBody;
+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;
+
+import javax.validation.Valid;
+import java.util.List;
+import java.util.Optional;
+
+@RestController
+@RequestMapping("/offices/{officeIdentifier}/teller")
+public class TellerManagementRestController {
+
+  private final Logger logger;
+  private final CommandGateway commandGateway;
+  private final TellerManagementService tellerManagementService;
+  private final OrganizationService organizationService;
+  private final AccountingService accountingService;
+
+  @Autowired
+  public TellerManagementRestController(@Qualifier(ServiceConstants.LOGGER_NAME) final Logger logger,
+                                        final CommandGateway commandGateway,
+                                        final TellerManagementService tellerManagementService,
+                                        final OrganizationService organizationService,
+                                        final AccountingService accountingService) {
+    super();
+    this.logger = logger;
+    this.commandGateway = commandGateway;
+    this.tellerManagementService = tellerManagementService;
+    this.organizationService = organizationService;
+    this.accountingService = accountingService;
+  }
+
+  @Permittable(value = AcceptedTokenType.TENANT, groupId = PermittableGroupIds.TELLER_MANAGEMENT)
+  @RequestMapping(
+      value = "",
+      method = RequestMethod.POST,
+      consumes = MediaType.APPLICATION_JSON_VALUE,
+      produces = MediaType.APPLICATION_JSON_VALUE
+  )
+  @ResponseBody
+  ResponseEntity<Void> create(@PathVariable("officeIdentifier") final String officeIdentifier,
+                              @RequestBody @Valid final Teller teller) {
+    if (this.tellerManagementService.findByIdentifier(teller.getCode()).isPresent()) {
+      throw ServiceException.conflict("Teller {0} already exists.", teller.getCode());
+    }
+
+    this.verifyOffice(officeIdentifier);
+    this.verifyAccount(teller.getTellerAccountIdentifier());
+    this.verifyAccount(teller.getVaultAccountIdentifier());
+
+    this.commandGateway.process(new CreateTellerCommand(officeIdentifier, teller));
+
+    return ResponseEntity.accepted().build();
+  }
+
+  @Permittable(value = AcceptedTokenType.TENANT, groupId = PermittableGroupIds.TELLER_MANAGEMENT)
+  @RequestMapping(
+      value = "/{tellerCode}",
+      method = RequestMethod.GET,
+      consumes = MediaType.ALL_VALUE,
+      produces = MediaType.APPLICATION_JSON_VALUE
+  )
+  @ResponseBody
+  ResponseEntity<Teller> find(@PathVariable("officeIdentifier") final String officeIdentifier,
+                              @PathVariable("tellerCode") final String tellerCode) {
+    this.verifyOffice(officeIdentifier);
+
+    return ResponseEntity.ok(
+        this.tellerManagementService.findByIdentifier(tellerCode)
+            .orElseThrow(() -> ServiceException.notFound("Teller {0} not found.", tellerCode))
+    );
+  }
+
+  @Permittable(value = AcceptedTokenType.TENANT, groupId = PermittableGroupIds.TELLER_MANAGEMENT)
+  @RequestMapping(
+      value = "",
+      method = RequestMethod.GET,
+      consumes = MediaType.ALL_VALUE,
+      produces = MediaType.APPLICATION_JSON_VALUE
+  )
+  @ResponseBody
+  ResponseEntity<List<Teller>> fetch(@PathVariable("officeIdentifier") final String officeIdentifier) {
+    this.verifyOffice(officeIdentifier);
+
+    return ResponseEntity.ok(
+        this.tellerManagementService.findByOfficeIdentifier(officeIdentifier)
+    );
+  }
+
+  @Permittable(value = AcceptedTokenType.TENANT, groupId = PermittableGroupIds.TELLER_MANAGEMENT)
+  @RequestMapping(
+      value = "/{tellerCode}",
+      method = RequestMethod.PUT,
+      consumes = MediaType.APPLICATION_JSON_VALUE,
+      produces = MediaType.APPLICATION_JSON_VALUE
+  )
+  @ResponseBody
+  ResponseEntity<Void> change(@PathVariable("officeIdentifier") final String officeIdentifier,
+                              @PathVariable("tellerCode") final String tellerCode,
+                              @RequestBody @Valid final Teller teller) {
+    if (!tellerCode.equals(teller.getCode())) {
+      throw ServiceException.badRequest("Teller code {0} must much given teller.", tellerCode);
+    }
+
+    this.verifyTeller(tellerCode);
+    this.verifyOffice(officeIdentifier);
+    this.verifyAccount(teller.getTellerAccountIdentifier());
+    this.verifyAccount(teller.getVaultAccountIdentifier());
+
+    this.commandGateway.process(new ChangeTellerCommand(officeIdentifier, teller));
+
+    return ResponseEntity.accepted().build();
+  }
+
+  @Permittable(value = AcceptedTokenType.TENANT, groupId = PermittableGroupIds.TELLER_MANAGEMENT)
+  @RequestMapping(
+      value = "/{tellerCode}/commands",
+      method = RequestMethod.POST,
+      consumes = MediaType.APPLICATION_JSON_VALUE,
+      produces = MediaType.APPLICATION_JSON_VALUE
+  )
+  @ResponseBody
+  ResponseEntity<Void> post(@PathVariable("officeIdentifier") final String officeIdentifier,
+                            @PathVariable("tellerCode") final String tellerCode,
+                            @RequestBody @Valid final TellerManagementCommand tellerManagementCommand) {
+    final Teller teller = this.verifyTeller(tellerCode);
+
+    if (tellerManagementCommand.getAmount() != null && tellerManagementCommand.getAmount() > teller.getCashdrawLimit()) {
+      throw ServiceException.badRequest("Adjustment exceeds cashdraw limit.");
+    }
+
+    final TellerManagementCommand.Action action = TellerManagementCommand.Action.valueOf(tellerManagementCommand.getAction());
+    switch (action) {
+      case OPEN:
+        if (!teller.getState().equals(Teller.State.CLOSED.name())) {
+          throw ServiceException.badRequest("Teller {0} is already active.", tellerCode);
+        }
+        this.verifyEmployee(tellerManagementCommand.getAssignedEmployeeIdentifier());
+        this.commandGateway.process(new OpenTellerCommand(tellerCode, tellerManagementCommand));
+        break;
+      case CLOSE:
+        if (teller.getState().equals(Teller.State.CLOSED.name())) {
+          throw ServiceException.badRequest("Teller {0} is already closed.", tellerCode);
+        }
+        this.commandGateway.process(new CloseTellerCommand(tellerCode, tellerManagementCommand));
+        break;
+      default:
+        throw ServiceException.badRequest("Unsupported teller command {0}.", action.name());
+    }
+
+    return ResponseEntity.accepted().build();
+  }
+
+  @Permittable(value = AcceptedTokenType.TENANT, groupId = PermittableGroupIds.TELLER_MANAGEMENT)
+  @RequestMapping(
+      value = "/{tellerCode}/balance",
+      method = RequestMethod.GET,
+      consumes = MediaType.ALL_VALUE,
+      produces = MediaType.APPLICATION_JSON_VALUE
+  )
+  @ResponseBody
+  ResponseEntity<TellerBalanceSheet> getBalance(@PathVariable("officeIdentifier") final String officeIdentifier,
+                                                @PathVariable("tellerCode") final String tellerCode) {
+    this.verifyOffice(officeIdentifier);
+    this.verifyTeller(tellerCode);
+
+    return ResponseEntity.ok(this.tellerManagementService.getBalance(tellerCode));
+  }
+
+  private void verifyAccount(final String accountIdentifier) {
+    if (!this.accountingService.accountExists(accountIdentifier)) {
+      throw ServiceException.badRequest("Account {0} not found.", accountIdentifier);
+    }
+  }
+
+  private void verifyEmployee(final String employeeIdentifier) {
+    if (!this.organizationService.employeeExists(employeeIdentifier)) {
+      throw ServiceException.badRequest("Employee {0} not found.", employeeIdentifier);
+    }
+  }
+
+  private void verifyOffice(final String officeIdentifier) {
+    if (!this.organizationService.officeExists(officeIdentifier)) {
+      throw ServiceException.badRequest("Office {0} not found.", officeIdentifier);
+    }
+  }
+
+  private Teller verifyTeller(final String tellerCode) {
+    final Optional<Teller> optionalTeller = this.tellerManagementService.findByIdentifier(tellerCode);
+    if (!optionalTeller.isPresent()) {
+      throw ServiceException.notFound("Teller {0} not found.", tellerCode);
+    }
+    return optionalTeller.get();
+  }
+}
diff --git a/service/src/main/java/io/mifos/teller/service/rest/TellerOperationRestController.java b/service/src/main/java/io/mifos/teller/service/rest/TellerOperationRestController.java
new file mode 100644
index 0000000..303428d
--- /dev/null
+++ b/service/src/main/java/io/mifos/teller/service/rest/TellerOperationRestController.java
@@ -0,0 +1,143 @@
+/*
+ * 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.
+ */
+package io.mifos.teller.service.rest;
+
+import io.mifos.accounting.api.v1.client.LedgerManager;
+import io.mifos.anubis.annotation.AcceptedTokenType;
+import io.mifos.anubis.annotation.Permittable;
+import io.mifos.core.command.gateway.CommandGateway;
+import io.mifos.core.lang.ServiceException;
+import io.mifos.deposit.api.v1.client.DepositAccountManager;
+import io.mifos.portfolio.api.v1.client.PortfolioManager;
+import io.mifos.teller.ServiceConstants;
+import io.mifos.teller.api.v1.PermittableGroupIds;
+import io.mifos.teller.api.v1.domain.TellerAuthentication;
+import io.mifos.teller.api.v1.domain.TellerTransaction;
+import io.mifos.teller.api.v1.domain.TellerTransactionCosts;
+import io.mifos.teller.service.internal.service.TellerManagementService;
+import io.mifos.teller.service.internal.service.TellerOperationService;
+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.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.ResponseBody;
+import org.springframework.web.bind.annotation.RestController;
+
+import javax.validation.Valid;
+import java.util.Collections;
+import java.util.List;
+
+@RestController
+@RequestMapping("/teller/{tellerCode}")
+public class TellerOperationRestController {
+
+  private final Logger logger;
+  private final CommandGateway commandGateway;
+  private final TellerOperationService tellerOperationService;
+  private final TellerManagementService tellerManagementService;
+  private final LedgerManager ledgerManager;
+  private final DepositAccountManager depositAccountManager;
+  private final PortfolioManager portfolioManager;
+
+  @Autowired
+  public TellerOperationRestController(@Qualifier(ServiceConstants.LOGGER_NAME) final Logger logger,
+                                       final CommandGateway commandGateway,
+                                       final TellerOperationService tellerOperationService,
+                                       final TellerManagementService tellerManagementService,
+                                       final LedgerManager ledgerManager,
+                                       final DepositAccountManager depositAccountManager,
+                                       final PortfolioManager portfolioManager) {
+    this.logger = logger;
+    this.commandGateway = commandGateway;
+    this.tellerOperationService = tellerOperationService;
+    this.tellerManagementService = tellerManagementService;
+    this.ledgerManager = ledgerManager;
+    this.depositAccountManager = depositAccountManager;
+    this.portfolioManager = portfolioManager;
+  }
+
+  @Permittable(value = AcceptedTokenType.TENANT, groupId = PermittableGroupIds.TELLER_OPERATION)
+  @RequestMapping(
+      value = "/auth",
+      method = RequestMethod.POST,
+      consumes = MediaType.APPLICATION_JSON_VALUE,
+      produces = MediaType.APPLICATION_JSON_VALUE
+  )
+  @ResponseBody
+  ResponseEntity<Void> auth(@PathVariable("tellerCode") final String tellerCode,
+                            @RequestBody @Valid final TellerAuthentication tellerAuthentication) {
+    return ResponseEntity.accepted().build();
+  }
+
+  @Permittable(value = AcceptedTokenType.TENANT, groupId = PermittableGroupIds.TELLER_OPERATION)
+  @RequestMapping(
+      value = "",
+      method = RequestMethod.POST,
+      consumes = MediaType.APPLICATION_JSON_VALUE,
+      produces = MediaType.APPLICATION_JSON_VALUE
+  )
+  @ResponseBody
+  ResponseEntity<Void> post(@PathVariable("tellerCode") final String tellerCode,
+                            @RequestParam(value = "command", required = true) final String command) {
+    return ResponseEntity.accepted().build();
+  }
+
+  @Permittable(value = AcceptedTokenType.TENANT, groupId = PermittableGroupIds.TELLER_OPERATION)
+  @RequestMapping(
+      value = "/transactions",
+      method = RequestMethod.POST,
+      consumes = MediaType.APPLICATION_JSON_VALUE,
+      produces = MediaType.APPLICATION_JSON_VALUE
+  )
+  @ResponseBody
+  ResponseEntity<TellerTransactionCosts> post(@PathVariable("tellerCode") final String tellerCode,
+                                              @RequestBody @Valid final TellerTransaction tellerTransaction) {
+    throw ServiceException.notFound("Teller {0} not found.", tellerCode);
+  }
+
+  @Permittable(value = AcceptedTokenType.TENANT, groupId = PermittableGroupIds.TELLER_OPERATION)
+  @RequestMapping(
+      value = "/transactions/{identifier}",
+      method = RequestMethod.POST,
+      consumes = MediaType.APPLICATION_JSON_VALUE,
+      produces = MediaType.APPLICATION_JSON_VALUE
+  )
+  @ResponseBody
+  ResponseEntity<Void> confirm(@PathVariable("tellerCode") final String tellerCode,
+                               @PathVariable("identifier") final String tellerTransactionIdentifier,
+                               @RequestParam(value = "command", required = true) final String command) {
+    return ResponseEntity.accepted().build();
+  }
+
+  @Permittable(value = AcceptedTokenType.TENANT, groupId = PermittableGroupIds.TELLER_OPERATION)
+  @RequestMapping(
+      value = "/transactions",
+      method = RequestMethod.GET,
+      consumes = MediaType.ALL_VALUE,
+      produces = MediaType.APPLICATION_JSON_VALUE
+  )
+  @ResponseBody
+  ResponseEntity<List<TellerTransaction>> fetch(@PathVariable("tellerCode") final String tellerCode,
+                                                @RequestParam(value = "status", required = false) final String status) {
+    return ResponseEntity.ok(Collections.emptyList());
+  }
+}
diff --git a/service/src/main/java/io/mifos/teller/service/rest/TellerRestController.java b/service/src/main/java/io/mifos/teller/service/rest/TellerRestController.java
new file mode 100644
index 0000000..5518d93
--- /dev/null
+++ b/service/src/main/java/io/mifos/teller/service/rest/TellerRestController.java
@@ -0,0 +1,59 @@
+/*
+ * 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.
+ */
+package io.mifos.teller.service.rest;
+
+import io.mifos.anubis.annotation.AcceptedTokenType;
+import io.mifos.anubis.annotation.Permittable;
+import io.mifos.core.command.gateway.CommandGateway;
+import io.mifos.teller.ServiceConstants;
+import io.mifos.teller.service.internal.command.MigrationCommand;
+import org.slf4j.Logger;
+import org.springframework.beans.factory.annotation.Qualifier;
+import org.springframework.http.MediaType;
+import org.springframework.http.ResponseEntity;
+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("/")
+public class TellerRestController {
+
+  private final Logger logger;
+  private final CommandGateway commandGateway;
+
+  public TellerRestController(@Qualifier(ServiceConstants.LOGGER_NAME) final Logger logger,
+                              final CommandGateway commandGateway) {
+    super();
+    this.logger = logger;
+    this.commandGateway = commandGateway;
+  }
+
+  @Permittable(value = AcceptedTokenType.SYSTEM)
+  @RequestMapping(
+      value = "/initialize",
+      method = RequestMethod.POST,
+      consumes = MediaType.ALL_VALUE,
+      produces = MediaType.APPLICATION_JSON_VALUE
+  )
+  public
+  @ResponseBody
+  ResponseEntity<Void> initialize() {
+    this.commandGateway.process(new MigrationCommand());
+    return ResponseEntity.accepted().build();
+  }
+}
diff --git a/service/src/main/resources/db/migrations/mariadb/V1__initial_setup.sql b/service/src/main/resources/db/migrations/mariadb/V1__initial_setup.sql
index fb1b54e..717b5da 100644
--- a/service/src/main/resources/db/migrations/mariadb/V1__initial_setup.sql
+++ b/service/src/main/resources/db/migrations/mariadb/V1__initial_setup.sql
@@ -14,9 +14,21 @@
 -- limitations under the License.
 --
 
-CREATE TABLE template_samples (
+CREATE TABLE tajet_teller (
   id BIGINT NOT NULL AUTO_INCREMENT,
-  identifier VARCHAR(8) NOT NULL,
-  payload VARCHAR(512) NULL,
-  CONSTRAINT template_samples_pk PRIMARY KEY (id)
+  identifier                   VARCHAR(32)     NOT NULL,
+  a_password                   VARCHAR(4096)  NOT NULL,
+  a_salt                       VARCHAR(4069)  NOT NULL,
+  office_identifier            VARCHAR(32)    NOT NULL,
+  cashdraw_limit               NUMERIC(15, 5) NOT NULL,
+  teller_account_identifier    VARCHAR(32)    NOT NULL,
+  vault_account_identifier     VARCHAR(32)    NOT NULL,
+  assigned_employee_identifier VARCHAR(32)    NULL,
+  a_state                      VARCHAR(256)   NOT NULL,
+  created_on                   TIMESTAMP(3)   NOT NULL,
+  created_by                   VARCHAR(32)    NOT NULL,
+  last_modified_on             TIMESTAMP(3)   NULL,
+  last_modified_by             VARCHAR(32)    NULL,
+  CONSTRAINT tajet_teller_pk PRIMARY KEY (id),
+  CONSTRAINT tajet_teller_identifier_uq UNIQUE (identifier)
 );
diff --git a/shared.gradle b/shared.gradle
index 81135ee..4006bc4 100644
--- a/shared.gradle
+++ b/shared.gradle
@@ -9,7 +9,12 @@ ext.versions = [
         frameworkmariadb : '0.1.0-BUILD-SNAPSHOT',
         frameworkcommand : '0.1.0-BUILD-SNAPSHOT',
         frameworktest: '0.1.0-BUILD-SNAPSHOT',
+        frameworkcrypto: '0.1.0-BUILD-SNAPSHOT',
         frameworkanubis: '0.1.0-BUILD-SNAPSHOT',
+        frameworkoffice: '0.1.0-BUILD-SNAPSHOT',
+        frameworkaccounting: '0.1.0-BUILD-SNAPSHOT',
+        frameworkdeposit: '0.1.0-BUILD-SNAPSHOT',
+        frameworkportfolio: '0.1.0-BUILD-SNAPSHOT',
         validator : '5.3.0.Final'
 ]
 

-- 
To stop receiving notification emails like this one, please contact
myrle@apache.org.

[fineract-cn-teller] 24/30: added account state validation before any transaction added ability to include charges in cash received

Posted by my...@apache.org.
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-teller.git

commit 4da5eddb976af4c75d69b9acee772e8f80e02643
Author: mgeiss <mg...@mifos.org>
AuthorDate: Thu Jul 6 11:06:22 2017 +0200

    added account state validation before any transaction
    added ability to include charges in cash received
---
 .../mifos/teller/api/v1/client/TellerManager.java  |   3 +-
 .../java/io/mifos/teller/TestTellerOperation.java  | 129 +++++++++---
 .../mifos/teller/listener/TellerEventListener.java |  11 +
 .../command/ConfirmTellerTransactionCommand.java   |   8 +-
 .../handler/TellerTransactionAggregate.java        |   3 +-
 ...ocessor.java => DepositTransactionHandler.java} | 146 ++++++--------
 .../processor/TellerTransactionProcessor.java      | 224 +--------------------
 .../rest/TellerOperationRestController.java        |  15 +-
 8 files changed, 204 insertions(+), 335 deletions(-)

diff --git a/api/src/main/java/io/mifos/teller/api/v1/client/TellerManager.java b/api/src/main/java/io/mifos/teller/api/v1/client/TellerManager.java
index 82529b3..b31001e 100644
--- a/api/src/main/java/io/mifos/teller/api/v1/client/TellerManager.java
+++ b/api/src/main/java/io/mifos/teller/api/v1/client/TellerManager.java
@@ -169,7 +169,8 @@ public interface TellerManager {
   })
   void confirm(@PathVariable("tellerCode") final String tellerCode,
                @PathVariable("identifier") final String tellerTransactionIdentifier,
-               @RequestParam(value = "command", required = true) final String command);
+               @RequestParam(value = "command", required = true) final String command,
+               @RequestParam(value = "charges", required = false, defaultValue = "excluded") final String charges);
 
   @RequestMapping(
       value = "/teller/{tellerCode}/transactions",
diff --git a/component-test/src/main/java/io/mifos/teller/TestTellerOperation.java b/component-test/src/main/java/io/mifos/teller/TestTellerOperation.java
index 1f58971..98cbfbc 100644
--- a/component-test/src/main/java/io/mifos/teller/TestTellerOperation.java
+++ b/component-test/src/main/java/io/mifos/teller/TestTellerOperation.java
@@ -16,14 +16,19 @@
 package io.mifos.teller;
 
 import io.mifos.accounting.api.v1.domain.Account;
+import io.mifos.core.api.context.AutoUserContext;
 import io.mifos.core.lang.DateConverter;
+import io.mifos.deposit.api.v1.definition.domain.ProductDefinition;
+import io.mifos.deposit.api.v1.instance.domain.ProductInstance;
 import io.mifos.teller.api.v1.EventConstants;
 import io.mifos.teller.api.v1.client.TellerNotFoundException;
+import io.mifos.teller.api.v1.client.TellerTransactionValidationException;
 import io.mifos.teller.api.v1.client.TellerValidationException;
 import io.mifos.teller.api.v1.client.TransactionProcessingException;
 import io.mifos.teller.api.v1.domain.Teller;
 import io.mifos.teller.api.v1.domain.TellerManagementCommand;
 import io.mifos.teller.api.v1.domain.TellerTransaction;
+import io.mifos.teller.api.v1.domain.TellerTransactionCosts;
 import io.mifos.teller.api.v1.domain.UnlockDrawerCommand;
 import io.mifos.teller.util.TellerGenerator;
 import org.apache.commons.lang3.RandomStringUtils;
@@ -39,6 +44,8 @@ import java.util.Optional;
 
 public class TestTellerOperation extends AbstractTellerTest {
 
+  private static Teller tellerUnderTest = null;
+
   public TestTellerOperation() {
     super();
   }
@@ -94,13 +101,6 @@ public class TestTellerOperation extends AbstractTellerTest {
     Assert.assertTrue(super.eventRecorder.wait(EventConstants.PAUSE_TELLER, teller.getCode()));
   }
 
-  @Test(expected = TellerValidationException.class)
-  public void shouldNotPauseTellerNotAuthenticated() throws Exception {
-    final Teller teller = this.prepareTeller();
-
-    super.testSubject.post(teller.getCode(), "PAUSE");
-  }
-
   @Test
   public void shouldOpenAccount() throws Exception {
     final Teller teller = this.prepareTeller();
@@ -331,37 +331,49 @@ public class TestTellerOperation extends AbstractTellerTest {
     super.testSubject.post(teller.getCode(), tellerTransaction);
   }
 
-
   private Teller prepareTeller() throws Exception {
-    final String officeIdentifier = RandomStringUtils.randomAlphabetic(32);
-    final Teller teller = TellerGenerator.createRandomTeller();
+    if (TestTellerOperation.tellerUnderTest == null) {
+      final String officeIdentifier = RandomStringUtils.randomAlphabetic(32);
+      TestTellerOperation.tellerUnderTest = TellerGenerator.createRandomTeller();
 
-    Mockito.doAnswer(invocation -> true)
-        .when(super.organizationServiceSpy).officeExists(Matchers.eq(officeIdentifier));
+      Mockito.doAnswer(invocation -> true)
+          .when(super.organizationServiceSpy).officeExists(Matchers.eq(officeIdentifier));
 
-    Mockito.doAnswer(invocation -> Optional.of(new Account()))
-        .when(super.accountingServiceSpy).findAccount(Matchers.eq(teller.getTellerAccountIdentifier()));
+      Mockito.doAnswer(invocation -> Optional.of(new Account()))
+          .when(super.accountingServiceSpy).findAccount(Matchers.eq(TestTellerOperation.tellerUnderTest.getTellerAccountIdentifier()));
 
-    Mockito.doAnswer(invocation -> Optional.of(new Account()))
-        .when(super.accountingServiceSpy).findAccount(Matchers.eq(teller.getVaultAccountIdentifier()));
+      Mockito.doAnswer(invocation -> Optional.of(new Account()))
+          .when(super.accountingServiceSpy).findAccount(Matchers.eq(TestTellerOperation.tellerUnderTest.getVaultAccountIdentifier()));
 
-    super.testSubject.create(officeIdentifier, teller);
+      super.testSubject.create(officeIdentifier, TestTellerOperation.tellerUnderTest);
 
-    Assert.assertTrue(super.eventRecorder.wait(EventConstants.POST_TELLER, teller.getCode()));
+      Assert.assertTrue(super.eventRecorder.wait(EventConstants.POST_TELLER, TestTellerOperation.tellerUnderTest.getCode()));
 
-    final TellerManagementCommand command = new TellerManagementCommand();
-    command.setAction(TellerManagementCommand.Action.OPEN.name());
-    command.setAdjustment(TellerManagementCommand.Adjustment.NONE.name());
-    command.setAssignedEmployeeIdentifier(AbstractTellerTest.TEST_USER);
+      final TellerManagementCommand command = new TellerManagementCommand();
+      command.setAction(TellerManagementCommand.Action.OPEN.name());
+      command.setAdjustment(TellerManagementCommand.Adjustment.NONE.name());
+      command.setAssignedEmployeeIdentifier(AbstractTellerTest.TEST_USER);
 
-    Mockito.doAnswer(invocation -> true)
-        .when(super.organizationServiceSpy).employeeExists(Matchers.eq(command.getAssignedEmployeeIdentifier()));
+      Mockito.doAnswer(invocation -> true)
+          .when(super.organizationServiceSpy).employeeExists(Matchers.eq(command.getAssignedEmployeeIdentifier()));
+
+      super.testSubject.post(officeIdentifier, TestTellerOperation.tellerUnderTest.getCode(), command);
 
-    super.testSubject.post(officeIdentifier, teller.getCode(), command);
+      Assert.assertTrue(super.eventRecorder.wait(EventConstants.OPEN_TELLER, TestTellerOperation.tellerUnderTest.getCode()));
+    }
 
-    Assert.assertTrue(super.eventRecorder.wait(EventConstants.OPEN_TELLER, teller.getCode()));
+    final ProductInstance productInstance = new ProductInstance();
+    productInstance.setProductIdentifier(RandomStringUtils.randomAlphanumeric(32));
+    productInstance.setBalance(0.00D);
+    Mockito.doAnswer(invocation -> productInstance)
+        .when(super.depositAccountManagementServiceSpy).findProductInstance(Matchers.anyString());
 
-    return teller;
+    final ProductDefinition productDefinition = new ProductDefinition();
+    productDefinition.setMinimumBalance(0.00D);
+    Mockito.doAnswer(invocation -> productDefinition)
+        .when(super.depositAccountManagementServiceSpy).findProductDefinition(Matchers.eq(productInstance.getProductIdentifier()));
+
+    return TestTellerOperation.tellerUnderTest;
   }
 
   @Test(expected = TellerNotFoundException.class)
@@ -388,4 +400,67 @@ public class TestTellerOperation extends AbstractTellerTest {
 
     super.testSubject.unlockDrawer(teller.getCode(), unlockDrawerCommand);
   }
+
+  @Test(expected = TellerTransactionValidationException.class)
+  public void shouldNotReopenAccountClosed() throws Exception {
+    final Teller teller = this.prepareTeller();
+
+    final UnlockDrawerCommand unlockDrawerCommand = new UnlockDrawerCommand();
+    unlockDrawerCommand.setEmployeeIdentifier(AbstractTellerTest.TEST_USER);
+    unlockDrawerCommand.setPassword(teller.getPassword());
+
+    super.testSubject.unlockDrawer(teller.getCode(), unlockDrawerCommand);
+
+    super.eventRecorder.wait(EventConstants.AUTHENTICATE_TELLER, teller.getCode());
+
+    final TellerTransaction openAccountTransaction =  new TellerTransaction();
+    openAccountTransaction.setTransactionType(ServiceConstants.TX_OPEN_ACCOUNT);
+    openAccountTransaction.setTransactionDate(DateConverter.toIsoString(LocalDateTime.now(Clock.systemUTC())));
+    openAccountTransaction.setProductIdentifier(RandomStringUtils.randomAlphanumeric(32));
+    openAccountTransaction.setCustomerAccountIdentifier(RandomStringUtils.randomAlphanumeric(32));
+    openAccountTransaction.setCustomerIdentifier(RandomStringUtils.randomAlphanumeric(32));
+    openAccountTransaction.setClerk(AbstractTellerTest.TEST_USER);
+    openAccountTransaction.setAmount(1234.56D);
+
+    Mockito.doAnswer(invocation -> Optional.of(new Account()))
+        .when(super.accountingServiceSpy).findAccount(openAccountTransaction.getCustomerAccountIdentifier());
+    Mockito.doAnswer(invocation -> Collections.emptyList())
+        .when(super.depositAccountManagementServiceSpy).getCharges(Matchers.eq(openAccountTransaction));
+    Mockito.doAnswer(invocation -> Collections.emptyList())
+        .when(super.depositAccountManagementServiceSpy).fetchProductInstances(openAccountTransaction.getCustomerIdentifier());
+
+    final TellerTransactionCosts openingCosts = super.testSubject.post(teller.getCode(), openAccountTransaction);
+    super.testSubject.confirm(teller.getCode(), openingCosts.getTellerTransactionIdentifier(), "CONFIRM", "excluded");
+    super.eventRecorder.wait(EventConstants.CONFIRM_TRANSACTION, openingCosts.getTellerTransactionIdentifier());
+
+    final TellerTransaction closeAccountTransaction =  new TellerTransaction();
+    closeAccountTransaction.setTransactionType(ServiceConstants.TX_CLOSE_ACCOUNT);
+    closeAccountTransaction.setTransactionDate(DateConverter.toIsoString(LocalDateTime.now(Clock.systemUTC())));
+    closeAccountTransaction.setProductIdentifier(openAccountTransaction.getProductIdentifier());
+    closeAccountTransaction.setCustomerAccountIdentifier(openAccountTransaction.getCustomerAccountIdentifier());
+    closeAccountTransaction.setCustomerIdentifier(openAccountTransaction.getCustomerIdentifier());
+    closeAccountTransaction.setClerk(AbstractTellerTest.TEST_USER);
+    closeAccountTransaction.setAmount(1234.56D);
+
+    final Account account = new Account();
+    account.setBalance(1234.56D);
+
+    Mockito.doAnswer(invocation -> Optional.of(account))
+        .when(super.accountingServiceSpy).findAccount(openAccountTransaction.getCustomerAccountIdentifier());
+
+    final TellerTransactionCosts closingCosts = super.testSubject.post(teller.getCode(), closeAccountTransaction);
+    super.testSubject.confirm(teller.getCode(), closingCosts.getTellerTransactionIdentifier(), "CONFIRM", "excluded");
+    super.eventRecorder.wait(EventConstants.CONFIRM_TRANSACTION, closingCosts.getTellerTransactionIdentifier());
+
+    final TellerTransaction reopenAccountTransaction =  new TellerTransaction();
+    reopenAccountTransaction.setTransactionType(ServiceConstants.TX_OPEN_ACCOUNT);
+    reopenAccountTransaction.setTransactionDate(DateConverter.toIsoString(LocalDateTime.now(Clock.systemUTC())));
+    reopenAccountTransaction.setProductIdentifier(openAccountTransaction.getProductIdentifier());
+    reopenAccountTransaction.setCustomerAccountIdentifier(openAccountTransaction.getCustomerAccountIdentifier());
+    reopenAccountTransaction.setCustomerIdentifier(openAccountTransaction.getCustomerIdentifier());
+    reopenAccountTransaction.setClerk(AbstractTellerTest.TEST_USER);
+    reopenAccountTransaction.setAmount(1234.56D);
+
+    super.testSubject.post(teller.getCode(), reopenAccountTransaction);
+  }
 }
diff --git a/component-test/src/main/java/io/mifos/teller/listener/TellerEventListener.java b/component-test/src/main/java/io/mifos/teller/listener/TellerEventListener.java
index 0ad678a..a334311 100644
--- a/component-test/src/main/java/io/mifos/teller/listener/TellerEventListener.java
+++ b/component-test/src/main/java/io/mifos/teller/listener/TellerEventListener.java
@@ -103,4 +103,15 @@ public class TellerEventListener {
     this.logger.debug("Teller {} created.", payload);
     this.eventRecorder.event(tenant, EventConstants.PAUSE_TELLER, payload, String.class);
   }
+
+  @JmsListener(
+      destination = EventConstants.DESTINATION,
+      selector = EventConstants.SELECTOR_CONFIRM_TRANSACTION,
+      subscription = EventConstants.DESTINATION
+  )
+  public void confirmTransaction(@Header(TenantHeaderFilter.TENANT_HEADER) final String tenant,
+                      final String payload) {
+    this.logger.debug("Teller {} created.", payload);
+    this.eventRecorder.event(tenant, EventConstants.CONFIRM_TRANSACTION, payload, String.class);
+  }
 }
diff --git a/service/src/main/java/io/mifos/teller/service/internal/command/ConfirmTellerTransactionCommand.java b/service/src/main/java/io/mifos/teller/service/internal/command/ConfirmTellerTransactionCommand.java
index 1da91da..32b156e 100644
--- a/service/src/main/java/io/mifos/teller/service/internal/command/ConfirmTellerTransactionCommand.java
+++ b/service/src/main/java/io/mifos/teller/service/internal/command/ConfirmTellerTransactionCommand.java
@@ -17,13 +17,19 @@ package io.mifos.teller.service.internal.command;
 
 public class ConfirmTellerTransactionCommand {
   private final String tellerTransactionIdentifier;
+  private final boolean chargesIncluded;
 
-  public ConfirmTellerTransactionCommand(final String tellerTransactionIdentifier) {
+  public ConfirmTellerTransactionCommand(final String tellerTransactionIdentifier, final String charges) {
     super();
     this.tellerTransactionIdentifier = tellerTransactionIdentifier;
+    this.chargesIncluded = charges.equalsIgnoreCase("included");
   }
 
   public String tellerTransactionIdentifier() {
     return this.tellerTransactionIdentifier;
   }
+
+  public boolean chargesIncluded() {
+    return this.chargesIncluded;
+  }
 }
diff --git a/service/src/main/java/io/mifos/teller/service/internal/command/handler/TellerTransactionAggregate.java b/service/src/main/java/io/mifos/teller/service/internal/command/handler/TellerTransactionAggregate.java
index 5d59db4..224056c 100644
--- a/service/src/main/java/io/mifos/teller/service/internal/command/handler/TellerTransactionAggregate.java
+++ b/service/src/main/java/io/mifos/teller/service/internal/command/handler/TellerTransactionAggregate.java
@@ -91,7 +91,8 @@ public class TellerTransactionAggregate {
       final TellerTransactionEntity tellerTransactionEntity = optionalTellerTransaction.get();
 
       this.tellerTransactionProcessor.process(tellerTransactionEntity.getTeller().getIdentifier(),
-          TellerTransactionMapper.map(tellerTransactionEntity));
+          TellerTransactionMapper.map(tellerTransactionEntity),
+          confirmTellerTransactionCommand.chargesIncluded());
 
       tellerTransactionEntity.setState(TellerTransaction.State.CONFIRMED.name());
       this.tellerTransactionRepository.save(tellerTransactionEntity);
diff --git a/service/src/main/java/io/mifos/teller/service/internal/processor/TellerTransactionProcessor.java b/service/src/main/java/io/mifos/teller/service/internal/processor/DepositTransactionHandler.java
similarity index 67%
copy from service/src/main/java/io/mifos/teller/service/internal/processor/TellerTransactionProcessor.java
copy to service/src/main/java/io/mifos/teller/service/internal/processor/DepositTransactionHandler.java
index c03adff..ae78300 100644
--- a/service/src/main/java/io/mifos/teller/service/internal/processor/TellerTransactionProcessor.java
+++ b/service/src/main/java/io/mifos/teller/service/internal/processor/DepositTransactionHandler.java
@@ -41,7 +41,7 @@ import java.util.Set;
 import java.util.stream.Collectors;
 
 @Component
-public class TellerTransactionProcessor {
+public class DepositTransactionHandler {
 
   private final Logger logger;
   private final AccountingService accountingService;
@@ -49,10 +49,10 @@ public class TellerTransactionProcessor {
   private final TellerRepository tellerRepository;
 
   @Autowired
-  public TellerTransactionProcessor(@Qualifier(ServiceConstants.LOGGER_NAME) final Logger logger,
-                                    final AccountingService accountingService,
-                                    final DepositAccountManagementService depositAccountManagementService,
-                                    final TellerRepository tellerRepository) {
+  public DepositTransactionHandler(@Qualifier(ServiceConstants.LOGGER_NAME) final Logger logger,
+                                   final AccountingService accountingService,
+                                   final DepositAccountManagementService depositAccountManagementService,
+                                   final TellerRepository tellerRepository) {
     super();
     this.logger = logger;
     this.accountingService = accountingService;
@@ -60,42 +60,22 @@ public class TellerTransactionProcessor {
     this.tellerRepository = tellerRepository;
   }
 
-  public void process(final String tellerCode, final TellerTransaction tellerTransaction) {
-    switch (tellerTransaction.getTransactionType()) {
-      case ServiceConstants.TX_OPEN_ACCOUNT:
-        this.processDepositAccountOpening(tellerCode, tellerTransaction);
-        break;
-      case ServiceConstants.TX_CLOSE_ACCOUNT:
-        this.processDepositAccountClosing(tellerCode, tellerTransaction);
-        break;
-      case ServiceConstants.TX_ACCOUNT_TRANSFER:
-        this.processTransfer(tellerTransaction);
-        break;
-      case ServiceConstants.TX_CASH_DEPOSIT:
-        this.processCashDeposit(tellerCode, tellerTransaction);
-        break;
-      case ServiceConstants.TX_CASH_WITHDRAWAL:
-        this.processCashWithdrawal(tellerCode, tellerTransaction);
-        break;
-      default:
-        throw new IllegalArgumentException("Unsupported TX type " + tellerTransaction.getTransactionType());
-    }
-  }
+  public TellerTransactionCosts getDepositTransactionCosts(final TellerTransaction tellerTransaction) {
+    final List<Charge> charges = this.depositAccountManagementService.getCharges(tellerTransaction);
 
-  public TellerTransactionCosts getCosts(final TellerTransaction tellerTransaction) {
-    switch (tellerTransaction.getTransactionType()) {
-      case ServiceConstants.TX_OPEN_ACCOUNT:
-      case ServiceConstants.TX_CLOSE_ACCOUNT:
-      case ServiceConstants.TX_ACCOUNT_TRANSFER:
-      case ServiceConstants.TX_CASH_DEPOSIT:
-      case ServiceConstants.TX_CASH_WITHDRAWAL:
-        return this.getDepositTransactionCosts(tellerTransaction);
-      default:
-        throw new IllegalArgumentException("Unsupported TX type " + tellerTransaction.getTransactionType());
-    }
+    final TellerTransactionCosts tellerTransactionCosts = new TellerTransactionCosts();
+    tellerTransactionCosts.setCharges(charges);
+    tellerTransactionCosts.setTellerTransactionIdentifier(tellerTransaction.getIdentifier());
+    tellerTransactionCosts.setTotalAmount(
+        tellerTransaction.getAmount() + charges.stream().mapToDouble(Charge::getAmount).sum()
+    );
+
+    return tellerTransactionCosts;
   }
 
-  private void processTransfer(final TellerTransaction tellerTransaction) {
+  public void processTransfer(final String tellerCode, final TellerTransaction tellerTransaction,
+                               final boolean chargesIncluded) {
+    final TellerEntity tellerEntity = getTellerEntity(tellerCode);
     final JournalEntry journalEntry = this.prepareJournalEntry(tellerTransaction);
 
     final TellerTransactionCosts tellerTransactionCosts = this.getDepositTransactionCosts(tellerTransaction);
@@ -109,7 +89,11 @@ public class TellerTransactionProcessor {
     debtors.add(customerDebtor);
 
     if (!tellerTransactionCosts.getCharges().isEmpty()) {
-      debtors.add(this.createChargesDebtor(tellerTransaction.getCustomerAccountIdentifier(), tellerTransactionCosts));
+      if (chargesIncluded) {
+        debtors.add(this.createChargesDebtor(tellerEntity.getTellerAccountIdentifier(), tellerTransactionCosts));
+      } else {
+        debtors.add(this.createChargesDebtor(tellerTransaction.getCustomerAccountIdentifier(), tellerTransactionCosts));
+      }
     }
 
     final HashSet<Creditor> creditors = new HashSet<>();
@@ -125,14 +109,8 @@ public class TellerTransactionProcessor {
     this.accountingService.postJournalEntry(journalEntry);
   }
 
-  private void processCashDeposit(final String tellerCode, final TellerTransaction tellerTransaction) {
-    final Optional<TellerEntity> optionalTeller = this.tellerRepository.findByIdentifier(tellerCode);
-    if (!optionalTeller.isPresent()) {
-      this.logger.warn("Teller {} not found.", tellerCode);
-      throw new IllegalStateException("Teller not found.");
-    }
-
-    final TellerEntity tellerEntity = optionalTeller.get();
+  public void processCashDeposit(final String tellerCode, final TellerTransaction tellerTransaction, final boolean chargesIncluded) {
+    final TellerEntity tellerEntity = getTellerEntity(tellerCode);
     final JournalEntry journalEntry = this.prepareJournalEntry(tellerTransaction);
     final TellerTransactionCosts tellerTransactionCosts = this.getDepositTransactionCosts(tellerTransaction);
 
@@ -141,12 +119,15 @@ public class TellerTransactionProcessor {
 
     final Debtor tellerDebtor = new Debtor();
     tellerDebtor.setAccountNumber(tellerEntity.getTellerAccountIdentifier());
-    tellerDebtor.setAmount(tellerTransaction.getAmount().toString());
-    debtors.add(tellerDebtor);
-
-    if (!tellerTransactionCosts.getCharges().isEmpty()) {
-      debtors.add(this.createChargesDebtor(tellerTransaction.getCustomerAccountIdentifier(), tellerTransactionCosts));
+    if (chargesIncluded) {
+      tellerDebtor.setAmount(tellerTransactionCosts.getTotalAmount().toString());
+    } else {
+      tellerDebtor.setAmount(tellerTransaction.getAmount().toString());
+      if (!tellerTransactionCosts.getCharges().isEmpty()) {
+        debtors.add(this.createChargesDebtor(tellerTransaction.getCustomerAccountIdentifier(), tellerTransactionCosts));
+      }
     }
+    debtors.add(tellerDebtor);
 
     final HashSet<Creditor> creditors = new HashSet<>();
     journalEntry.setCreditors(creditors);
@@ -161,14 +142,9 @@ public class TellerTransactionProcessor {
     this.accountingService.postJournalEntry(journalEntry);
   }
 
-  private void processCashWithdrawal(final String tellerCode, final TellerTransaction tellerTransaction) {
-    final Optional<TellerEntity> optionalTeller = this.tellerRepository.findByIdentifier(tellerCode);
-    if (!optionalTeller.isPresent()) {
-      this.logger.warn("Teller {} not found.", tellerCode);
-      throw new IllegalStateException("Teller not found.");
-    }
-
-    final TellerEntity tellerEntity = optionalTeller.get();
+  public void processCashWithdrawal(final String tellerCode, final TellerTransaction tellerTransaction,
+                                    final boolean chargesIncluded) {
+    final TellerEntity tellerEntity = getTellerEntity(tellerCode);
     final JournalEntry journalEntry = this.prepareJournalEntry(tellerTransaction);
     final TellerTransactionCosts tellerTransactionCosts = this.getDepositTransactionCosts(tellerTransaction);
 
@@ -181,7 +157,11 @@ public class TellerTransactionProcessor {
     debtors.add(customerDebtor);
 
     if (!tellerTransactionCosts.getCharges().isEmpty()) {
-      debtors.add(this.createChargesDebtor(tellerTransaction.getCustomerAccountIdentifier(), tellerTransactionCosts));
+      if (chargesIncluded) {
+        debtors.add(this.createChargesDebtor(tellerEntity.getTellerAccountIdentifier(), tellerTransactionCosts));
+      } else {
+        debtors.add(this.createChargesDebtor(tellerTransaction.getCustomerAccountIdentifier(), tellerTransactionCosts));
+      }
     }
 
     final HashSet<Creditor> creditors = new HashSet<>();
@@ -197,28 +177,23 @@ public class TellerTransactionProcessor {
     this.accountingService.postJournalEntry(journalEntry);
   }
 
-  private void processDepositAccountClosing(final String tellerCode, final TellerTransaction tellerTransaction) {
-    final List<ProductInstance> productInstances =
-        this.depositAccountManagementService.fetchProductInstances(tellerTransaction.getCustomerIdentifier());
+  public void processDepositAccountClosing(final String tellerCode, final TellerTransaction tellerTransaction,
+                                            final boolean chargesIncluded) {
+    this.processCashWithdrawal(tellerCode, tellerTransaction, chargesIncluded);
 
-    this.processCashWithdrawal(tellerCode, tellerTransaction);
-
-    productInstances.forEach(productInstance -> {
-      if (productInstance.getAccountIdentifier().equals(tellerTransaction.getCustomerAccountIdentifier())) {
-        this.depositAccountManagementService.closeProductInstance(tellerTransaction.getCustomerAccountIdentifier());
-        this.accountingService.closeAccount(tellerTransaction.getCustomerAccountIdentifier());
-      }
-    });
+    this.depositAccountManagementService.closeProductInstance(tellerTransaction.getCustomerAccountIdentifier());
+    this.accountingService.closeAccount(tellerTransaction.getCustomerAccountIdentifier());
   }
 
-  private void processDepositAccountOpening(final String tellerCode, final TellerTransaction tellerTransaction) {
+  public void processDepositAccountOpening(final String tellerCode, final TellerTransaction tellerTransaction,
+                                            final boolean chargesIncluded) {
     final ProductInstance productInstances =
         this.depositAccountManagementService.findProductInstance(tellerTransaction.getCustomerAccountIdentifier());
 
     final ProductDefinition productDefinition =
         this.depositAccountManagementService.findProductDefinition(productInstances.getProductIdentifier());
 
-    this.processCashDeposit(tellerCode, tellerTransaction);
+    this.processCashDeposit(tellerCode, tellerTransaction, chargesIncluded);
 
     if ((tellerTransaction.getAmount() + productInstances.getBalance()) >= productDefinition.getMinimumBalance()) {
       this.depositAccountManagementService.activateProductInstance(tellerTransaction.getCustomerAccountIdentifier());
@@ -226,6 +201,16 @@ public class TellerTransactionProcessor {
     }
   }
 
+  private TellerEntity getTellerEntity(final String tellerCode) {
+    final Optional<TellerEntity> optionalTeller = this.tellerRepository.findByIdentifier(tellerCode);
+    if (!optionalTeller.isPresent()) {
+      this.logger.warn("Teller {} not found.", tellerCode);
+      throw new IllegalStateException("Teller not found.");
+    }
+
+    return optionalTeller.get();
+  }
+
   private JournalEntry prepareJournalEntry(final TellerTransaction tellerTransaction) {
     final JournalEntry journalEntry = new JournalEntry();
     journalEntry.setTransactionIdentifier(tellerTransaction.getIdentifier());
@@ -237,19 +222,6 @@ public class TellerTransactionProcessor {
     return journalEntry;
   }
 
-  private TellerTransactionCosts getDepositTransactionCosts(final TellerTransaction tellerTransaction) {
-    final List<Charge> charges = this.depositAccountManagementService.getCharges(tellerTransaction);
-
-    final TellerTransactionCosts tellerTransactionCosts = new TellerTransactionCosts();
-    tellerTransactionCosts.setCharges(charges);
-    tellerTransactionCosts.setTellerTransactionIdentifier(tellerTransaction.getIdentifier());
-    tellerTransactionCosts.setTotalAmount(
-        tellerTransaction.getAmount() + charges.stream().mapToDouble(Charge::getAmount).sum()
-    );
-
-    return tellerTransactionCosts;
-  }
-
   private Debtor createChargesDebtor(final String accountIdentifier, final TellerTransactionCosts tellerTransactionCosts) {
     final Debtor chargesDebtor = new Debtor();
     chargesDebtor.setAccountNumber(accountIdentifier);
diff --git a/service/src/main/java/io/mifos/teller/service/internal/processor/TellerTransactionProcessor.java b/service/src/main/java/io/mifos/teller/service/internal/processor/TellerTransactionProcessor.java
index c03adff..705911a 100644
--- a/service/src/main/java/io/mifos/teller/service/internal/processor/TellerTransactionProcessor.java
+++ b/service/src/main/java/io/mifos/teller/service/internal/processor/TellerTransactionProcessor.java
@@ -15,67 +15,44 @@
  */
 package io.mifos.teller.service.internal.processor;
 
-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.core.api.util.UserContextHolder;
-import io.mifos.deposit.api.v1.definition.domain.ProductDefinition;
-import io.mifos.deposit.api.v1.instance.domain.ProductInstance;
 import io.mifos.teller.ServiceConstants;
-import io.mifos.teller.api.v1.domain.Charge;
 import io.mifos.teller.api.v1.domain.TellerTransaction;
 import io.mifos.teller.api.v1.domain.TellerTransactionCosts;
-import io.mifos.teller.service.internal.repository.TellerEntity;
-import io.mifos.teller.service.internal.repository.TellerRepository;
-import io.mifos.teller.service.internal.service.helper.AccountingService;
-import io.mifos.teller.service.internal.service.helper.DepositAccountManagementService;
 import org.slf4j.Logger;
 import org.springframework.beans.factory.annotation.Autowired;
 import org.springframework.beans.factory.annotation.Qualifier;
 import org.springframework.stereotype.Component;
 
-import java.util.HashSet;
-import java.util.List;
-import java.util.Optional;
-import java.util.Set;
-import java.util.stream.Collectors;
-
 @Component
 public class TellerTransactionProcessor {
 
   private final Logger logger;
-  private final AccountingService accountingService;
-  private final DepositAccountManagementService depositAccountManagementService;
-  private final TellerRepository tellerRepository;
+  private final DepositTransactionHandler depositTransactionHandler;
 
   @Autowired
   public TellerTransactionProcessor(@Qualifier(ServiceConstants.LOGGER_NAME) final Logger logger,
-                                    final AccountingService accountingService,
-                                    final DepositAccountManagementService depositAccountManagementService,
-                                    final TellerRepository tellerRepository) {
+                                    final DepositTransactionHandler depositTransactionHandler) {
     super();
     this.logger = logger;
-    this.accountingService = accountingService;
-    this.depositAccountManagementService = depositAccountManagementService;
-    this.tellerRepository = tellerRepository;
+    this.depositTransactionHandler = depositTransactionHandler;
   }
 
-  public void process(final String tellerCode, final TellerTransaction tellerTransaction) {
+  public void process(final String tellerCode, final TellerTransaction tellerTransaction, final Boolean chargesIncluded) {
     switch (tellerTransaction.getTransactionType()) {
       case ServiceConstants.TX_OPEN_ACCOUNT:
-        this.processDepositAccountOpening(tellerCode, tellerTransaction);
+        this.depositTransactionHandler.processDepositAccountOpening(tellerCode, tellerTransaction, chargesIncluded);
         break;
       case ServiceConstants.TX_CLOSE_ACCOUNT:
-        this.processDepositAccountClosing(tellerCode, tellerTransaction);
+        this.depositTransactionHandler.processDepositAccountClosing(tellerCode, tellerTransaction, chargesIncluded);
         break;
       case ServiceConstants.TX_ACCOUNT_TRANSFER:
-        this.processTransfer(tellerTransaction);
+        this.depositTransactionHandler.processTransfer(tellerCode, tellerTransaction, chargesIncluded);
         break;
       case ServiceConstants.TX_CASH_DEPOSIT:
-        this.processCashDeposit(tellerCode, tellerTransaction);
+        this.depositTransactionHandler.processCashDeposit(tellerCode, tellerTransaction, chargesIncluded);
         break;
       case ServiceConstants.TX_CASH_WITHDRAWAL:
-        this.processCashWithdrawal(tellerCode, tellerTransaction);
+        this.depositTransactionHandler.processCashWithdrawal(tellerCode, tellerTransaction, chargesIncluded);
         break;
       default:
         throw new IllegalArgumentException("Unsupported TX type " + tellerTransaction.getTransactionType());
@@ -89,191 +66,10 @@ public class TellerTransactionProcessor {
       case ServiceConstants.TX_ACCOUNT_TRANSFER:
       case ServiceConstants.TX_CASH_DEPOSIT:
       case ServiceConstants.TX_CASH_WITHDRAWAL:
-        return this.getDepositTransactionCosts(tellerTransaction);
+        return this.depositTransactionHandler.getDepositTransactionCosts(tellerTransaction);
       default:
         throw new IllegalArgumentException("Unsupported TX type " + tellerTransaction.getTransactionType());
     }
   }
 
-  private void processTransfer(final TellerTransaction tellerTransaction) {
-    final JournalEntry journalEntry = this.prepareJournalEntry(tellerTransaction);
-
-    final TellerTransactionCosts tellerTransactionCosts = this.getDepositTransactionCosts(tellerTransaction);
-
-    final HashSet<Debtor> debtors = new HashSet<>();
-    journalEntry.setDebtors(debtors);
-
-    final Debtor customerDebtor = new Debtor();
-    customerDebtor.setAccountNumber(tellerTransaction.getCustomerAccountIdentifier());
-    customerDebtor.setAmount(tellerTransaction.getAmount().toString());
-    debtors.add(customerDebtor);
-
-    if (!tellerTransactionCosts.getCharges().isEmpty()) {
-      debtors.add(this.createChargesDebtor(tellerTransaction.getCustomerAccountIdentifier(), tellerTransactionCosts));
-    }
-
-    final HashSet<Creditor> creditors = new HashSet<>();
-    journalEntry.setCreditors(creditors);
-
-    final Creditor targetCreditor = new Creditor();
-    targetCreditor.setAccountNumber(tellerTransaction.getTargetAccountIdentifier());
-    targetCreditor.setAmount(tellerTransaction.getAmount().toString());
-    creditors.add(targetCreditor);
-
-    creditors.addAll(this.createChargeCreditors(tellerTransactionCosts));
-
-    this.accountingService.postJournalEntry(journalEntry);
-  }
-
-  private void processCashDeposit(final String tellerCode, final TellerTransaction tellerTransaction) {
-    final Optional<TellerEntity> optionalTeller = this.tellerRepository.findByIdentifier(tellerCode);
-    if (!optionalTeller.isPresent()) {
-      this.logger.warn("Teller {} not found.", tellerCode);
-      throw new IllegalStateException("Teller not found.");
-    }
-
-    final TellerEntity tellerEntity = optionalTeller.get();
-    final JournalEntry journalEntry = this.prepareJournalEntry(tellerTransaction);
-    final TellerTransactionCosts tellerTransactionCosts = this.getDepositTransactionCosts(tellerTransaction);
-
-    final HashSet<Debtor> debtors = new HashSet<>();
-    journalEntry.setDebtors(debtors);
-
-    final Debtor tellerDebtor = new Debtor();
-    tellerDebtor.setAccountNumber(tellerEntity.getTellerAccountIdentifier());
-    tellerDebtor.setAmount(tellerTransaction.getAmount().toString());
-    debtors.add(tellerDebtor);
-
-    if (!tellerTransactionCosts.getCharges().isEmpty()) {
-      debtors.add(this.createChargesDebtor(tellerTransaction.getCustomerAccountIdentifier(), tellerTransactionCosts));
-    }
-
-    final HashSet<Creditor> creditors = new HashSet<>();
-    journalEntry.setCreditors(creditors);
-
-    final Creditor customerCreditor = new Creditor();
-    customerCreditor.setAccountNumber(tellerTransaction.getCustomerAccountIdentifier());
-    customerCreditor.setAmount(tellerTransaction.getAmount().toString());
-    creditors.add(customerCreditor);
-
-    creditors.addAll(this.createChargeCreditors(tellerTransactionCosts));
-
-    this.accountingService.postJournalEntry(journalEntry);
-  }
-
-  private void processCashWithdrawal(final String tellerCode, final TellerTransaction tellerTransaction) {
-    final Optional<TellerEntity> optionalTeller = this.tellerRepository.findByIdentifier(tellerCode);
-    if (!optionalTeller.isPresent()) {
-      this.logger.warn("Teller {} not found.", tellerCode);
-      throw new IllegalStateException("Teller not found.");
-    }
-
-    final TellerEntity tellerEntity = optionalTeller.get();
-    final JournalEntry journalEntry = this.prepareJournalEntry(tellerTransaction);
-    final TellerTransactionCosts tellerTransactionCosts = this.getDepositTransactionCosts(tellerTransaction);
-
-    final HashSet<Debtor> debtors = new HashSet<>();
-    journalEntry.setDebtors(debtors);
-
-    final Debtor customerDebtor = new Debtor();
-    customerDebtor.setAccountNumber(tellerTransaction.getCustomerAccountIdentifier());
-    customerDebtor.setAmount(tellerTransaction.getAmount().toString());
-    debtors.add(customerDebtor);
-
-    if (!tellerTransactionCosts.getCharges().isEmpty()) {
-      debtors.add(this.createChargesDebtor(tellerTransaction.getCustomerAccountIdentifier(), tellerTransactionCosts));
-    }
-
-    final HashSet<Creditor> creditors = new HashSet<>();
-    journalEntry.setCreditors(creditors);
-
-    final Creditor tellerCreditor = new Creditor();
-    tellerCreditor.setAccountNumber(tellerEntity.getTellerAccountIdentifier());
-    tellerCreditor.setAmount(tellerTransaction.getAmount().toString());
-    creditors.add(tellerCreditor);
-
-    creditors.addAll(this.createChargeCreditors(tellerTransactionCosts));
-
-    this.accountingService.postJournalEntry(journalEntry);
-  }
-
-  private void processDepositAccountClosing(final String tellerCode, final TellerTransaction tellerTransaction) {
-    final List<ProductInstance> productInstances =
-        this.depositAccountManagementService.fetchProductInstances(tellerTransaction.getCustomerIdentifier());
-
-    this.processCashWithdrawal(tellerCode, tellerTransaction);
-
-    productInstances.forEach(productInstance -> {
-      if (productInstance.getAccountIdentifier().equals(tellerTransaction.getCustomerAccountIdentifier())) {
-        this.depositAccountManagementService.closeProductInstance(tellerTransaction.getCustomerAccountIdentifier());
-        this.accountingService.closeAccount(tellerTransaction.getCustomerAccountIdentifier());
-      }
-    });
-  }
-
-  private void processDepositAccountOpening(final String tellerCode, final TellerTransaction tellerTransaction) {
-    final ProductInstance productInstances =
-        this.depositAccountManagementService.findProductInstance(tellerTransaction.getCustomerAccountIdentifier());
-
-    final ProductDefinition productDefinition =
-        this.depositAccountManagementService.findProductDefinition(productInstances.getProductIdentifier());
-
-    this.processCashDeposit(tellerCode, tellerTransaction);
-
-    if ((tellerTransaction.getAmount() + productInstances.getBalance()) >= productDefinition.getMinimumBalance()) {
-      this.depositAccountManagementService.activateProductInstance(tellerTransaction.getCustomerAccountIdentifier());
-      this.accountingService.openAccount(tellerTransaction.getCustomerAccountIdentifier());
-    }
-  }
-
-  private JournalEntry prepareJournalEntry(final TellerTransaction tellerTransaction) {
-    final JournalEntry journalEntry = new JournalEntry();
-    journalEntry.setTransactionIdentifier(tellerTransaction.getIdentifier());
-    journalEntry.setTransactionDate(tellerTransaction.getTransactionDate());
-    journalEntry.setTransactionType(tellerTransaction.getTransactionType());
-    journalEntry.setMessage(tellerTransaction.getTransactionType());
-    journalEntry.setClerk(UserContextHolder.checkedGetUser());
-
-    return journalEntry;
-  }
-
-  private TellerTransactionCosts getDepositTransactionCosts(final TellerTransaction tellerTransaction) {
-    final List<Charge> charges = this.depositAccountManagementService.getCharges(tellerTransaction);
-
-    final TellerTransactionCosts tellerTransactionCosts = new TellerTransactionCosts();
-    tellerTransactionCosts.setCharges(charges);
-    tellerTransactionCosts.setTellerTransactionIdentifier(tellerTransaction.getIdentifier());
-    tellerTransactionCosts.setTotalAmount(
-        tellerTransaction.getAmount() + charges.stream().mapToDouble(Charge::getAmount).sum()
-    );
-
-    return tellerTransactionCosts;
-  }
-
-  private Debtor createChargesDebtor(final String accountIdentifier, final TellerTransactionCosts tellerTransactionCosts) {
-    final Debtor chargesDebtor = new Debtor();
-    chargesDebtor.setAccountNumber(accountIdentifier);
-    chargesDebtor.setAmount(
-        Double.valueOf(
-            tellerTransactionCosts.getCharges()
-                .stream()
-                .mapToDouble(Charge::getAmount)
-                .sum()
-        ).toString()
-    );
-
-    return chargesDebtor;
-  }
-
-  private Set<Creditor> createChargeCreditors(final TellerTransactionCosts tellerTransactionCosts) {
-    return tellerTransactionCosts.getCharges()
-        .stream()
-        .map(charge -> {
-          final Creditor chargeCreditor = new Creditor();
-          chargeCreditor.setAccountNumber(charge.getIncomeAccountIdentifier());
-          chargeCreditor.setAmount(charge.getAmount().toString());
-          return chargeCreditor;
-        })
-        .collect(Collectors.toSet());
-  }
 }
diff --git a/service/src/main/java/io/mifos/teller/service/rest/TellerOperationRestController.java b/service/src/main/java/io/mifos/teller/service/rest/TellerOperationRestController.java
index 6f1104f..6295119 100644
--- a/service/src/main/java/io/mifos/teller/service/rest/TellerOperationRestController.java
+++ b/service/src/main/java/io/mifos/teller/service/rest/TellerOperationRestController.java
@@ -84,7 +84,7 @@ public class TellerOperationRestController {
   )
   @ResponseBody
   ResponseEntity<Teller> unlockDrawer(@PathVariable("tellerCode") final String tellerCode,
-                                    @RequestBody @Valid final UnlockDrawerCommand unlockDrawerCommand) {
+                                      @RequestBody @Valid final UnlockDrawerCommand unlockDrawerCommand) {
     final Teller teller = this.verifyTeller(tellerCode);
 
     if (teller.getState().equals(Teller.State.CLOSED.name())) {
@@ -170,11 +170,17 @@ public class TellerOperationRestController {
     if (!optionalCustomerAccount.isPresent()) {
       throw ServiceException.badRequest("Customer account {0} not found.");
     } else {
+      final Account customerAccount = optionalCustomerAccount.get();
+
+      if (!customerAccount.getState().equals(Account.State.OPEN)) {
+        throw ServiceException.conflict("Account {0} is not open.", customerAccount.getIdentifier());
+      }
+
       if (transactionType.equals(ServiceConstants.TX_ACCOUNT_TRANSFER)
           || transactionType.equals(ServiceConstants.TX_CASH_WITHDRAWAL)
           || transactionType.equals(ServiceConstants.TX_CLOSE_ACCOUNT)) {
 
-        final Account customerAccount = optionalCustomerAccount.get();
+
         if (customerAccount.getBalance() < tellerTransaction.getAmount()) {
           throw ServiceException.conflict("Not enough balance.");
         }
@@ -206,7 +212,8 @@ public class TellerOperationRestController {
   @ResponseBody
   ResponseEntity<Void> confirm(@PathVariable("tellerCode") final String tellerCode,
                                @PathVariable("identifier") final String tellerTransactionIdentifier,
-                               @RequestParam(value = "command", required = true) final String command) {
+                               @RequestParam(value = "command", required = true) final String command,
+                               @RequestParam(value = "charges", required = false, defaultValue = "excluded") final String charges) {
     final Teller teller = this.verifyTeller(tellerCode);
 
     this.verifyEmployee(teller);
@@ -217,7 +224,7 @@ public class TellerOperationRestController {
 
     switch (command.toUpperCase()) {
       case "CONFIRM" :
-        this.commandGateway.process(new ConfirmTellerTransactionCommand(tellerTransactionIdentifier));
+        this.commandGateway.process(new ConfirmTellerTransactionCommand(tellerTransactionIdentifier, charges));
         break;
       case "CANCEL" :
         this.commandGateway.process(new CancelTellerTransactionCommand(tellerTransactionIdentifier));

-- 
To stop receiving notification emails like this one, please contact
myrle@apache.org.

[fineract-cn-teller] 21/30: refactored to add more clarity

Posted by my...@apache.org.
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-teller.git

commit 733149bfe9ba9fe17976d82116ead8ecac4738fe
Author: mgeiss <mg...@mifos.org>
AuthorDate: Wed Jun 28 09:06:21 2017 +0200

    refactored to add more clarity
---
 .../processor/TellerTransactionProcessor.java      | 73 +++++++++++++---------
 1 file changed, 43 insertions(+), 30 deletions(-)

diff --git a/service/src/main/java/io/mifos/teller/service/internal/processor/TellerTransactionProcessor.java b/service/src/main/java/io/mifos/teller/service/internal/processor/TellerTransactionProcessor.java
index f429425..c03adff 100644
--- a/service/src/main/java/io/mifos/teller/service/internal/processor/TellerTransactionProcessor.java
+++ b/service/src/main/java/io/mifos/teller/service/internal/processor/TellerTransactionProcessor.java
@@ -89,39 +89,28 @@ public class TellerTransactionProcessor {
       case ServiceConstants.TX_ACCOUNT_TRANSFER:
       case ServiceConstants.TX_CASH_DEPOSIT:
       case ServiceConstants.TX_CASH_WITHDRAWAL:
-        return this.depositAccountCosts(tellerTransaction);
+        return this.getDepositTransactionCosts(tellerTransaction);
       default:
         throw new IllegalArgumentException("Unsupported TX type " + tellerTransaction.getTransactionType());
     }
   }
 
-  private TellerTransactionCosts depositAccountCosts(final TellerTransaction tellerTransaction) {
-    final List<Charge> charges = this.depositAccountManagementService.getCharges(tellerTransaction);
-
-    final TellerTransactionCosts tellerTransactionCosts = new TellerTransactionCosts();
-    tellerTransactionCosts.setCharges(charges);
-    tellerTransactionCosts.setTellerTransactionIdentifier(tellerTransaction.getIdentifier());
-    tellerTransactionCosts.setTotalAmount(tellerTransaction.getAmount() + charges.stream().mapToDouble(Charge::getAmount).sum());
-
-    return tellerTransactionCosts;
-  }
-
   private void processTransfer(final TellerTransaction tellerTransaction) {
     final JournalEntry journalEntry = this.prepareJournalEntry(tellerTransaction);
 
-    final TellerTransactionCosts tellerTransactionCosts = this.depositAccountCosts(tellerTransaction);
+    final TellerTransactionCosts tellerTransactionCosts = this.getDepositTransactionCosts(tellerTransaction);
 
     final HashSet<Debtor> debtors = new HashSet<>();
     journalEntry.setDebtors(debtors);
 
-    final Debtor debtor = new Debtor();
-    debtor.setAccountNumber(tellerTransaction.getCustomerAccountIdentifier());
+    final Debtor customerDebtor = new Debtor();
+    customerDebtor.setAccountNumber(tellerTransaction.getCustomerAccountIdentifier());
+    customerDebtor.setAmount(tellerTransaction.getAmount().toString());
+    debtors.add(customerDebtor);
+
     if (!tellerTransactionCosts.getCharges().isEmpty()) {
-      debtor.setAmount(tellerTransactionCosts.getTotalAmount().toString());
-    } else {
-      debtor.setAmount(tellerTransaction.getAmount().toString());
+      debtors.add(this.createChargesDebtor(tellerTransaction.getCustomerAccountIdentifier(), tellerTransactionCosts));
     }
-    debtors.add(debtor);
 
     final HashSet<Creditor> creditors = new HashSet<>();
     journalEntry.setCreditors(creditors);
@@ -145,7 +134,7 @@ public class TellerTransactionProcessor {
 
     final TellerEntity tellerEntity = optionalTeller.get();
     final JournalEntry journalEntry = this.prepareJournalEntry(tellerTransaction);
-    final TellerTransactionCosts tellerTransactionCosts = this.depositAccountCosts(tellerTransaction);
+    final TellerTransactionCosts tellerTransactionCosts = this.getDepositTransactionCosts(tellerTransaction);
 
     final HashSet<Debtor> debtors = new HashSet<>();
     journalEntry.setDebtors(debtors);
@@ -156,11 +145,7 @@ public class TellerTransactionProcessor {
     debtors.add(tellerDebtor);
 
     if (!tellerTransactionCosts.getCharges().isEmpty()) {
-      final Double chargesTotal = tellerTransactionCosts.getTotalAmount() - tellerTransaction.getAmount();
-      final Debtor customerDebtor = new Debtor();
-      customerDebtor.setAccountNumber(tellerTransaction.getCustomerAccountIdentifier());
-      customerDebtor.setAmount(chargesTotal.toString());
-      debtors.add(customerDebtor);
+      debtors.add(this.createChargesDebtor(tellerTransaction.getCustomerAccountIdentifier(), tellerTransactionCosts));
     }
 
     final HashSet<Creditor> creditors = new HashSet<>();
@@ -185,19 +170,19 @@ public class TellerTransactionProcessor {
 
     final TellerEntity tellerEntity = optionalTeller.get();
     final JournalEntry journalEntry = this.prepareJournalEntry(tellerTransaction);
-    final TellerTransactionCosts tellerTransactionCosts = this.depositAccountCosts(tellerTransaction);
+    final TellerTransactionCosts tellerTransactionCosts = this.getDepositTransactionCosts(tellerTransaction);
 
     final HashSet<Debtor> debtors = new HashSet<>();
     journalEntry.setDebtors(debtors);
 
     final Debtor customerDebtor = new Debtor();
     customerDebtor.setAccountNumber(tellerTransaction.getCustomerAccountIdentifier());
+    customerDebtor.setAmount(tellerTransaction.getAmount().toString());
+    debtors.add(customerDebtor);
+
     if (!tellerTransactionCosts.getCharges().isEmpty()) {
-      customerDebtor.setAmount(tellerTransactionCosts.getTotalAmount().toString());
-    } else {
-      customerDebtor.setAmount(tellerTransaction.getAmount().toString());
+      debtors.add(this.createChargesDebtor(tellerTransaction.getCustomerAccountIdentifier(), tellerTransactionCosts));
     }
-    debtors.add(customerDebtor);
 
     final HashSet<Creditor> creditors = new HashSet<>();
     journalEntry.setCreditors(creditors);
@@ -252,6 +237,34 @@ public class TellerTransactionProcessor {
     return journalEntry;
   }
 
+  private TellerTransactionCosts getDepositTransactionCosts(final TellerTransaction tellerTransaction) {
+    final List<Charge> charges = this.depositAccountManagementService.getCharges(tellerTransaction);
+
+    final TellerTransactionCosts tellerTransactionCosts = new TellerTransactionCosts();
+    tellerTransactionCosts.setCharges(charges);
+    tellerTransactionCosts.setTellerTransactionIdentifier(tellerTransaction.getIdentifier());
+    tellerTransactionCosts.setTotalAmount(
+        tellerTransaction.getAmount() + charges.stream().mapToDouble(Charge::getAmount).sum()
+    );
+
+    return tellerTransactionCosts;
+  }
+
+  private Debtor createChargesDebtor(final String accountIdentifier, final TellerTransactionCosts tellerTransactionCosts) {
+    final Debtor chargesDebtor = new Debtor();
+    chargesDebtor.setAccountNumber(accountIdentifier);
+    chargesDebtor.setAmount(
+        Double.valueOf(
+            tellerTransactionCosts.getCharges()
+                .stream()
+                .mapToDouble(Charge::getAmount)
+                .sum()
+        ).toString()
+    );
+
+    return chargesDebtor;
+  }
+
   private Set<Creditor> createChargeCreditors(final TellerTransactionCosts tellerTransactionCosts) {
     return tellerTransactionCosts.getCharges()
         .stream()

-- 
To stop receiving notification emails like this one, please contact
myrle@apache.org.

[fineract-cn-teller] 20/30: returning teller after unlock

Posted by my...@apache.org.
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-teller.git

commit c536d8332bc2d099364289ce3ff00e349c1d79de
Author: mgeiss <mg...@mifos.org>
AuthorDate: Mon Jun 26 15:48:39 2017 +0200

    returning teller after unlock
---
 api/src/main/java/io/mifos/teller/api/v1/client/TellerManager.java  | 2 +-
 .../src/main/java/io/mifos/teller/TestTellerOperation.java          | 6 +++---
 .../io/mifos/teller/service/rest/TellerOperationRestController.java | 4 ++--
 3 files changed, 6 insertions(+), 6 deletions(-)

diff --git a/api/src/main/java/io/mifos/teller/api/v1/client/TellerManager.java b/api/src/main/java/io/mifos/teller/api/v1/client/TellerManager.java
index 6a965e6..82529b3 100644
--- a/api/src/main/java/io/mifos/teller/api/v1/client/TellerManager.java
+++ b/api/src/main/java/io/mifos/teller/api/v1/client/TellerManager.java
@@ -128,7 +128,7 @@ public interface TellerManager {
       @ThrowsException(status = HttpStatus.BAD_REQUEST, exception = TellerNotFoundException.class),
       @ThrowsException(status = HttpStatus.CONFLICT, exception = TellerNotFoundException.class)
   })
-  void unlockDrawer(@PathVariable("tellerCode") final String tellerCode,
+  Teller unlockDrawer(@PathVariable("tellerCode") final String tellerCode,
                     @RequestBody @Valid final UnlockDrawerCommand unlockDrawerCommand);
 
   @RequestMapping(
diff --git a/component-test/src/main/java/io/mifos/teller/TestTellerOperation.java b/component-test/src/main/java/io/mifos/teller/TestTellerOperation.java
index 7d3e1da..1f58971 100644
--- a/component-test/src/main/java/io/mifos/teller/TestTellerOperation.java
+++ b/component-test/src/main/java/io/mifos/teller/TestTellerOperation.java
@@ -44,7 +44,7 @@ public class TestTellerOperation extends AbstractTellerTest {
   }
 
   @Test
-  public void shouldAuthenticate() throws Exception {
+  public void shouldUnlock() throws Exception {
     final Teller teller = this.prepareTeller();
 
     final UnlockDrawerCommand unlockDrawerCommand = new UnlockDrawerCommand();
@@ -56,7 +56,7 @@ public class TestTellerOperation extends AbstractTellerTest {
 
 
   @Test(expected = TellerNotFoundException.class)
-  public void shouldNotAuthenticateUserMismatch() throws Exception {
+  public void shouldNotUnlockUserMismatch() throws Exception {
     final Teller teller = this.prepareTeller();
 
     final UnlockDrawerCommand unlockDrawerCommand = new UnlockDrawerCommand();
@@ -67,7 +67,7 @@ public class TestTellerOperation extends AbstractTellerTest {
   }
 
   @Test(expected = TellerNotFoundException.class)
-  public void shouldNotAuthenticatePasswordMismatch() throws Exception {
+  public void shouldNotUnlockPasswordMismatch() throws Exception {
     final Teller teller = this.prepareTeller();
 
     final UnlockDrawerCommand unlockDrawerCommand = new UnlockDrawerCommand();
diff --git a/service/src/main/java/io/mifos/teller/service/rest/TellerOperationRestController.java b/service/src/main/java/io/mifos/teller/service/rest/TellerOperationRestController.java
index 2a2ca8d..6f1104f 100644
--- a/service/src/main/java/io/mifos/teller/service/rest/TellerOperationRestController.java
+++ b/service/src/main/java/io/mifos/teller/service/rest/TellerOperationRestController.java
@@ -83,7 +83,7 @@ public class TellerOperationRestController {
       produces = MediaType.APPLICATION_JSON_VALUE
   )
   @ResponseBody
-  ResponseEntity<Void> unlockDrawer(@PathVariable("tellerCode") final String tellerCode,
+  ResponseEntity<Teller> unlockDrawer(@PathVariable("tellerCode") final String tellerCode,
                                     @RequestBody @Valid final UnlockDrawerCommand unlockDrawerCommand) {
     final Teller teller = this.verifyTeller(tellerCode);
 
@@ -103,7 +103,7 @@ public class TellerOperationRestController {
 
       this.logger.debug("Drawer {0} unlocked", unlockedTeller);
 
-      return ResponseEntity.ok().build();
+      return ResponseEntity.ok(teller);
     } catch (final Exception e) {
       throw ServiceException.notFound("Teller {0} not found.", teller.getCode());
     }

-- 
To stop receiving notification emails like this one, please contact
myrle@apache.org.

[fineract-cn-teller] 02/30: edited readme

Posted by my...@apache.org.
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-teller.git

commit 480ddbde8c4d04feac9b70b1522222dfc51b5e65
Author: mgeiss <mg...@mifos.org>
AuthorDate: Wed Jun 7 07:57:25 2017 +0200

    edited readme
---
 README.md | 45 ++-------------------------------------------
 1 file changed, 2 insertions(+), 43 deletions(-)

diff --git a/README.md b/README.md
index 1839633..19e4010 100644
--- a/README.md
+++ b/README.md
@@ -1,49 +1,8 @@
-# Mifos I/O Template
+# Mifos I/O Teller
 
 [![Join the chat at https://gitter.im/mifos-initiative/mifos.io](https://badges.gitter.im/Join%20Chat.svg)](https://gitter.im/mifos-initiative/mifos.io?utm_source=badge&utm_medium=badge&utm_campaign=pr-badge&utm_content=badge)
 
-This project provides a template layout for all Mifos I/O microservices.
-
-## Abstract
-Mifos I/O is an application framework for digital financial services, a system to support nationwide and cross-national financial transactions and help to level and speed the creation of an inclusive, interconnected digital economy for every nation in the world.
-
-## Steps needed to turn the template project into a real project
-
-1.  Git clone template into {project name} folder
-
-        git clone https://github.com/mifosio/template.git {project name}
-
-2.  Delete _.git_
-
-        rm -rf .git
-    
-3.  Open settings.gradle and replace value of _rootProject.name_ with {project name}
-
-4.  Open root build.gradle and replace value of _version_ with 0.1.0-snapshot
-
-6.  Create Gradle wrapper
-
-        gradle wrapper
-
-6.  Open all module specific build.gradle files (api, service, and component-test) and replace value of _group_ with io.mifos.{project name}
-
-7.  Import project into IDE
-
-8.  Rename all io.mifos.template packages to io.mifos.{project name}
-
-9.  Open _SampleRestConfiguration_ and _SampleServiceConfiguration_, adjust @ComponentScan to reflect the new package name
-
-10. Open _application.yml_ and replace _server.contextPath_ with /{project name}/v1/*
-
-11. Open _bootstrap.yml_ and replace _spring.application.name_ with {project name}/v1/
-
-12. Open _SampleTest_ and replace constructor argument of TestEnvironment in line 80 with {project name}/v1/
-
-13. Run _SampleTest_
-
-14. Replace the contents of the README with text describing your new project.
-
-15. Happy coding! ; o) 
+This project provides management and operational functionality for teller operation.
 
 ## Versioning
 The version numbers follow the [Semantic Versioning](http://semver.org/) scheme.

-- 
To stop receiving notification emails like this one, please contact
myrle@apache.org.

[fineract-cn-teller] 08/30: added NONE for adjustment

Posted by my...@apache.org.
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-teller.git

commit d1e78ab10a17537eca4c95412593bfc24cc78731
Author: mgeiss <mg...@mifos.org>
AuthorDate: Mon Jun 12 16:51:05 2017 +0200

    added NONE for adjustment
---
 .../java/io/mifos/teller/api/v1/domain/TellerManagementCommand.java     | 2 ++
 1 file changed, 2 insertions(+)

diff --git a/api/src/main/java/io/mifos/teller/api/v1/domain/TellerManagementCommand.java b/api/src/main/java/io/mifos/teller/api/v1/domain/TellerManagementCommand.java
index 01194eb..d332ffb 100644
--- a/api/src/main/java/io/mifos/teller/api/v1/domain/TellerManagementCommand.java
+++ b/api/src/main/java/io/mifos/teller/api/v1/domain/TellerManagementCommand.java
@@ -27,12 +27,14 @@ public class TellerManagementCommand {
   }
 
   public enum Adjustment {
+    NONE,
     DEBIT,
     CREDIT
   }
 
   @NotNull
   private Action action;
+  @NotNull
   private Adjustment adjustment;
   private Double amount;
   @ValidIdentifier(optional = true)

-- 
To stop receiving notification emails like this one, please contact
myrle@apache.org.

[fineract-cn-teller] 22/30: check if employee is already assigned

Posted by my...@apache.org.
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-teller.git

commit 23688fb1f9002c562595d8ca23c7b20057980a80
Author: mgeiss <mg...@mifos.org>
AuthorDate: Wed Jun 28 17:45:06 2017 +0200

    check if employee is already assigned
---
 .../teller/service/internal/repository/TellerRepository.java   |  2 ++
 .../service/internal/service/TellerManagementService.java      |  4 ++++
 .../teller/service/rest/TellerManagementRestController.java    | 10 ++++++----
 3 files changed, 12 insertions(+), 4 deletions(-)

diff --git a/service/src/main/java/io/mifos/teller/service/internal/repository/TellerRepository.java b/service/src/main/java/io/mifos/teller/service/internal/repository/TellerRepository.java
index 530cb19..af5761e 100644
--- a/service/src/main/java/io/mifos/teller/service/internal/repository/TellerRepository.java
+++ b/service/src/main/java/io/mifos/teller/service/internal/repository/TellerRepository.java
@@ -27,4 +27,6 @@ public interface TellerRepository extends JpaRepository<TellerEntity, Long> {
   Optional<TellerEntity> findByIdentifier(final String identifier);
 
   List<TellerEntity> findByOfficeIdentifier(final String officeIdentifier);
+
+  Optional<TellerEntity> findFirstByAssignedEmployeeIdentifier(final String employeeIdentifier);
 }
diff --git a/service/src/main/java/io/mifos/teller/service/internal/service/TellerManagementService.java b/service/src/main/java/io/mifos/teller/service/internal/service/TellerManagementService.java
index c90d2ba..0a00d76 100644
--- a/service/src/main/java/io/mifos/teller/service/internal/service/TellerManagementService.java
+++ b/service/src/main/java/io/mifos/teller/service/internal/service/TellerManagementService.java
@@ -106,4 +106,8 @@ public class TellerManagementService {
 
     return tellerEntries;
   }
+
+  public Optional<Teller> findByAssignedEmployee(final String employeeIdentifier) {
+    return this.tellerRepository.findFirstByAssignedEmployeeIdentifier(employeeIdentifier).map(TellerMapper::map);
+  }
 }
diff --git a/service/src/main/java/io/mifos/teller/service/rest/TellerManagementRestController.java b/service/src/main/java/io/mifos/teller/service/rest/TellerManagementRestController.java
index 454d02c..4ff84cb 100644
--- a/service/src/main/java/io/mifos/teller/service/rest/TellerManagementRestController.java
+++ b/service/src/main/java/io/mifos/teller/service/rest/TellerManagementRestController.java
@@ -166,10 +166,6 @@ public class TellerManagementRestController {
                             @RequestBody @Valid final TellerManagementCommand tellerManagementCommand) {
     final Teller teller = this.verifyTeller(tellerCode);
 
-    if (tellerManagementCommand.getAmount() != null && tellerManagementCommand.getAmount() > teller.getCashdrawLimit()) {
-      throw ServiceException.badRequest("Adjustment exceeds cashdraw limit.");
-    }
-
     final TellerManagementCommand.Action action = TellerManagementCommand.Action.valueOf(tellerManagementCommand.getAction());
     switch (action) {
       case OPEN:
@@ -215,6 +211,12 @@ public class TellerManagementRestController {
   }
 
   private void verifyEmployee(final String employeeIdentifier) {
+    final Optional<Teller> optionalTeller = this.tellerManagementService.findByAssignedEmployee(employeeIdentifier);
+    if (optionalTeller.isPresent()) {
+      throw ServiceException.conflict("Employee {0} already assigned to teller {1}.",
+          employeeIdentifier, optionalTeller.get().getCode());
+    }
+
     if (!this.organizationService.employeeExists(employeeIdentifier)) {
       throw ServiceException.badRequest("Employee {0} not found.", employeeIdentifier);
     }

-- 
To stop receiving notification emails like this one, please contact
myrle@apache.org.

[fineract-cn-teller] 17/30: fixed bug when no charges are applied

Posted by my...@apache.org.
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-teller.git

commit d898f75d84076f801a3ba802e5f2622b3de1cc97
Author: mgeiss <mg...@mifos.org>
AuthorDate: Thu Jun 22 18:11:06 2017 +0200

    fixed bug when no charges are applied
---
 .../processor/TellerTransactionProcessor.java      | 24 +++++++++++++++-------
 1 file changed, 17 insertions(+), 7 deletions(-)

diff --git a/service/src/main/java/io/mifos/teller/service/internal/processor/TellerTransactionProcessor.java b/service/src/main/java/io/mifos/teller/service/internal/processor/TellerTransactionProcessor.java
index 64bda9c..7c62568 100644
--- a/service/src/main/java/io/mifos/teller/service/internal/processor/TellerTransactionProcessor.java
+++ b/service/src/main/java/io/mifos/teller/service/internal/processor/TellerTransactionProcessor.java
@@ -115,7 +115,11 @@ public class TellerTransactionProcessor {
 
     final Debtor debtor = new Debtor();
     debtor.setAccountNumber(tellerTransaction.getCustomerAccountIdentifier());
-    debtor.setAmount(tellerTransactionCosts.getTotalAmount().toString());
+    if (!tellerTransactionCosts.getCharges().isEmpty()) {
+      debtor.setAmount(tellerTransactionCosts.getTotalAmount().toString());
+    } else {
+      debtor.setAmount(tellerTransaction.getAmount().toString());
+    }
     debtors.add(debtor);
 
     final HashSet<Creditor> creditors = new HashSet<>();
@@ -150,11 +154,13 @@ public class TellerTransactionProcessor {
     tellerDebtor.setAmount(tellerTransaction.getAmount().toString());
     debtors.add(tellerDebtor);
 
-    final Double chargesTotal = tellerTransactionCosts.getTotalAmount() - tellerTransaction.getAmount();
-    final Debtor customerDebtor = new Debtor();
-    customerDebtor.setAccountNumber(tellerTransaction.getCustomerAccountIdentifier());
-    customerDebtor.setAmount(chargesTotal.toString());
-    debtors.add(customerDebtor);
+    if (!tellerTransactionCosts.getCharges().isEmpty()) {
+      final Double chargesTotal = tellerTransactionCosts.getTotalAmount() - tellerTransaction.getAmount();
+      final Debtor customerDebtor = new Debtor();
+      customerDebtor.setAccountNumber(tellerTransaction.getCustomerAccountIdentifier());
+      customerDebtor.setAmount(chargesTotal.toString());
+      debtors.add(customerDebtor);
+    }
 
     final HashSet<Creditor> creditors = new HashSet<>();
     journalEntry.setCreditors(creditors);
@@ -185,7 +191,11 @@ public class TellerTransactionProcessor {
 
     final Debtor customerDebtor = new Debtor();
     customerDebtor.setAccountNumber(tellerTransaction.getCustomerAccountIdentifier());
-    customerDebtor.setAmount(tellerTransactionCosts.getTotalAmount().toString());
+    if (!tellerTransactionCosts.getCharges().isEmpty()) {
+      customerDebtor.setAmount(tellerTransactionCosts.getTotalAmount().toString());
+    } else {
+      customerDebtor.setAmount(tellerTransaction.getAmount().toString());
+    }
     debtors.add(customerDebtor);
 
     final HashSet<Creditor> creditors = new HashSet<>();

-- 
To stop receiving notification emails like this one, please contact
myrle@apache.org.

[fineract-cn-teller] 01/30: initial commit

Posted by my...@apache.org.
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-teller.git

commit 2d306fc145da8403258ee01c07a9067afdfda9ff
Author: mgeiss <mg...@mifos.org>
AuthorDate: Wed Jun 7 07:53:42 2017 +0200

    initial commit
---
 .gitignore                                         |  16 ++
 HEADER                                             |  13 ++
 LICENSE                                            | 201 +++++++++++++++++++++
 README.md                                          |  66 +++++++
 api/build.gradle                                   |  39 ++++
 api/settings.gradle                                |   1 +
 .../main/java/io/mifos/teller/EventConstants.java  |  30 +++
 .../java/io/mifos/teller/PermittableGroupIds.java  |  22 +++
 .../client/TellerAlreadyExistsException.java       |   4 +
 .../java/io/mifos/teller/client/TellerManager.java | 153 ++++++++++++++++
 .../teller/client/TellerNotFoundException.java     |   4 +
 .../TellerTransactionValidationException.java      |   4 +
 .../teller/client/TellerValidationException.java   |   4 +
 .../main/java/io/mifos/teller/domain/Charge.java   |  36 ++++
 .../main/java/io/mifos/teller/domain/Teller.java   | 118 ++++++++++++
 .../mifos/teller/domain/TellerAuthentication.java  |  27 +++
 .../io/mifos/teller/domain/TellerBalanceSheet.java |  38 ++++
 .../java/io/mifos/teller/domain/TellerEntry.java   |  59 ++++++
 .../teller/domain/TellerManagementCommand.java     |  55 ++++++
 .../io/mifos/teller/domain/TellerTransaction.java  |  90 +++++++++
 .../teller/domain/TellerTransactionCosts.java      |  38 ++++
 build.gradle                                       |  36 ++++
 component-test/build.gradle                        |  38 ++++
 component-test/settings.gradle                     |   1 +
 component-test/src/main/resources/logback-test.xml |  32 ++++
 gradle/wrapper/gradle-wrapper.jar                  | Bin 0 -> 54212 bytes
 gradle/wrapper/gradle-wrapper.properties           |   6 +
 gradlew                                            | 172 ++++++++++++++++++
 gradlew.bat                                        |  84 +++++++++
 service/build.gradle                               |  63 +++++++
 service/settings.gradle                            |   1 +
 .../java/io/mifos/teller/ServiceConstants.java     |  20 ++
 .../java/io/mifos/teller/TellerApplication.java    |  29 +++
 .../java/io/mifos/teller/TellerConfiguration.java  |  71 ++++++++
 service/src/main/resources/application.yml         |  66 +++++++
 service/src/main/resources/bootstrap.yml           |  19 ++
 .../db/migrations/mariadb/V1__initial_setup.sql    |  22 +++
 settings.gradle                                    |   6 +
 shared.gradle                                      |  69 +++++++
 39 files changed, 1753 insertions(+)

diff --git a/.gitignore b/.gitignore
new file mode 100644
index 0000000..f9d7cba
--- /dev/null
+++ b/.gitignore
@@ -0,0 +1,16 @@
+.gradle
+.idea
+build/
+target/
+
+# Ignore Gradle GUI config
+gradle-app.setting
+
+# Avoid ignoring Gradle wrapper jar file (.jar files are usually ignored)
+!gradle-wrapper.jar
+
+*.iml
+
+*.log
+
+*.toDelete
diff --git a/HEADER b/HEADER
new file mode 100644
index 0000000..4b2eadf
--- /dev/null
+++ b/HEADER
@@ -0,0 +1,13 @@
+Copyright ${year} ${name}.
+
+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.
\ No newline at end of file
diff --git a/LICENSE b/LICENSE
new file mode 100644
index 0000000..8dada3e
--- /dev/null
+++ b/LICENSE
@@ -0,0 +1,201 @@
+                                 Apache License
+                           Version 2.0, January 2004
+                        http://www.apache.org/licenses/
+
+   TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION
+
+   1. Definitions.
+
+      "License" shall mean the terms and conditions for use, reproduction,
+      and distribution as defined by Sections 1 through 9 of this document.
+
+      "Licensor" shall mean the copyright owner or entity authorized by
+      the copyright owner that is granting the License.
+
+      "Legal Entity" shall mean the union of the acting entity and all
+      other entities that control, are controlled by, or are under common
+      control with that entity. For the purposes of this definition,
+      "control" means (i) the power, direct or indirect, to cause the
+      direction or management of such entity, whether by contract or
+      otherwise, or (ii) ownership of fifty percent (50%) or more of the
+      outstanding shares, or (iii) beneficial ownership of such entity.
+
+      "You" (or "Your") shall mean an individual or Legal Entity
+      exercising permissions granted by this License.
+
+      "Source" form shall mean the preferred form for making modifications,
+      including but not limited to software source code, documentation
+      source, and configuration files.
+
+      "Object" form shall mean any form resulting from mechanical
+      transformation or translation of a Source form, including but
+      not limited to compiled object code, generated documentation,
+      and conversions to other media types.
+
+      "Work" shall mean the work of authorship, whether in Source or
+      Object form, made available under the License, as indicated by a
+      copyright notice that is included in or attached to the work
+      (an example is provided in the Appendix below).
+
+      "Derivative Works" shall mean any work, whether in Source or Object
+      form, that is based on (or derived from) the Work and for which the
+      editorial revisions, annotations, elaborations, or other modifications
+      represent, as a whole, an original work of authorship. For the purposes
+      of this License, Derivative Works shall not include works that remain
+      separable from, or merely link (or bind by name) to the interfaces of,
+      the Work and Derivative Works thereof.
+
+      "Contribution" shall mean any work of authorship, including
+      the original version of the Work and any modifications or additions
+      to that Work or Derivative Works thereof, that is intentionally
+      submitted to Licensor for inclusion in the Work by the copyright owner
+      or by an individual or Legal Entity authorized to submit on behalf of
+      the copyright owner. For the purposes of this definition, "submitted"
+      means any form of electronic, verbal, or written communication sent
+      to the Licensor or its representatives, including but not limited to
+      communication on electronic mailing lists, source code control systems,
+      and issue tracking systems that are managed by, or on behalf of, the
+      Licensor for the purpose of discussing and improving the Work, but
+      excluding communication that is conspicuously marked or otherwise
+      designated in writing by the copyright owner as "Not a Contribution."
+
+      "Contributor" shall mean Licensor and any individual or Legal Entity
+      on behalf of whom a Contribution has been received by Licensor and
+      subsequently incorporated within the Work.
+
+   2. Grant of Copyright License. Subject to the terms and conditions of
+      this License, each Contributor hereby grants to You a perpetual,
+      worldwide, non-exclusive, no-charge, royalty-free, irrevocable
+      copyright license to reproduce, prepare Derivative Works of,
+      publicly display, publicly perform, sublicense, and distribute the
+      Work and such Derivative Works in Source or Object form.
+
+   3. Grant of Patent License. Subject to the terms and conditions of
+      this License, each Contributor hereby grants to You a perpetual,
+      worldwide, non-exclusive, no-charge, royalty-free, irrevocable
+      (except as stated in this section) patent license to make, have made,
+      use, offer to sell, sell, import, and otherwise transfer the Work,
+      where such license applies only to those patent claims licensable
+      by such Contributor that are necessarily infringed by their
+      Contribution(s) alone or by combination of their Contribution(s)
+      with the Work to which such Contribution(s) was submitted. If You
+      institute patent litigation against any entity (including a
+      cross-claim or counterclaim in a lawsuit) alleging that the Work
+      or a Contribution incorporated within the Work constitutes direct
+      or contributory patent infringement, then any patent licenses
+      granted to You under this License for that Work shall terminate
+      as of the date such litigation is filed.
+
+   4. Redistribution. You may reproduce and distribute copies of the
+      Work or Derivative Works thereof in any medium, with or without
+      modifications, and in Source or Object form, provided that You
+      meet the following conditions:
+
+      (a) You must give any other recipients of the Work or
+          Derivative Works a copy of this License; and
+
+      (b) You must cause any modified files to carry prominent notices
+          stating that You changed the files; and
+
+      (c) You must retain, in the Source form of any Derivative Works
+          that You distribute, all copyright, patent, trademark, and
+          attribution notices from the Source form of the Work,
+          excluding those notices that do not pertain to any part of
+          the Derivative Works; and
+
+      (d) If the Work includes a "NOTICE" text file as part of its
+          distribution, then any Derivative Works that You distribute must
+          include a readable copy of the attribution notices contained
+          within such NOTICE file, excluding those notices that do not
+          pertain to any part of the Derivative Works, in at least one
+          of the following places: within a NOTICE text file distributed
+          as part of the Derivative Works; within the Source form or
+          documentation, if provided along with the Derivative Works; or,
+          within a display generated by the Derivative Works, if and
+          wherever such third-party notices normally appear. The contents
+          of the NOTICE file are for informational purposes only and
+          do not modify the License. You may add Your own attribution
+          notices within Derivative Works that You distribute, alongside
+          or as an addendum to the NOTICE text from the Work, provided
+          that such additional attribution notices cannot be construed
+          as modifying the License.
+
+      You may add Your own copyright statement to Your modifications and
+      may provide additional or different license terms and conditions
+      for use, reproduction, or distribution of Your modifications, or
+      for any such Derivative Works as a whole, provided Your use,
+      reproduction, and distribution of the Work otherwise complies with
+      the conditions stated in this License.
+
+   5. Submission of Contributions. Unless You explicitly state otherwise,
+      any Contribution intentionally submitted for inclusion in the Work
+      by You to the Licensor shall be under the terms and conditions of
+      this License, without any additional terms or conditions.
+      Notwithstanding the above, nothing herein shall supersede or modify
+      the terms of any separate license agreement you may have executed
+      with Licensor regarding such Contributions.
+
+   6. Trademarks. This License does not grant permission to use the trade
+      names, trademarks, service marks, or product names of the Licensor,
+      except as required for reasonable and customary use in describing the
+      origin of the Work and reproducing the content of the NOTICE file.
+
+   7. Disclaimer of Warranty. Unless required by applicable law or
+      agreed to in writing, Licensor provides the Work (and each
+      Contributor provides its Contributions) on an "AS IS" BASIS,
+      WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
+      implied, including, without limitation, any warranties or conditions
+      of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A
+      PARTICULAR PURPOSE. You are solely responsible for determining the
+      appropriateness of using or redistributing the Work and assume any
+      risks associated with Your exercise of permissions under this License.
+
+   8. Limitation of Liability. In no event and under no legal theory,
+      whether in tort (including negligence), contract, or otherwise,
+      unless required by applicable law (such as deliberate and grossly
+      negligent acts) or agreed to in writing, shall any Contributor be
+      liable to You for damages, including any direct, indirect, special,
+      incidental, or consequential damages of any character arising as a
+      result of this License or out of the use or inability to use the
+      Work (including but not limited to damages for loss of goodwill,
+      work stoppage, computer failure or malfunction, or any and all
+      other commercial damages or losses), even if such Contributor
+      has been advised of the possibility of such damages.
+
+   9. Accepting Warranty or Additional Liability. While redistributing
+      the Work or Derivative Works thereof, You may choose to offer,
+      and charge a fee for, acceptance of support, warranty, indemnity,
+      or other liability obligations and/or rights consistent with this
+      License. However, in accepting such obligations, You may act only
+      on Your own behalf and on Your sole responsibility, not on behalf
+      of any other Contributor, and only if You agree to indemnify,
+      defend, and hold each Contributor harmless for any liability
+      incurred by, or claims asserted against, such Contributor by reason
+      of your accepting any such warranty or additional liability.
+
+   END OF TERMS AND CONDITIONS
+
+   APPENDIX: How to apply the Apache License to your work.
+
+      To apply the Apache License to your work, attach the following
+      boilerplate notice, with the fields enclosed by brackets "{}"
+      replaced with your own identifying information. (Don't include
+      the brackets!)  The text should be enclosed in the appropriate
+      comment syntax for the file format. We also recommend that a
+      file or class name and description of purpose be included on the
+      same "printed page" as the copyright notice for easier
+      identification within third-party archives.
+
+   Copyright {yyyy} {name of copyright owner}
+
+   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.
diff --git a/README.md b/README.md
new file mode 100644
index 0000000..1839633
--- /dev/null
+++ b/README.md
@@ -0,0 +1,66 @@
+# Mifos I/O Template
+
+[![Join the chat at https://gitter.im/mifos-initiative/mifos.io](https://badges.gitter.im/Join%20Chat.svg)](https://gitter.im/mifos-initiative/mifos.io?utm_source=badge&utm_medium=badge&utm_campaign=pr-badge&utm_content=badge)
+
+This project provides a template layout for all Mifos I/O microservices.
+
+## Abstract
+Mifos I/O is an application framework for digital financial services, a system to support nationwide and cross-national financial transactions and help to level and speed the creation of an inclusive, interconnected digital economy for every nation in the world.
+
+## Steps needed to turn the template project into a real project
+
+1.  Git clone template into {project name} folder
+
+        git clone https://github.com/mifosio/template.git {project name}
+
+2.  Delete _.git_
+
+        rm -rf .git
+    
+3.  Open settings.gradle and replace value of _rootProject.name_ with {project name}
+
+4.  Open root build.gradle and replace value of _version_ with 0.1.0-snapshot
+
+6.  Create Gradle wrapper
+
+        gradle wrapper
+
+6.  Open all module specific build.gradle files (api, service, and component-test) and replace value of _group_ with io.mifos.{project name}
+
+7.  Import project into IDE
+
+8.  Rename all io.mifos.template packages to io.mifos.{project name}
+
+9.  Open _SampleRestConfiguration_ and _SampleServiceConfiguration_, adjust @ComponentScan to reflect the new package name
+
+10. Open _application.yml_ and replace _server.contextPath_ with /{project name}/v1/*
+
+11. Open _bootstrap.yml_ and replace _spring.application.name_ with {project name}/v1/
+
+12. Open _SampleTest_ and replace constructor argument of TestEnvironment in line 80 with {project name}/v1/
+
+13. Run _SampleTest_
+
+14. Replace the contents of the README with text describing your new project.
+
+15. Happy coding! ; o) 
+
+## Versioning
+The version numbers follow the [Semantic Versioning](http://semver.org/) scheme.
+
+In addition to MAJOR.MINOR.PATCH the following postfixes are used to indicate the development state.
+
+* BUILD-SNAPSHOT - A release currently in development. 
+* M - A _milestone_ release include specific sets of functions and are released as soon as the functionality is complete.
+* RC - A _release candidate_ is a version with potential to be a final product, considered _code complete_.
+* RELEASE - _General availability_ indicates that this release is the best available version and is recommended for all usage.
+
+The versioning layout is {MAJOR}.{MINOR}.{PATCH}-{INDICATOR}[.{PATCH}]. Only milestones and release candidates can  have patch versions. Some examples:
+
+1.2.3.BUILD-SNAPSHOT  
+1.3.5.M.1  
+1.5.7.RC.2  
+2.0.0.RELEASE
+
+## License
+See [LICENSE](LICENSE) file.
diff --git a/api/build.gradle b/api/build.gradle
new file mode 100644
index 0000000..17c6648
--- /dev/null
+++ b/api/build.gradle
@@ -0,0 +1,39 @@
+buildscript {
+    repositories {
+        jcenter()
+    }
+
+    dependencies {
+        classpath 'io.spring.gradle:dependency-management-plugin:0.6.0.RELEASE'
+    }
+}
+
+plugins {
+    id "com.github.hierynomus.license" version "0.13.1"
+}
+
+apply from: '../shared.gradle'
+
+dependencies {
+    compile(
+            [group: 'org.springframework.cloud', name: 'spring-cloud-starter-feign'],
+            [group: 'io.mifos.core', name: 'api', version: versions.frameworkapi],
+            [group: 'org.hibernate', name: 'hibernate-validator', version: versions.validator],
+            [group: 'org.hibernate', name: 'hibernate-validator-annotation-processor', version: versions.validator]
+    )
+
+    testCompile(
+            [group: 'io.mifos.core', name: 'test', version: versions.frameworktest],
+    )
+}
+
+publishing {
+    publications {
+        api(MavenPublication) {
+            from components.java
+            groupId project.group
+            artifactId project.name
+            version project.version
+        }
+    }
+}
diff --git a/api/settings.gradle b/api/settings.gradle
new file mode 100644
index 0000000..7c8e3dc
--- /dev/null
+++ b/api/settings.gradle
@@ -0,0 +1 @@
+rootProject.name = 'api'
\ No newline at end of file
diff --git a/api/src/main/java/io/mifos/teller/EventConstants.java b/api/src/main/java/io/mifos/teller/EventConstants.java
new file mode 100644
index 0000000..f2a0d0b
--- /dev/null
+++ b/api/src/main/java/io/mifos/teller/EventConstants.java
@@ -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.
+ */
+package io.mifos.teller;
+
+@SuppressWarnings("unused")
+public interface EventConstants {
+
+  String DESTINATION = "teller-v1";
+
+  String SELECTOR_NAME = "operation";
+
+  String INITIALIZE = "initialize";
+  String SELECTOR_INITIALIZE = SELECTOR_NAME + " = '" + INITIALIZE + "'";
+
+  String POST_TELLER = "post-teller";
+  String SELECTOR_POST_TELLER = SELECTOR_NAME + " = '" + POST_TELLER + "'";
+}
diff --git a/api/src/main/java/io/mifos/teller/PermittableGroupIds.java b/api/src/main/java/io/mifos/teller/PermittableGroupIds.java
new file mode 100644
index 0000000..aff0c79
--- /dev/null
+++ b/api/src/main/java/io/mifos/teller/PermittableGroupIds.java
@@ -0,0 +1,22 @@
+/*
+ * 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.
+ */
+package io.mifos.teller;
+
+@SuppressWarnings("unused")
+public interface PermittableGroupIds {
+  String TELLER_MANAGEMENT = "teller__v1__management";
+  String TELLER_OPERATION = "teller__v1__operation";
+}
diff --git a/api/src/main/java/io/mifos/teller/client/TellerAlreadyExistsException.java b/api/src/main/java/io/mifos/teller/client/TellerAlreadyExistsException.java
new file mode 100644
index 0000000..28cf9aa
--- /dev/null
+++ b/api/src/main/java/io/mifos/teller/client/TellerAlreadyExistsException.java
@@ -0,0 +1,4 @@
+package io.mifos.teller.client;
+
+public class TellerAlreadyExistsException extends RuntimeException {
+}
diff --git a/api/src/main/java/io/mifos/teller/client/TellerManager.java b/api/src/main/java/io/mifos/teller/client/TellerManager.java
new file mode 100644
index 0000000..e392f28
--- /dev/null
+++ b/api/src/main/java/io/mifos/teller/client/TellerManager.java
@@ -0,0 +1,153 @@
+package io.mifos.teller.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.teller.domain.Teller;
+import io.mifos.teller.domain.TellerAuthentication;
+import io.mifos.teller.domain.TellerBalanceSheet;
+import io.mifos.teller.domain.TellerManagementCommand;
+import io.mifos.teller.domain.TellerTransaction;
+import io.mifos.teller.domain.TellerTransactionCosts;
+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 javax.validation.Valid;
+import java.util.List;
+
+@FeignClient(value = "teller-v1", path = "/teller/v1", configuration = CustomFeignClientsConfiguration.class)
+public interface TellerManager {
+
+  @RequestMapping(
+      value = "/management/{officeIdentifier}",
+      method = RequestMethod.POST,
+      consumes = MediaType.APPLICATION_JSON_VALUE,
+      produces = MediaType.APPLICATION_JSON_VALUE
+  )
+  @ThrowsExceptions({
+      @ThrowsException(status = HttpStatus.NOT_FOUND, exception = TellerNotFoundException.class),
+      @ThrowsException(status = HttpStatus.BAD_REQUEST, exception = TellerValidationException.class),
+      @ThrowsException(status = HttpStatus.CONFLICT, exception = TellerAlreadyExistsException.class)
+  })
+  void create(@PathVariable("officeIdentifier") final String officeIdentifier, @RequestBody @Valid final Teller teller);
+
+  @RequestMapping(
+      value = "/management/{officeIdentifier}/teller/{tellerCode}",
+      method = RequestMethod.GET,
+      consumes = MediaType.APPLICATION_JSON_VALUE,
+      produces = MediaType.ALL_VALUE
+  )
+  @ThrowsExceptions({
+      @ThrowsException(status = HttpStatus.NOT_FOUND, exception = TellerNotFoundException.class)
+  })
+  Teller find(@PathVariable("officeIdentifier") final String officeIdentifier,
+              @PathVariable("tellerCode") final String tellerCode);
+
+  @RequestMapping(
+      value = "/management/{officeIdentifier}/teller",
+      method = RequestMethod.GET,
+      consumes = MediaType.APPLICATION_JSON_VALUE,
+      produces = MediaType.ALL_VALUE
+  )
+  @ThrowsExceptions({
+      @ThrowsException(status = HttpStatus.NOT_FOUND, exception = TellerNotFoundException.class)
+  })
+  List<Teller> fetch(@PathVariable("officeIdentifier") final String officeIdentifier);
+
+  @RequestMapping(
+      value = "/management/{officeIdentifier}/teller/{tellerCode}",
+      method = RequestMethod.PUT,
+      consumes = MediaType.APPLICATION_JSON_VALUE,
+      produces = MediaType.APPLICATION_JSON_VALUE
+  )
+  @ThrowsExceptions({
+      @ThrowsException(status = HttpStatus.NOT_FOUND, exception = TellerNotFoundException.class),
+      @ThrowsException(status = HttpStatus.BAD_REQUEST, exception = TellerValidationException.class)
+  })
+  void change(@PathVariable("officeIdentifier") final String officeIdentifier,
+              @PathVariable("tellerCode") final String tellerCode,
+              @RequestBody @Valid final Teller teller);
+
+  @RequestMapping(
+      value = "/management/{officeIdentifier}/teller/{tellerCode}/commands",
+      method = RequestMethod.POST,
+      consumes = MediaType.APPLICATION_JSON_VALUE,
+      produces = MediaType.APPLICATION_JSON_VALUE
+  )
+  @ThrowsExceptions({
+      @ThrowsException(status = HttpStatus.NOT_FOUND, exception = TellerNotFoundException.class),
+      @ThrowsException(status = HttpStatus.BAD_REQUEST, exception = TellerValidationException.class)
+  })
+  void post(@PathVariable("officeIdentifier") final String officeIdentifier,
+            @PathVariable("tellerCode") final String tellerCode,
+            @RequestBody @Valid final TellerManagementCommand tellerManagementCommand);
+
+  @RequestMapping(
+      value = "/management/{officeIdentifier}/teller/{tellerCode}/balance",
+      method = RequestMethod.GET,
+      consumes = MediaType.APPLICATION_JSON_VALUE,
+      produces = MediaType.ALL_VALUE
+  )
+  @ThrowsExceptions({
+      @ThrowsException(status = HttpStatus.NOT_FOUND, exception = TellerNotFoundException.class)
+  })
+  TellerBalanceSheet getBalance(@PathVariable("officeIdentifier") final String officeIdentifier,
+                                @PathVariable("tellerCode") final String tellerCode);
+
+  @RequestMapping(
+      value = "/operations/{tellerCode}/auth",
+      method = RequestMethod.POST,
+      consumes = MediaType.APPLICATION_JSON_VALUE,
+      produces = MediaType.APPLICATION_JSON_VALUE
+  )
+  @ThrowsExceptions({
+      @ThrowsException(status = HttpStatus.NOT_FOUND, exception = TellerNotFoundException.class),
+      @ThrowsException(status = HttpStatus.BAD_REQUEST, exception = TellerNotFoundException.class)
+  })
+  void auth(@PathVariable("tellerCode") final String tellerCode,
+            @RequestBody @Valid final TellerAuthentication tellerAuthentication);
+
+  @RequestMapping(
+      value = "/operations/{tellerCode}",
+      method = RequestMethod.POST,
+      consumes = MediaType.APPLICATION_JSON_VALUE,
+      produces = MediaType.APPLICATION_JSON_VALUE
+  )
+  @ThrowsExceptions({
+      @ThrowsException(status = HttpStatus.NOT_FOUND, exception = TellerNotFoundException.class)
+  })
+  void post(@PathVariable("tellerCode") final String tellerCode,
+            @RequestParam(value = "command", required = true) final String command);
+
+  @RequestMapping(
+      value = "/operations/{tellerCode}/transactions",
+      method = RequestMethod.POST,
+      consumes = MediaType.APPLICATION_JSON_VALUE,
+      produces = MediaType.APPLICATION_JSON_VALUE
+  )
+  @ThrowsExceptions({
+      @ThrowsException(status = HttpStatus.NOT_FOUND, exception = TellerNotFoundException.class),
+      @ThrowsException(status = HttpStatus.BAD_REQUEST, exception = TellerTransactionValidationException.class)
+  })
+  TellerTransactionCosts post(@PathVariable("tellerCode") final String tellerCode,
+                              @RequestBody @Valid final TellerTransaction tellerTransaction);
+
+  @RequestMapping(
+      value = "/operations/{tellerCode}/transactions/{identifier}",
+      method = RequestMethod.POST,
+      consumes = MediaType.APPLICATION_JSON_VALUE,
+      produces = MediaType.APPLICATION_JSON_VALUE
+  )
+  @ThrowsExceptions({
+      @ThrowsException(status = HttpStatus.NOT_FOUND, exception = TellerNotFoundException.class)
+  })
+  void confirm(@PathVariable("tellerCode") final String tellerCode,
+               @PathVariable("identifier") final String tellerTransactionIdentifier,
+               @RequestParam(value = "command", required = true) final String command);
+}
diff --git a/api/src/main/java/io/mifos/teller/client/TellerNotFoundException.java b/api/src/main/java/io/mifos/teller/client/TellerNotFoundException.java
new file mode 100644
index 0000000..4334646
--- /dev/null
+++ b/api/src/main/java/io/mifos/teller/client/TellerNotFoundException.java
@@ -0,0 +1,4 @@
+package io.mifos.teller.client;
+
+public class TellerNotFoundException extends RuntimeException {
+}
diff --git a/api/src/main/java/io/mifos/teller/client/TellerTransactionValidationException.java b/api/src/main/java/io/mifos/teller/client/TellerTransactionValidationException.java
new file mode 100644
index 0000000..453b5d2
--- /dev/null
+++ b/api/src/main/java/io/mifos/teller/client/TellerTransactionValidationException.java
@@ -0,0 +1,4 @@
+package io.mifos.teller.client;
+
+public class TellerTransactionValidationException extends RuntimeException {
+}
diff --git a/api/src/main/java/io/mifos/teller/client/TellerValidationException.java b/api/src/main/java/io/mifos/teller/client/TellerValidationException.java
new file mode 100644
index 0000000..07f0be8
--- /dev/null
+++ b/api/src/main/java/io/mifos/teller/client/TellerValidationException.java
@@ -0,0 +1,4 @@
+package io.mifos.teller.client;
+
+public class TellerValidationException extends RuntimeException {
+}
diff --git a/api/src/main/java/io/mifos/teller/domain/Charge.java b/api/src/main/java/io/mifos/teller/domain/Charge.java
new file mode 100644
index 0000000..8f71964
--- /dev/null
+++ b/api/src/main/java/io/mifos/teller/domain/Charge.java
@@ -0,0 +1,36 @@
+package io.mifos.teller.domain;
+
+public class Charge {
+
+  private String code;
+  private String name;
+  private Double amount;
+
+  public Charge() {
+    super();
+  }
+
+  public String getCode() {
+    return this.code;
+  }
+
+  public void setCode(final String code) {
+    this.code = code;
+  }
+
+  public String getName() {
+    return this.name;
+  }
+
+  public void setName(final String name) {
+    this.name = name;
+  }
+
+  public Double getAmount() {
+    return this.amount;
+  }
+
+  public void setAmount(final Double amount) {
+    this.amount = amount;
+  }
+}
diff --git a/api/src/main/java/io/mifos/teller/domain/Teller.java b/api/src/main/java/io/mifos/teller/domain/Teller.java
new file mode 100644
index 0000000..688f37f
--- /dev/null
+++ b/api/src/main/java/io/mifos/teller/domain/Teller.java
@@ -0,0 +1,118 @@
+package io.mifos.teller.domain;
+
+import io.mifos.core.lang.validation.constraints.ValidIdentifier;
+import org.hibernate.validator.constraints.NotEmpty;
+
+import javax.validation.constraints.DecimalMin;
+import javax.validation.constraints.NotNull;
+
+public class Teller {
+
+  public enum Status {
+    ACTIVE,
+    CLOSED,
+    OPEN,
+    PAUSED
+  }
+
+  @ValidIdentifier
+  private String code;
+  @NotEmpty
+  private String password;
+  @NotNull
+  @DecimalMin("0.00")
+  private Double cashdrawLimit;
+  @ValidIdentifier
+  private String tellerAccountIdentifier;
+  @ValidIdentifier
+  private String vaultAccountIdentifier;
+  private String status;
+  private String createdBy;
+  private String createdOn;
+  private String lastModifiedBy;
+  private String lastModifiedOn;
+
+  public Teller() {
+    super();
+  }
+
+  public String getCode() {
+    return this.code;
+  }
+
+  public void setCode(final String code) {
+    this.code = code;
+  }
+
+  public String getPassword() {
+    return this.password;
+  }
+
+  public void setPassword(final String password) {
+    this.password = password;
+  }
+
+  public Double getCashdrawLimit() {
+    return this.cashdrawLimit;
+  }
+
+  public void setCashdrawLimit(final Double cashdrawLimit) {
+    this.cashdrawLimit = cashdrawLimit;
+  }
+
+  public String getTellerAccountIdentifier() {
+    return this.tellerAccountIdentifier;
+  }
+
+  public void setTellerAccountIdentifier(final String tellerAccountIdentifier) {
+    this.tellerAccountIdentifier = tellerAccountIdentifier;
+  }
+
+  public String getVaultAccountIdentifier() {
+    return this.vaultAccountIdentifier;
+  }
+
+  public void setVaultAccountIdentifier(final String vaultAccountIdentifier) {
+    this.vaultAccountIdentifier = vaultAccountIdentifier;
+  }
+
+  public String getStatus() {
+    return this.status;
+  }
+
+  public void setStatus(final String status) {
+    this.status = status;
+  }
+
+  public String getCreatedBy() {
+    return this.createdBy;
+  }
+
+  public void setCreatedBy(final String createdBy) {
+    this.createdBy = createdBy;
+  }
+
+  public String getCreatedOn() {
+    return this.createdOn;
+  }
+
+  public void setCreatedOn(final String createdOn) {
+    this.createdOn = createdOn;
+  }
+
+  public String getLastModifiedBy() {
+    return this.lastModifiedBy;
+  }
+
+  public void setLastModifiedBy(final String lastModifiedBy) {
+    this.lastModifiedBy = lastModifiedBy;
+  }
+
+  public String getLastModifiedOn() {
+    return this.lastModifiedOn;
+  }
+
+  public void setLastModifiedOn(final String lastModifiedOn) {
+    this.lastModifiedOn = lastModifiedOn;
+  }
+}
diff --git a/api/src/main/java/io/mifos/teller/domain/TellerAuthentication.java b/api/src/main/java/io/mifos/teller/domain/TellerAuthentication.java
new file mode 100644
index 0000000..135d73b
--- /dev/null
+++ b/api/src/main/java/io/mifos/teller/domain/TellerAuthentication.java
@@ -0,0 +1,27 @@
+package io.mifos.teller.domain;
+
+public class TellerAuthentication {
+
+  private String employeeIdentifier;
+  private String password;
+
+  public TellerAuthentication() {
+    super();
+  }
+
+  public String getEmployeeIdentifier() {
+    return this.employeeIdentifier;
+  }
+
+  public void setEmployeeIdentifier(final String employeeIdentifier) {
+    this.employeeIdentifier = employeeIdentifier;
+  }
+
+  public String getPassword() {
+    return this.password;
+  }
+
+  public void setPassword(final String password) {
+    this.password = password;
+  }
+}
diff --git a/api/src/main/java/io/mifos/teller/domain/TellerBalanceSheet.java b/api/src/main/java/io/mifos/teller/domain/TellerBalanceSheet.java
new file mode 100644
index 0000000..f46478c
--- /dev/null
+++ b/api/src/main/java/io/mifos/teller/domain/TellerBalanceSheet.java
@@ -0,0 +1,38 @@
+package io.mifos.teller.domain;
+
+import java.util.List;
+
+public class TellerBalanceSheet {
+
+  private String day;
+  private Double balance;
+  private List<TellerEntry> entries;
+
+  public TellerBalanceSheet() {
+    super();
+  }
+
+  public String getDay() {
+    return this.day;
+  }
+
+  public void setDay(final String day) {
+    this.day = day;
+  }
+
+  public Double getBalance() {
+    return this.balance;
+  }
+
+  public void setBalance(final Double balance) {
+    this.balance = balance;
+  }
+
+  public List<TellerEntry> getEntries() {
+    return this.entries;
+  }
+
+  public void setEntries(final List<TellerEntry> entries) {
+    this.entries = entries;
+  }
+}
diff --git a/api/src/main/java/io/mifos/teller/domain/TellerEntry.java b/api/src/main/java/io/mifos/teller/domain/TellerEntry.java
new file mode 100644
index 0000000..72535d3
--- /dev/null
+++ b/api/src/main/java/io/mifos/teller/domain/TellerEntry.java
@@ -0,0 +1,59 @@
+package io.mifos.teller.domain;
+
+public class TellerEntry {
+
+  public enum Type {
+    DEBIT,
+    CREDIT
+  }
+
+  private Type type;
+  private String transactionDate;
+  private String message;
+  private Double amount;
+  private Double balance;
+
+  public TellerEntry() {
+    super();
+  }
+
+  public String getType() {
+    return this.type.name();
+  }
+
+  public void setType(final String type) {
+    this.type = Type.valueOf(type);
+  }
+
+  public String getTransactionDate() {
+    return this.transactionDate;
+  }
+
+  public void setTransactionDate(final String transactionDate) {
+    this.transactionDate = transactionDate;
+  }
+
+  public String getMessage() {
+    return this.message;
+  }
+
+  public void setMessage(final String message) {
+    this.message = message;
+  }
+
+  public Double getAmount() {
+    return this.amount;
+  }
+
+  public void setAmount(final Double amount) {
+    this.amount = amount;
+  }
+
+  public Double getBalance() {
+    return this.balance;
+  }
+
+  public void setBalance(final Double balance) {
+    this.balance = balance;
+  }
+}
diff --git a/api/src/main/java/io/mifos/teller/domain/TellerManagementCommand.java b/api/src/main/java/io/mifos/teller/domain/TellerManagementCommand.java
new file mode 100644
index 0000000..41f29f5
--- /dev/null
+++ b/api/src/main/java/io/mifos/teller/domain/TellerManagementCommand.java
@@ -0,0 +1,55 @@
+package io.mifos.teller.domain;
+
+public class TellerManagementCommand {
+
+  public enum Action {
+    OPEN,
+    CLOSE
+  }
+
+  public enum Adjustment {
+    DEBIT,
+    CREDIT
+  }
+
+  private Action action;
+  private Adjustment adjustment;
+  private Double amount;
+  private String assignedEmployeeIdentifier;
+
+  public TellerManagementCommand() {
+    super();
+  }
+
+  public String getAction() {
+    return this.action.name();
+  }
+
+  public void setAction(final String action) {
+    this.action = Action.valueOf(action);
+  }
+
+  public String getAdjustment() {
+    return this.adjustment.name();
+  }
+
+  public void setAdjustment(final String adjustment) {
+    this.adjustment = Adjustment.valueOf(adjustment);
+  }
+
+  public Double getAmount() {
+    return this.amount;
+  }
+
+  public void setAmount(final Double amount) {
+    this.amount = amount;
+  }
+
+  public String getAssignedEmployeeIdentifier() {
+    return this.assignedEmployeeIdentifier;
+  }
+
+  public void setAssignedEmployeeIdentifier(final String assignedEmployeeIdentifier) {
+    this.assignedEmployeeIdentifier = assignedEmployeeIdentifier;
+  }
+}
diff --git a/api/src/main/java/io/mifos/teller/domain/TellerTransaction.java b/api/src/main/java/io/mifos/teller/domain/TellerTransaction.java
new file mode 100644
index 0000000..a00e7cc
--- /dev/null
+++ b/api/src/main/java/io/mifos/teller/domain/TellerTransaction.java
@@ -0,0 +1,90 @@
+package io.mifos.teller.domain;
+
+import io.mifos.core.lang.validation.constraints.ValidIdentifier;
+
+public class TellerTransaction {
+
+  public enum State {
+    PENDING,
+    CANCELED,
+    CONFIRMED
+  }
+
+  @ValidIdentifier(optional = true)
+  private String identifier;
+  private String transactionType;
+  private String transactionDate;
+  private String productIdentifier;
+  private String accountIdentifier;
+  private String clerk;
+  private Double amount;
+  private State state;
+
+  public TellerTransaction() {
+    super();
+  }
+
+  public String getIdentifier() {
+    return this.identifier;
+  }
+
+  public void setIdentifier(final String identifier) {
+    this.identifier = identifier;
+  }
+
+  public String getTransactionType() {
+    return this.transactionType;
+  }
+
+  public void setTransactionType(final String transactionType) {
+    this.transactionType = transactionType;
+  }
+
+  public String getTransactionDate() {
+    return this.transactionDate;
+  }
+
+  public void setTransactionDate(final String transactionDate) {
+    this.transactionDate = transactionDate;
+  }
+
+  public String getProductIdentifier() {
+    return this.productIdentifier;
+  }
+
+  public void setProductIdentifier(final String productIdentifier) {
+    this.productIdentifier = productIdentifier;
+  }
+
+  public String getAccountIdentifier() {
+    return this.accountIdentifier;
+  }
+
+  public void setAccountIdentifier(final String accountIdentifier) {
+    this.accountIdentifier = accountIdentifier;
+  }
+
+  public String getClerk() {
+    return this.clerk;
+  }
+
+  public void setClerk(final String clerk) {
+    this.clerk = clerk;
+  }
+
+  public Double getAmount() {
+    return this.amount;
+  }
+
+  public void setAmount(final Double amount) {
+    this.amount = amount;
+  }
+
+  public String getState() {
+    return this.state.name();
+  }
+
+  public void setState(final String state) {
+    this.state = State.valueOf(state);
+  }
+}
diff --git a/api/src/main/java/io/mifos/teller/domain/TellerTransactionCosts.java b/api/src/main/java/io/mifos/teller/domain/TellerTransactionCosts.java
new file mode 100644
index 0000000..ceb7348
--- /dev/null
+++ b/api/src/main/java/io/mifos/teller/domain/TellerTransactionCosts.java
@@ -0,0 +1,38 @@
+package io.mifos.teller.domain;
+
+import java.util.List;
+
+public class TellerTransactionCosts {
+
+  private String tellerTransactionIdentifier;
+  private Double totalAmount;
+  private List<Charge> charges;
+
+  public TellerTransactionCosts() {
+    super();
+  }
+
+  public String getTellerTransactionIdentifier() {
+    return this.tellerTransactionIdentifier;
+  }
+
+  public void setTellerTransactionIdentifier(final String tellerTransactionIdentifier) {
+    this.tellerTransactionIdentifier = tellerTransactionIdentifier;
+  }
+
+  public Double getTotalAmount() {
+    return this.totalAmount;
+  }
+
+  public void setTotalAmount(final Double totalAmount) {
+    this.totalAmount = totalAmount;
+  }
+
+  public List<Charge> getCharges() {
+    return this.charges;
+  }
+
+  public void setCharges(final List<Charge> charges) {
+    this.charges = charges;
+  }
+}
diff --git a/build.gradle b/build.gradle
new file mode 100644
index 0000000..b30bd55
--- /dev/null
+++ b/build.gradle
@@ -0,0 +1,36 @@
+group 'io.mifos'
+
+task publishApiToMavenLocal {
+    dependsOn gradle.includedBuild('api').task(':publishToMavenLocal')
+}
+
+task publishServiceToMavenLocal {
+    mustRunAfter publishApiToMavenLocal
+    dependsOn gradle.includedBuild('service').task(':publishToMavenLocal')
+}
+
+task publishComponentTestToMavenLocal {
+    mustRunAfter publishApiToMavenLocal
+    mustRunAfter publishServiceToMavenLocal
+    dependsOn gradle.includedBuild('component-test').task(':publishToMavenLocal')
+}
+
+task publishToMavenLocal {
+    group 'all'
+    dependsOn publishApiToMavenLocal
+    dependsOn publishServiceToMavenLocal
+    dependsOn publishComponentTestToMavenLocal
+}
+
+task prepareForTest {
+    group 'all'
+    dependsOn publishToMavenLocal
+    dependsOn gradle.includedBuild('component-test').task(':build')
+}
+
+task licenseFormat {
+    group 'all'
+    dependsOn gradle.includedBuild('api').task(':licenseFormat')
+    dependsOn gradle.includedBuild('service').task(':licenseFormat')
+    dependsOn gradle.includedBuild('component-test').task(':licenseFormat')
+}
diff --git a/component-test/build.gradle b/component-test/build.gradle
new file mode 100644
index 0000000..26359e5
--- /dev/null
+++ b/component-test/build.gradle
@@ -0,0 +1,38 @@
+buildscript {
+    ext {
+        springBootVersion = '1.4.1.RELEASE'
+    }
+
+    repositories {
+        jcenter()
+    }
+
+    dependencies {
+        classpath ("org.springframework.boot:spring-boot-gradle-plugin:${springBootVersion}")
+    }
+}
+
+plugins {
+    id "com.github.hierynomus.license" version "0.13.1"
+}
+apply from: '../shared.gradle'
+
+dependencies {
+    compile(
+            [group: 'io.mifos.teller', name: 'api', version: project.version],
+            [group: 'io.mifos.teller', name: 'service', version: project.version],
+            [group: 'io.mifos.anubis', name: 'test', version: versions.frameworkanubis],
+            [group: 'io.mifos.core', name: 'api', version: versions.frameworkapi],
+            [group: 'io.mifos.core', name: 'test', version: versions.frameworktest],
+            [group: 'io.mifos.core', name: 'lang', version: versions.frameworklang],
+            [group: 'org.springframework.boot', name: 'spring-boot-starter-test']
+    )
+}
+
+publishing {
+    publications {
+        mavenJava(MavenPublication) {
+            from components.java
+        }
+    }
+}
diff --git a/component-test/settings.gradle b/component-test/settings.gradle
new file mode 100644
index 0000000..07867cb
--- /dev/null
+++ b/component-test/settings.gradle
@@ -0,0 +1 @@
+rootProject.name = 'component-test'
\ No newline at end of file
diff --git a/component-test/src/main/resources/logback-test.xml b/component-test/src/main/resources/logback-test.xml
new file mode 100644
index 0000000..1d5c4e7
--- /dev/null
+++ b/component-test/src/main/resources/logback-test.xml
@@ -0,0 +1,32 @@
+<!--
+
+    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.
+
+-->
+<configuration>
+    <appender name="STDOUT" class="ch.qos.logback.core.ConsoleAppender">
+        <encoder>
+            <pattern>%d{HH:mm:ss.SSS} [%thread] %-5level %logger{36} - %msg%n</pattern>
+        </encoder>
+    </appender>
+
+    <logger name="org" level="OFF"/>
+    <logger name="com" level="OFF"/>
+    <logger name="ch" level="OFF"/>
+
+    <root level="DEBUG">
+        <appender-ref ref="STDOUT"/>
+    </root>
+</configuration>
\ No newline at end of file
diff --git a/gradle/wrapper/gradle-wrapper.jar b/gradle/wrapper/gradle-wrapper.jar
new file mode 100644
index 0000000..400f155
Binary files /dev/null and b/gradle/wrapper/gradle-wrapper.jar differ
diff --git a/gradle/wrapper/gradle-wrapper.properties b/gradle/wrapper/gradle-wrapper.properties
new file mode 100644
index 0000000..2888922
--- /dev/null
+++ b/gradle/wrapper/gradle-wrapper.properties
@@ -0,0 +1,6 @@
+#Fri Mar 17 17:54:20 CET 2017
+distributionBase=GRADLE_USER_HOME
+distributionPath=wrapper/dists
+zipStoreBase=GRADLE_USER_HOME
+zipStorePath=wrapper/dists
+distributionUrl=https\://services.gradle.org/distributions/gradle-3.4.1-bin.zip
diff --git a/gradlew b/gradlew
new file mode 100644
index 0000000..4453cce
--- /dev/null
+++ b/gradlew
@@ -0,0 +1,172 @@
+#!/usr/bin/env sh
+
+##############################################################################
+##
+##  Gradle start up script for UN*X
+##
+##############################################################################
+
+# Attempt to set APP_HOME
+# Resolve links: $0 may be a link
+PRG="$0"
+# Need this for relative symlinks.
+while [ -h "$PRG" ] ; do
+    ls=`ls -ld "$PRG"`
+    link=`expr "$ls" : '.*-> \(.*\)$'`
+    if expr "$link" : '/.*' > /dev/null; then
+        PRG="$link"
+    else
+        PRG=`dirname "$PRG"`"/$link"
+    fi
+done
+SAVED="`pwd`"
+cd "`dirname \"$PRG\"`/" >/dev/null
+APP_HOME="`pwd -P`"
+cd "$SAVED" >/dev/null
+
+APP_NAME="Gradle"
+APP_BASE_NAME=`basename "$0"`
+
+# Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script.
+DEFAULT_JVM_OPTS=""
+
+# Use the maximum available, or set MAX_FD != -1 to use that value.
+MAX_FD="maximum"
+
+warn ( ) {
+    echo "$*"
+}
+
+die ( ) {
+    echo
+    echo "$*"
+    echo
+    exit 1
+}
+
+# OS specific support (must be 'true' or 'false').
+cygwin=false
+msys=false
+darwin=false
+nonstop=false
+case "`uname`" in
+  CYGWIN* )
+    cygwin=true
+    ;;
+  Darwin* )
+    darwin=true
+    ;;
+  MINGW* )
+    msys=true
+    ;;
+  NONSTOP* )
+    nonstop=true
+    ;;
+esac
+
+CLASSPATH=$APP_HOME/gradle/wrapper/gradle-wrapper.jar
+
+# Determine the Java command to use to start the JVM.
+if [ -n "$JAVA_HOME" ] ; then
+    if [ -x "$JAVA_HOME/jre/sh/java" ] ; then
+        # IBM's JDK on AIX uses strange locations for the executables
+        JAVACMD="$JAVA_HOME/jre/sh/java"
+    else
+        JAVACMD="$JAVA_HOME/bin/java"
+    fi
+    if [ ! -x "$JAVACMD" ] ; then
+        die "ERROR: JAVA_HOME is set to an invalid directory: $JAVA_HOME
+
+Please set the JAVA_HOME variable in your environment to match the
+location of your Java installation."
+    fi
+else
+    JAVACMD="java"
+    which java >/dev/null 2>&1 || die "ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH.
+
+Please set the JAVA_HOME variable in your environment to match the
+location of your Java installation."
+fi
+
+# Increase the maximum file descriptors if we can.
+if [ "$cygwin" = "false" -a "$darwin" = "false" -a "$nonstop" = "false" ] ; then
+    MAX_FD_LIMIT=`ulimit -H -n`
+    if [ $? -eq 0 ] ; then
+        if [ "$MAX_FD" = "maximum" -o "$MAX_FD" = "max" ] ; then
+            MAX_FD="$MAX_FD_LIMIT"
+        fi
+        ulimit -n $MAX_FD
+        if [ $? -ne 0 ] ; then
+            warn "Could not set maximum file descriptor limit: $MAX_FD"
+        fi
+    else
+        warn "Could not query maximum file descriptor limit: $MAX_FD_LIMIT"
+    fi
+fi
+
+# For Darwin, add options to specify how the application appears in the dock
+if $darwin; then
+    GRADLE_OPTS="$GRADLE_OPTS \"-Xdock:name=$APP_NAME\" \"-Xdock:icon=$APP_HOME/media/gradle.icns\""
+fi
+
+# For Cygwin, switch paths to Windows format before running java
+if $cygwin ; then
+    APP_HOME=`cygpath --path --mixed "$APP_HOME"`
+    CLASSPATH=`cygpath --path --mixed "$CLASSPATH"`
+    JAVACMD=`cygpath --unix "$JAVACMD"`
+
+    # We build the pattern for arguments to be converted via cygpath
+    ROOTDIRSRAW=`find -L / -maxdepth 1 -mindepth 1 -type d 2>/dev/null`
+    SEP=""
+    for dir in $ROOTDIRSRAW ; do
+        ROOTDIRS="$ROOTDIRS$SEP$dir"
+        SEP="|"
+    done
+    OURCYGPATTERN="(^($ROOTDIRS))"
+    # Add a user-defined pattern to the cygpath arguments
+    if [ "$GRADLE_CYGPATTERN" != "" ] ; then
+        OURCYGPATTERN="$OURCYGPATTERN|($GRADLE_CYGPATTERN)"
+    fi
+    # Now convert the arguments - kludge to limit ourselves to /bin/sh
+    i=0
+    for arg in "$@" ; do
+        CHECK=`echo "$arg"|egrep -c "$OURCYGPATTERN" -`
+        CHECK2=`echo "$arg"|egrep -c "^-"`                                 ### Determine if an option
+
+        if [ $CHECK -ne 0 ] && [ $CHECK2 -eq 0 ] ; then                    ### Added a condition
+            eval `echo args$i`=`cygpath --path --ignore --mixed "$arg"`
+        else
+            eval `echo args$i`="\"$arg\""
+        fi
+        i=$((i+1))
+    done
+    case $i in
+        (0) set -- ;;
+        (1) set -- "$args0" ;;
+        (2) set -- "$args0" "$args1" ;;
+        (3) set -- "$args0" "$args1" "$args2" ;;
+        (4) set -- "$args0" "$args1" "$args2" "$args3" ;;
+        (5) set -- "$args0" "$args1" "$args2" "$args3" "$args4" ;;
+        (6) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" ;;
+        (7) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" ;;
+        (8) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" "$args7" ;;
+        (9) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" "$args7" "$args8" ;;
+    esac
+fi
+
+# Escape application args
+save ( ) {
+    for i do printf %s\\n "$i" | sed "s/'/'\\\\''/g;1s/^/'/;\$s/\$/' \\\\/" ; done
+    echo " "
+}
+APP_ARGS=$(save "$@")
+
+# Collect all arguments for the java command, following the shell quoting and substitution rules
+eval set -- $DEFAULT_JVM_OPTS $JAVA_OPTS $GRADLE_OPTS "\"-Dorg.gradle.appname=$APP_BASE_NAME\"" -classpath "\"$CLASSPATH\"" org.gradle.wrapper.GradleWrapperMain "$APP_ARGS"
+
+# by default we should be in the correct project dir, but when run from Finder on Mac, the cwd is wrong
+if [ "$(uname)" = "Darwin" ] && [ "$HOME" = "$PWD" ]; then
+  cd "$(dirname "$0")"
+fi
+
+exec "$JAVACMD" "$@"
diff --git a/gradlew.bat b/gradlew.bat
new file mode 100644
index 0000000..f955316
--- /dev/null
+++ b/gradlew.bat
@@ -0,0 +1,84 @@
+@if "%DEBUG%" == "" @echo off
+@rem ##########################################################################
+@rem
+@rem  Gradle startup script for Windows
+@rem
+@rem ##########################################################################
+
+@rem Set local scope for the variables with windows NT shell
+if "%OS%"=="Windows_NT" setlocal
+
+set DIRNAME=%~dp0
+if "%DIRNAME%" == "" set DIRNAME=.
+set APP_BASE_NAME=%~n0
+set APP_HOME=%DIRNAME%
+
+@rem Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script.
+set DEFAULT_JVM_OPTS=
+
+@rem Find java.exe
+if defined JAVA_HOME goto findJavaFromJavaHome
+
+set JAVA_EXE=java.exe
+%JAVA_EXE% -version >NUL 2>&1
+if "%ERRORLEVEL%" == "0" goto init
+
+echo.
+echo ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH.
+echo.
+echo Please set the JAVA_HOME variable in your environment to match the
+echo location of your Java installation.
+
+goto fail
+
+:findJavaFromJavaHome
+set JAVA_HOME=%JAVA_HOME:"=%
+set JAVA_EXE=%JAVA_HOME%/bin/java.exe
+
+if exist "%JAVA_EXE%" goto init
+
+echo.
+echo ERROR: JAVA_HOME is set to an invalid directory: %JAVA_HOME%
+echo.
+echo Please set the JAVA_HOME variable in your environment to match the
+echo location of your Java installation.
+
+goto fail
+
+:init
+@rem Get command-line arguments, handling Windows variants
+
+if not "%OS%" == "Windows_NT" goto win9xME_args
+
+:win9xME_args
+@rem Slurp the command line arguments.
+set CMD_LINE_ARGS=
+set _SKIP=2
+
+:win9xME_args_slurp
+if "x%~1" == "x" goto execute
+
+set CMD_LINE_ARGS=%*
+
+:execute
+@rem Setup the command line
+
+set CLASSPATH=%APP_HOME%\gradle\wrapper\gradle-wrapper.jar
+
+@rem Execute Gradle
+"%JAVA_EXE%" %DEFAULT_JVM_OPTS% %JAVA_OPTS% %GRADLE_OPTS% "-Dorg.gradle.appname=%APP_BASE_NAME%" -classpath "%CLASSPATH%" org.gradle.wrapper.GradleWrapperMain %CMD_LINE_ARGS%
+
+:end
+@rem End local scope for the variables with windows NT shell
+if "%ERRORLEVEL%"=="0" goto mainEnd
+
+:fail
+rem Set variable GRADLE_EXIT_CONSOLE if you need the _script_ return code instead of
+rem the _cmd.exe /c_ return code!
+if  not "" == "%GRADLE_EXIT_CONSOLE%" exit 1
+exit /b 1
+
+:mainEnd
+if "%OS%"=="Windows_NT" endlocal
+
+:omega
diff --git a/service/build.gradle b/service/build.gradle
new file mode 100644
index 0000000..a00147c
--- /dev/null
+++ b/service/build.gradle
@@ -0,0 +1,63 @@
+buildscript {
+    ext {
+        springBootVersion = '1.4.1.RELEASE'
+    }
+
+    repositories {
+        jcenter()
+    }
+
+    dependencies {
+        classpath ("org.springframework.boot:spring-boot-gradle-plugin:${springBootVersion}")
+    }
+}
+
+plugins {
+    id "com.github.hierynomus.license" version "0.13.1"
+}
+
+apply from: '../shared.gradle'
+
+apply plugin: 'spring-boot'
+
+springBoot {
+    executable = true
+    classifier = 'boot'
+}
+
+dependencies {
+    compile(
+            [group: 'org.springframework.cloud', name: 'spring-cloud-starter-config'],
+            [group: 'org.springframework.cloud', name: 'spring-cloud-starter-eureka'],
+            [group: 'org.springframework.boot', name: 'spring-boot-starter-jetty'],
+            [group: 'io.mifos.teller', name: 'api', version: project.version],
+            [group: 'io.mifos.anubis', name: 'library', version: versions.frameworkanubis],
+            [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],
+            [group: 'io.mifos.core', name: 'cassandra', version: versions.frameworkcassandra],
+            [group: 'io.mifos.core', name: 'mariadb', version: versions.frameworkmariadb],
+            [group: 'io.mifos.core', name: 'command', version: versions.frameworkcommand],
+            [group: 'org.hibernate', name: 'hibernate-validator', version: versions.validator]
+    )
+}
+
+publishToMavenLocal.dependsOn bootRepackage
+
+publishing {
+    publications {
+        service(MavenPublication) {
+            from components.java
+            groupId project.group
+            artifactId project.name
+            version project.version
+        }
+        bootService(MavenPublication) {
+            // "boot" jar
+            artifact ("$buildDir/libs/$project.name-$version-boot.jar")
+            groupId project.group
+            artifactId ("$project.name-boot")
+            version project.version
+        }
+    }
+}
diff --git a/service/settings.gradle b/service/settings.gradle
new file mode 100644
index 0000000..081feb4
--- /dev/null
+++ b/service/settings.gradle
@@ -0,0 +1 @@
+rootProject.name = 'service'
\ No newline at end of file
diff --git a/service/src/main/java/io/mifos/teller/ServiceConstants.java b/service/src/main/java/io/mifos/teller/ServiceConstants.java
new file mode 100644
index 0000000..98de3be
--- /dev/null
+++ b/service/src/main/java/io/mifos/teller/ServiceConstants.java
@@ -0,0 +1,20 @@
+/*
+ * 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.
+ */
+package io.mifos.teller;
+
+public interface ServiceConstants {
+  String LOGGER_NAME = "teller-logger";
+}
diff --git a/service/src/main/java/io/mifos/teller/TellerApplication.java b/service/src/main/java/io/mifos/teller/TellerApplication.java
new file mode 100644
index 0000000..fc32cc0
--- /dev/null
+++ b/service/src/main/java/io/mifos/teller/TellerApplication.java
@@ -0,0 +1,29 @@
+/*
+ * 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.
+ */
+package io.mifos.teller;
+
+import org.springframework.boot.SpringApplication;
+
+public class TellerApplication {
+
+  public TellerApplication() {
+    super();
+  }
+
+  public static void main(String[] args) {
+    SpringApplication.run(TellerConfiguration.class, args);
+  }
+}
diff --git a/service/src/main/java/io/mifos/teller/TellerConfiguration.java b/service/src/main/java/io/mifos/teller/TellerConfiguration.java
new file mode 100644
index 0000000..42b730a
--- /dev/null
+++ b/service/src/main/java/io/mifos/teller/TellerConfiguration.java
@@ -0,0 +1,71 @@
+/*
+ * 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.
+ */
+package io.mifos.teller;
+
+import io.mifos.anubis.config.EnableAnubis;
+import io.mifos.core.async.config.EnableAsync;
+import io.mifos.core.cassandra.config.EnableCassandra;
+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 org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+import org.springframework.boot.autoconfigure.EnableAutoConfiguration;
+import org.springframework.cloud.client.discovery.EnableDiscoveryClient;
+import org.springframework.context.annotation.Bean;
+import org.springframework.context.annotation.ComponentScan;
+import org.springframework.context.annotation.Configuration;
+import org.springframework.data.jpa.repository.config.EnableJpaRepositories;
+import org.springframework.web.servlet.config.annotation.PathMatchConfigurer;
+import org.springframework.web.servlet.config.annotation.WebMvcConfigurerAdapter;
+
+@SuppressWarnings("WeakerAccess")
+@Configuration
+@EnableAutoConfiguration
+@EnableDiscoveryClient
+@EnableAsync
+@EnableTenantContext
+@EnableCassandra
+@EnableMariaDB
+@EnableCommandProcessing
+@EnableAnubis
+@EnableServiceException
+@ComponentScan({
+    "io.mifos.teller.service.rest",
+    "io.mifos.teller.service.internal.service",
+    "io.mifos.teller.service.internal.repository",
+    "io.mifos.teller.service.internal.command.handler"
+})
+@EnableJpaRepositories({
+    "io.mifos.teller.service.internal.repository"
+})
+public class TellerConfiguration extends WebMvcConfigurerAdapter {
+
+  public TellerConfiguration() {
+    super();
+  }
+
+  @Bean(name = ServiceConstants.LOGGER_NAME)
+  public Logger logger() {
+    return LoggerFactory.getLogger(ServiceConstants.LOGGER_NAME);
+  }
+
+  @Override
+  public void configurePathMatch(final PathMatchConfigurer configurer) {
+    configurer.setUseSuffixPatternMatch(Boolean.FALSE);
+  }
+}
diff --git a/service/src/main/resources/application.yml b/service/src/main/resources/application.yml
new file mode 100644
index 0000000..5b2287e
--- /dev/null
+++ b/service/src/main/resources/application.yml
@@ -0,0 +1,66 @@
+#
+# 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.
+#
+
+spring:
+  cloud:
+    discovery:
+      enabled: false
+    config:
+      enabled: false
+
+eureka:
+  client:
+    serviceUrl:
+      defaultZone: http://localhost:8761/eureka/
+
+server:
+  port: 8081
+  contextPath: /teller/v1/*
+
+cassandra:
+  clusterName: staging_cluster
+  contactPoints: 127.0.0.1:9042,127.0.0.2:9042,127.0.0.3:9042
+  keyspace: seshat
+  cl:
+    read: LOCAL_QUORUM
+    write: LOCAL_QUORUM
+    delete: LOCAL_QUORUM
+
+mariadb:
+  driverClass: org.mariadb.jdbc.Driver
+  database: seshat
+  host: localhost
+  port: 3306
+  user: root
+  password: mysql
+
+bonecp:
+  idleMaxAgeInMinutes: 240
+  idleConnectionTestPeriodInMinutes: 60
+  maxConnectionsPerPartition: 10
+  minConnectionsPerPartition: 1
+  partitionCount: 2
+  acquireIncrement: 5
+  statementsCacheSize: 100
+
+async:
+  corePoolSize: 32
+  maxPoolSize: 16384
+  queueCapacity: 0
+  threadName: async-processor-
+
+flyway:
+  enabled: false
diff --git a/service/src/main/resources/bootstrap.yml b/service/src/main/resources/bootstrap.yml
new file mode 100644
index 0000000..38cdd09
--- /dev/null
+++ b/service/src/main/resources/bootstrap.yml
@@ -0,0 +1,19 @@
+#
+# 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.
+#
+
+spring:
+    application:
+        name: teller-v1
diff --git a/service/src/main/resources/db/migrations/mariadb/V1__initial_setup.sql b/service/src/main/resources/db/migrations/mariadb/V1__initial_setup.sql
new file mode 100644
index 0000000..fb1b54e
--- /dev/null
+++ b/service/src/main/resources/db/migrations/mariadb/V1__initial_setup.sql
@@ -0,0 +1,22 @@
+--
+-- 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 template_samples (
+  id BIGINT NOT NULL AUTO_INCREMENT,
+  identifier VARCHAR(8) NOT NULL,
+  payload VARCHAR(512) NULL,
+  CONSTRAINT template_samples_pk PRIMARY KEY (id)
+);
diff --git a/settings.gradle b/settings.gradle
new file mode 100644
index 0000000..2f30b21
--- /dev/null
+++ b/settings.gradle
@@ -0,0 +1,6 @@
+rootProject.name = 'teller'
+
+includeBuild 'api'
+includeBuild 'service'
+includeBuild 'component-test'
+
diff --git a/shared.gradle b/shared.gradle
new file mode 100644
index 0000000..81135ee
--- /dev/null
+++ b/shared.gradle
@@ -0,0 +1,69 @@
+group 'io.mifos.teller'
+version '0.1.0.BUILD-SNAPSHOT'
+
+ext.versions = [
+        frameworkapi : '0.1.0-BUILD-SNAPSHOT',
+        frameworklang : '0.1.0-BUILD-SNAPSHOT',
+        frameworkasync : '0.1.0-BUILD-SNAPSHOT',
+        frameworkcassandra : '0.1.0-BUILD-SNAPSHOT',
+        frameworkmariadb : '0.1.0-BUILD-SNAPSHOT',
+        frameworkcommand : '0.1.0-BUILD-SNAPSHOT',
+        frameworktest: '0.1.0-BUILD-SNAPSHOT',
+        frameworkanubis: '0.1.0-BUILD-SNAPSHOT',
+        validator : '5.3.0.Final'
+]
+
+apply plugin: 'java'
+apply plugin: 'idea'
+apply plugin: 'maven-publish'
+apply plugin: 'io.spring.dependency-management'
+
+tasks.withType(JavaCompile) {
+    sourceCompatibility = JavaVersion.VERSION_1_8
+    targetCompatibility = JavaVersion.VERSION_1_8
+}
+
+repositories {
+    jcenter()
+    mavenLocal()
+}
+
+dependencyManagement {
+    imports {
+        mavenBom 'io.spring.platform:platform-bom:Athens-RELEASE'
+        mavenBom 'org.springframework.cloud:spring-cloud-dependencies:Camden.SR1'
+    }
+}
+
+// override certain dependency provided by Spring platform using newer releases
+ext['cassandra.version'] = '3.6'
+ext['cassandra-driver.version'] = '3.1.2'
+ext['activemq.version'] = '5.13.2'
+ext['spring-data-releasetrain.version'] = 'Gosling-SR2A'
+
+dependencies {
+    compile(
+            [group: 'com.google.code.findbugs', name: 'jsr305']
+    )
+
+    testCompile(
+            [group: 'org.springframework.boot', name: 'spring-boot-starter-test']
+    )
+}
+
+jar {
+    from sourceSets.main.allSource
+}
+
+license {
+    header rootProject.file('../HEADER')
+    strictCheck true
+    mapping {
+        java = 'SLASHSTAR_STYLE'
+        xml = 'XML_STYLE'
+        yml = 'SCRIPT_STYLE'
+        yaml = 'SCRIPT_STYLE'
+    }
+    ext.year = Calendar.getInstance().get(Calendar.YEAR)
+    ext.name = 'The Mifos Initiative'
+}
\ No newline at end of file

-- 
To stop receiving notification emails like this one, please contact
myrle@apache.org.

[fineract-cn-teller] 26/30: Fixing (most of) the teller operation test so that I can be sure my changes aren't causing the failures.

Posted by my...@apache.org.
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-teller.git

commit 1cad446619ae630894d02d8f4bb80aa2cede7289
Author: Myrle Krantz <my...@apache.org>
AuthorDate: Tue Jul 11 12:33:15 2017 +0200

    Fixing (most of) the teller operation test so that I can be sure my changes aren't causing the failures.
---
 .../java/io/mifos/teller/TestTellerOperation.java  | 25 +++++++++++++---------
 1 file changed, 15 insertions(+), 10 deletions(-)

diff --git a/component-test/src/main/java/io/mifos/teller/TestTellerOperation.java b/component-test/src/main/java/io/mifos/teller/TestTellerOperation.java
index 98cbfbc..8e0e1ce 100644
--- a/component-test/src/main/java/io/mifos/teller/TestTellerOperation.java
+++ b/component-test/src/main/java/io/mifos/teller/TestTellerOperation.java
@@ -16,20 +16,14 @@
 package io.mifos.teller;
 
 import io.mifos.accounting.api.v1.domain.Account;
-import io.mifos.core.api.context.AutoUserContext;
 import io.mifos.core.lang.DateConverter;
 import io.mifos.deposit.api.v1.definition.domain.ProductDefinition;
 import io.mifos.deposit.api.v1.instance.domain.ProductInstance;
 import io.mifos.teller.api.v1.EventConstants;
 import io.mifos.teller.api.v1.client.TellerNotFoundException;
 import io.mifos.teller.api.v1.client.TellerTransactionValidationException;
-import io.mifos.teller.api.v1.client.TellerValidationException;
 import io.mifos.teller.api.v1.client.TransactionProcessingException;
-import io.mifos.teller.api.v1.domain.Teller;
-import io.mifos.teller.api.v1.domain.TellerManagementCommand;
-import io.mifos.teller.api.v1.domain.TellerTransaction;
-import io.mifos.teller.api.v1.domain.TellerTransactionCosts;
-import io.mifos.teller.api.v1.domain.UnlockDrawerCommand;
+import io.mifos.teller.api.v1.domain.*;
 import io.mifos.teller.util.TellerGenerator;
 import org.apache.commons.lang3.RandomStringUtils;
 import org.junit.Assert;
@@ -122,7 +116,9 @@ public class TestTellerOperation extends AbstractTellerTest {
     tellerTransaction.setClerk(AbstractTellerTest.TEST_USER);
     tellerTransaction.setAmount(1234.56D);
 
-    Mockito.doAnswer(invocation -> Optional.of(new Account()))
+    final Account account = new Account();
+    account.setState(Account.State.OPEN.name());
+    Mockito.doAnswer(invocation -> Optional.of(account))
         .when(super.accountingServiceSpy).findAccount(tellerTransaction.getCustomerAccountIdentifier());
     Mockito.doAnswer(invocation -> Collections.emptyList())
         .when(super.depositAccountManagementServiceSpy).getCharges(Matchers.eq(tellerTransaction));
@@ -155,6 +151,7 @@ public class TestTellerOperation extends AbstractTellerTest {
 
     final Account account = new Account();
     account.setBalance(2000.00D);
+    account.setState(Account.State.OPEN.name());
     Mockito.doAnswer(invocation -> Optional.of(account))
         .when(super.accountingServiceSpy).findAccount(tellerTransaction.getCustomerAccountIdentifier());
     Mockito.doAnswer(invocation -> Collections.emptyList())
@@ -189,6 +186,7 @@ public class TestTellerOperation extends AbstractTellerTest {
 
     final Account account = new Account();
     account.setBalance(2000.00D);
+    account.setState(Account.State.OPEN.name());
     Mockito.doAnswer(invocation -> Optional.of(account))
         .when(super.accountingServiceSpy).findAccount(tellerTransaction.getCustomerAccountIdentifier());
     Mockito.doAnswer(invocation -> Optional.of(new Account()))
@@ -222,7 +220,9 @@ public class TestTellerOperation extends AbstractTellerTest {
     tellerTransaction.setClerk(AbstractTellerTest.TEST_USER);
     tellerTransaction.setAmount(1234.56D);
 
-    Mockito.doAnswer(invocation -> Optional.of(new Account()))
+    final Account account = new Account();
+    account.setState(Account.State.OPEN.name());
+    Mockito.doAnswer(invocation -> Optional.of(account))
         .when(super.accountingServiceSpy).findAccount(tellerTransaction.getCustomerAccountIdentifier());
     Mockito.doAnswer(invocation -> Collections.emptyList())
         .when(super.depositAccountManagementServiceSpy).getCharges(Matchers.eq(tellerTransaction));
@@ -255,6 +255,7 @@ public class TestTellerOperation extends AbstractTellerTest {
 
     final Account account = new Account();
     account.setBalance(2000.00D);
+    account.setState(Account.State.OPEN.name());
     Mockito.doAnswer(invocation -> Optional.of(account))
         .when(super.accountingServiceSpy).findAccount(tellerTransaction.getCustomerAccountIdentifier());
     Mockito.doAnswer(invocation -> Collections.emptyList())
@@ -288,6 +289,7 @@ public class TestTellerOperation extends AbstractTellerTest {
 
     final Account account = new Account();
     account.setBalance(2000.00D);
+    account.setState(Account.State.OPEN.name());
     Mockito.doAnswer(invocation -> Optional.of(account))
         .when(super.accountingServiceSpy).findAccount(tellerTransaction.getCustomerAccountIdentifier());
     Mockito.doAnswer(invocation -> Collections.emptyList())
@@ -422,7 +424,9 @@ public class TestTellerOperation extends AbstractTellerTest {
     openAccountTransaction.setClerk(AbstractTellerTest.TEST_USER);
     openAccountTransaction.setAmount(1234.56D);
 
-    Mockito.doAnswer(invocation -> Optional.of(new Account()))
+    final Account accountA = new Account();
+    accountA.setState(Account.State.OPEN.name());
+    Mockito.doAnswer(invocation -> Optional.of(accountA))
         .when(super.accountingServiceSpy).findAccount(openAccountTransaction.getCustomerAccountIdentifier());
     Mockito.doAnswer(invocation -> Collections.emptyList())
         .when(super.depositAccountManagementServiceSpy).getCharges(Matchers.eq(openAccountTransaction));
@@ -444,6 +448,7 @@ public class TestTellerOperation extends AbstractTellerTest {
 
     final Account account = new Account();
     account.setBalance(1234.56D);
+    account.setState(Account.State.CLOSED.name());
 
     Mockito.doAnswer(invocation -> Optional.of(account))
         .when(super.accountingServiceSpy).findAccount(openAccountTransaction.getCustomerAccountIdentifier());

-- 
To stop receiving notification emails like this one, please contact
myrle@apache.org.

[fineract-cn-teller] 13/30: fixed missing debtor in tx processing

Posted by my...@apache.org.
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-teller.git

commit abdb227ed907e4b8b846833a90073ad801fcff70
Author: mgeiss <mg...@mifos.org>
AuthorDate: Wed Jun 14 16:45:22 2017 +0200

    fixed missing debtor in tx processing
---
 .../teller/service/internal/processor/TellerTransactionProcessor.java   | 2 ++
 1 file changed, 2 insertions(+)

diff --git a/service/src/main/java/io/mifos/teller/service/internal/processor/TellerTransactionProcessor.java b/service/src/main/java/io/mifos/teller/service/internal/processor/TellerTransactionProcessor.java
index e9c9329..64bda9c 100644
--- a/service/src/main/java/io/mifos/teller/service/internal/processor/TellerTransactionProcessor.java
+++ b/service/src/main/java/io/mifos/teller/service/internal/processor/TellerTransactionProcessor.java
@@ -154,6 +154,7 @@ public class TellerTransactionProcessor {
     final Debtor customerDebtor = new Debtor();
     customerDebtor.setAccountNumber(tellerTransaction.getCustomerAccountIdentifier());
     customerDebtor.setAmount(chargesTotal.toString());
+    debtors.add(customerDebtor);
 
     final HashSet<Creditor> creditors = new HashSet<>();
     journalEntry.setCreditors(creditors);
@@ -185,6 +186,7 @@ public class TellerTransactionProcessor {
     final Debtor customerDebtor = new Debtor();
     customerDebtor.setAccountNumber(tellerTransaction.getCustomerAccountIdentifier());
     customerDebtor.setAmount(tellerTransactionCosts.getTotalAmount().toString());
+    debtors.add(customerDebtor);
 
     final HashSet<Creditor> creditors = new HashSet<>();
     journalEntry.setCreditors(creditors);

-- 
To stop receiving notification emails like this one, please contact
myrle@apache.org.

[fineract-cn-teller] 25/30: fixed equal for account stats

Posted by my...@apache.org.
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-teller.git

commit 2cc1c5ce45d31acabcc0e9d785b3197fbc241399
Author: mgeiss <mg...@mifos.org>
AuthorDate: Sun Jul 9 03:05:10 2017 +0200

    fixed equal for account stats
---
 .../io/mifos/teller/service/rest/TellerOperationRestController.java     | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/service/src/main/java/io/mifos/teller/service/rest/TellerOperationRestController.java b/service/src/main/java/io/mifos/teller/service/rest/TellerOperationRestController.java
index 6295119..065dfa1 100644
--- a/service/src/main/java/io/mifos/teller/service/rest/TellerOperationRestController.java
+++ b/service/src/main/java/io/mifos/teller/service/rest/TellerOperationRestController.java
@@ -172,7 +172,7 @@ public class TellerOperationRestController {
     } else {
       final Account customerAccount = optionalCustomerAccount.get();
 
-      if (!customerAccount.getState().equals(Account.State.OPEN)) {
+      if (!customerAccount.getState().equals(Account.State.OPEN.name())) {
         throw ServiceException.conflict("Account {0} is not open.", customerAccount.getIdentifier());
       }
 

-- 
To stop receiving notification emails like this one, please contact
myrle@apache.org.

[fineract-cn-teller] 12/30: fixed missing customer identifier

Posted by my...@apache.org.
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-teller.git

commit b4bfdc176dc7f61fc18899b383ef88c3ed5412e0
Author: mgeiss <mg...@mifos.org>
AuthorDate: Wed Jun 14 15:12:46 2017 +0200

    fixed missing customer identifier
---
 .../service/internal/mapper/TellerTransactionMapper.java       |  2 ++
 .../service/internal/repository/TellerTransactionEntity.java   | 10 ++++++++++
 .../main/resources/db/migrations/mariadb/V1__initial_setup.sql |  1 +
 3 files changed, 13 insertions(+)

diff --git a/service/src/main/java/io/mifos/teller/service/internal/mapper/TellerTransactionMapper.java b/service/src/main/java/io/mifos/teller/service/internal/mapper/TellerTransactionMapper.java
index 1073219..9677376 100644
--- a/service/src/main/java/io/mifos/teller/service/internal/mapper/TellerTransactionMapper.java
+++ b/service/src/main/java/io/mifos/teller/service/internal/mapper/TellerTransactionMapper.java
@@ -30,6 +30,7 @@ public class TellerTransactionMapper {
     tellerTransaction.setIdentifier(tellerTransactionEntity.getIdentifier());
     tellerTransaction.setTransactionType(tellerTransactionEntity.getTransactionType());
     tellerTransaction.setTransactionDate(DateConverter.toIsoString(tellerTransactionEntity.getTransactionDate()));
+    tellerTransaction.setCustomerIdentifier(tellerTransactionEntity.getCustomerIdentifier());
     tellerTransaction.setProductIdentifier(tellerTransactionEntity.getProductIdentifier());
     tellerTransaction.setProductCaseIdentifier(tellerTransactionEntity.getProductCaseIdentifier());
     tellerTransaction.setCustomerAccountIdentifier(tellerTransactionEntity.getCustomerAccountIdentifier());
@@ -46,6 +47,7 @@ public class TellerTransactionMapper {
     tellerTransactionEntity.setIdentifier(tellerTransaction.getIdentifier());
     tellerTransactionEntity.setTransactionType(tellerTransaction.getTransactionType());
     tellerTransactionEntity.setTransactionDate(DateConverter.fromIsoString(tellerTransaction.getTransactionDate()));
+    tellerTransactionEntity.setCustomerIdentifier(tellerTransaction.getCustomerIdentifier());
     tellerTransactionEntity.setProductIdentifier(tellerTransaction.getProductIdentifier());
     tellerTransactionEntity.setProductCaseIdentifier(tellerTransaction.getProductCaseIdentifier());
     tellerTransactionEntity.setCustomerAccountIdentifier(tellerTransaction.getCustomerAccountIdentifier());
diff --git a/service/src/main/java/io/mifos/teller/service/internal/repository/TellerTransactionEntity.java b/service/src/main/java/io/mifos/teller/service/internal/repository/TellerTransactionEntity.java
index f880906..9d15e01 100644
--- a/service/src/main/java/io/mifos/teller/service/internal/repository/TellerTransactionEntity.java
+++ b/service/src/main/java/io/mifos/teller/service/internal/repository/TellerTransactionEntity.java
@@ -48,6 +48,8 @@ public class TellerTransactionEntity {
   @Column(name = "transaction_date", nullable = false)
   @Convert(converter = LocalDateTimeConverter.class)
   private LocalDateTime transactionDate;
+  @Column(name = "customer_identifier", nullable = false, length = 32)
+  private String customerIdentifier;
   @Column(name = "product_identifier", nullable = false, length = 32)
   private String productIdentifier;
   @Column(name = "product_case_identifier", nullable = true, length = 32)
@@ -107,6 +109,14 @@ public class TellerTransactionEntity {
     this.transactionDate = transactionDate;
   }
 
+  public String getCustomerIdentifier() {
+    return this.customerIdentifier;
+  }
+
+  public void setCustomerIdentifier(final String customerIdentifier) {
+    this.customerIdentifier = customerIdentifier;
+  }
+
   public String getProductIdentifier() {
     return this.productIdentifier;
   }
diff --git a/service/src/main/resources/db/migrations/mariadb/V1__initial_setup.sql b/service/src/main/resources/db/migrations/mariadb/V1__initial_setup.sql
index 5b4556d..9f3a24b 100644
--- a/service/src/main/resources/db/migrations/mariadb/V1__initial_setup.sql
+++ b/service/src/main/resources/db/migrations/mariadb/V1__initial_setup.sql
@@ -39,6 +39,7 @@ CREATE TABLE tajet_teller_transactions (
   identifier                  VARCHAR(32)    NOT NULL,
   transaction_type            VARCHAR(32)    NOT NULL,
   transaction_date            TIMESTAMP(3)   NOT NULL,
+  customer_identifier         VARCHAR(32)    NOT NULL,
   product_identifier          VARCHAR(32)    NOT NULL,
   product_case_identifier     VARCHAR(32)    NULL,
   customer_account_identifier VARCHAR(32)    NOT NULL,

-- 
To stop receiving notification emails like this one, please contact
myrle@apache.org.

[fineract-cn-teller] 10/30: retrofitted password field

Posted by my...@apache.org.
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-teller.git

commit 2d7e458f327315c47968a469e652fbf2b8008d41
Author: mgeiss <mg...@mifos.org>
AuthorDate: Wed Jun 14 11:33:03 2017 +0200

    retrofitted password field
---
 .../teller/api/v1/domain/TellerAuthentication.java     |  6 +++---
 .../main/java/io/mifos/teller/TestTellerOperation.java | 18 +++++++++---------
 .../internal/command/handler/TellerAggregate.java      |  2 +-
 3 files changed, 13 insertions(+), 13 deletions(-)

diff --git a/api/src/main/java/io/mifos/teller/api/v1/domain/TellerAuthentication.java b/api/src/main/java/io/mifos/teller/api/v1/domain/TellerAuthentication.java
index dbd6bc4..60bc7fd 100644
--- a/api/src/main/java/io/mifos/teller/api/v1/domain/TellerAuthentication.java
+++ b/api/src/main/java/io/mifos/teller/api/v1/domain/TellerAuthentication.java
@@ -18,7 +18,7 @@ package io.mifos.teller.api.v1.domain;
 public class TellerAuthentication {
 
   private String employeeIdentifier;
-  private byte[] password;
+  private String password;
 
   public TellerAuthentication() {
     super();
@@ -32,11 +32,11 @@ public class TellerAuthentication {
     this.employeeIdentifier = employeeIdentifier;
   }
 
-  public byte[] getPassword() {
+  public String getPassword() {
     return this.password;
   }
 
-  public void setPassword(final byte[] password) {
+  public void setPassword(final String password) {
     this.password = password;
   }
 }
diff --git a/component-test/src/main/java/io/mifos/teller/TestTellerOperation.java b/component-test/src/main/java/io/mifos/teller/TestTellerOperation.java
index 39b7ed3..1c6edd7 100644
--- a/component-test/src/main/java/io/mifos/teller/TestTellerOperation.java
+++ b/component-test/src/main/java/io/mifos/teller/TestTellerOperation.java
@@ -46,7 +46,7 @@ public class TestTellerOperation extends AbstractTellerTest {
 
     final TellerAuthentication tellerAuthentication = new TellerAuthentication();
     tellerAuthentication.setEmployeeIdentifier(AbstractTellerTest.TEST_USER);
-    tellerAuthentication.setPassword(teller.getPassword().getBytes());
+    tellerAuthentication.setPassword(teller.getPassword());
 
     final String auth = super.testSubject.auth(teller.getCode(), tellerAuthentication);
 
@@ -60,7 +60,7 @@ public class TestTellerOperation extends AbstractTellerTest {
 
     final TellerAuthentication tellerAuthentication = new TellerAuthentication();
     tellerAuthentication.setEmployeeIdentifier("unassigneduser");
-    tellerAuthentication.setPassword(teller.getPassword().getBytes());
+    tellerAuthentication.setPassword(teller.getPassword());
 
     super.testSubject.auth(teller.getCode(), tellerAuthentication);
   }
@@ -71,7 +71,7 @@ public class TestTellerOperation extends AbstractTellerTest {
 
     final TellerAuthentication tellerAuthentication = new TellerAuthentication();
     tellerAuthentication.setEmployeeIdentifier(AbstractTellerTest.TEST_USER);
-    tellerAuthentication.setPassword("wrongpasword".getBytes());
+    tellerAuthentication.setPassword("wrongpasword");
 
     super.testSubject.auth(teller.getCode(), tellerAuthentication);
   }
@@ -82,7 +82,7 @@ public class TestTellerOperation extends AbstractTellerTest {
 
     final TellerAuthentication tellerAuthentication = new TellerAuthentication();
     tellerAuthentication.setEmployeeIdentifier(AbstractTellerTest.TEST_USER);
-    tellerAuthentication.setPassword(teller.getPassword().getBytes());
+    tellerAuthentication.setPassword(teller.getPassword());
 
     super.testSubject.auth(teller.getCode(), tellerAuthentication);
 
@@ -106,7 +106,7 @@ public class TestTellerOperation extends AbstractTellerTest {
 
     final TellerAuthentication tellerAuthentication = new TellerAuthentication();
     tellerAuthentication.setEmployeeIdentifier(AbstractTellerTest.TEST_USER);
-    tellerAuthentication.setPassword(teller.getPassword().getBytes());
+    tellerAuthentication.setPassword(teller.getPassword());
 
     super.testSubject.auth(teller.getCode(), tellerAuthentication);
 
@@ -137,7 +137,7 @@ public class TestTellerOperation extends AbstractTellerTest {
 
     final TellerAuthentication tellerAuthentication = new TellerAuthentication();
     tellerAuthentication.setEmployeeIdentifier(AbstractTellerTest.TEST_USER);
-    tellerAuthentication.setPassword(teller.getPassword().getBytes());
+    tellerAuthentication.setPassword(teller.getPassword());
 
     super.testSubject.auth(teller.getCode(), tellerAuthentication);
 
@@ -168,7 +168,7 @@ public class TestTellerOperation extends AbstractTellerTest {
 
     final TellerAuthentication tellerAuthentication = new TellerAuthentication();
     tellerAuthentication.setEmployeeIdentifier(AbstractTellerTest.TEST_USER);
-    tellerAuthentication.setPassword(teller.getPassword().getBytes());
+    tellerAuthentication.setPassword(teller.getPassword());
 
     super.testSubject.auth(teller.getCode(), tellerAuthentication);
 
@@ -202,7 +202,7 @@ public class TestTellerOperation extends AbstractTellerTest {
 
     final TellerAuthentication tellerAuthentication = new TellerAuthentication();
     tellerAuthentication.setEmployeeIdentifier(AbstractTellerTest.TEST_USER);
-    tellerAuthentication.setPassword(teller.getPassword().getBytes());
+    tellerAuthentication.setPassword(teller.getPassword());
 
     super.testSubject.auth(teller.getCode(), tellerAuthentication);
 
@@ -233,7 +233,7 @@ public class TestTellerOperation extends AbstractTellerTest {
 
     final TellerAuthentication tellerAuthentication = new TellerAuthentication();
     tellerAuthentication.setEmployeeIdentifier(AbstractTellerTest.TEST_USER);
-    tellerAuthentication.setPassword(teller.getPassword().getBytes());
+    tellerAuthentication.setPassword(teller.getPassword());
 
     super.testSubject.auth(teller.getCode(), tellerAuthentication);
 
diff --git a/service/src/main/java/io/mifos/teller/service/internal/command/handler/TellerAggregate.java b/service/src/main/java/io/mifos/teller/service/internal/command/handler/TellerAggregate.java
index 60abcb2..56e5b64 100644
--- a/service/src/main/java/io/mifos/teller/service/internal/command/handler/TellerAggregate.java
+++ b/service/src/main/java/io/mifos/teller/service/internal/command/handler/TellerAggregate.java
@@ -224,7 +224,7 @@ public class TellerAggregate {
         throw ServiceException.notFound("Teller {0} not found.", tellerCode);
       }
 
-      final byte[] givenPassword = this.hashGenerator.hash(new String(tellerAuthentication.getPassword()),
+      final byte[] givenPassword = this.hashGenerator.hash(tellerAuthentication.getPassword(),
           Base64Utils.decodeFromString(tellerEntity.getSalt()), ServiceConstants.ITERATION_COUNT, ServiceConstants.LENGTH);
 
       if (!tellerEntity.getPassword().equals(Base64Utils.encodeToString(givenPassword))) {

-- 
To stop receiving notification emails like this one, please contact
myrle@apache.org.

[fineract-cn-teller] 19/30: added verification for balance and cash draw limit

Posted by my...@apache.org.
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-teller.git

commit 71839a17fb6e181e6a3af0f44e5dce6418433b25
Author: mgeiss <mg...@mifos.org>
AuthorDate: Sun Jun 25 19:10:20 2017 +0200

    added verification for balance and cash draw limit
---
 .../mifos/teller/api/v1/client/TellerManager.java  |   5 +-
 .../v1/client/TransactionProcessingException.java  |  19 +++
 .../java/io/mifos/teller/TestTellerManagement.java | 122 ++++++++++----------
 .../java/io/mifos/teller/TestTellerOperation.java  | 128 ++++++++++++++++-----
 .../internal/command/handler/TellerAggregate.java  |   8 +-
 .../processor/TellerTransactionProcessor.java      |  22 ++--
 .../internal/service/helper/AccountingService.java |  10 +-
 .../helper/DepositAccountManagementService.java    |  10 +-
 .../rest/TellerManagementRestController.java       |   2 +-
 .../rest/TellerOperationRestController.java        |  30 ++++-
 10 files changed, 244 insertions(+), 112 deletions(-)

diff --git a/api/src/main/java/io/mifos/teller/api/v1/client/TellerManager.java b/api/src/main/java/io/mifos/teller/api/v1/client/TellerManager.java
index 3f3a9b2..6a965e6 100644
--- a/api/src/main/java/io/mifos/teller/api/v1/client/TellerManager.java
+++ b/api/src/main/java/io/mifos/teller/api/v1/client/TellerManager.java
@@ -19,11 +19,11 @@ import io.mifos.core.api.annotation.ThrowsException;
 import io.mifos.core.api.annotation.ThrowsExceptions;
 import io.mifos.core.api.util.CustomFeignClientsConfiguration;
 import io.mifos.teller.api.v1.domain.Teller;
-import io.mifos.teller.api.v1.domain.UnlockDrawerCommand;
 import io.mifos.teller.api.v1.domain.TellerBalanceSheet;
 import io.mifos.teller.api.v1.domain.TellerManagementCommand;
 import io.mifos.teller.api.v1.domain.TellerTransaction;
 import io.mifos.teller.api.v1.domain.TellerTransactionCosts;
+import io.mifos.teller.api.v1.domain.UnlockDrawerCommand;
 import org.springframework.cloud.netflix.feign.FeignClient;
 import org.springframework.http.HttpStatus;
 import org.springframework.http.MediaType;
@@ -152,7 +152,8 @@ public interface TellerManager {
   )
   @ThrowsExceptions({
       @ThrowsException(status = HttpStatus.NOT_FOUND, exception = TellerNotFoundException.class),
-      @ThrowsException(status = HttpStatus.BAD_REQUEST, exception = TellerTransactionValidationException.class)
+      @ThrowsException(status = HttpStatus.BAD_REQUEST, exception = TellerTransactionValidationException.class),
+      @ThrowsException(status = HttpStatus.CONFLICT, exception = TransactionProcessingException.class)
   })
   TellerTransactionCosts post(@PathVariable("tellerCode") final String tellerCode,
                               @RequestBody @Valid final TellerTransaction tellerTransaction);
diff --git a/api/src/main/java/io/mifos/teller/api/v1/client/TransactionProcessingException.java b/api/src/main/java/io/mifos/teller/api/v1/client/TransactionProcessingException.java
new file mode 100644
index 0000000..f36274f
--- /dev/null
+++ b/api/src/main/java/io/mifos/teller/api/v1/client/TransactionProcessingException.java
@@ -0,0 +1,19 @@
+/*
+ * 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.
+ */
+package io.mifos.teller.api.v1.client;
+
+public class TransactionProcessingException extends RuntimeException {
+}
diff --git a/component-test/src/main/java/io/mifos/teller/TestTellerManagement.java b/component-test/src/main/java/io/mifos/teller/TestTellerManagement.java
index ca28069..83611e2 100644
--- a/component-test/src/main/java/io/mifos/teller/TestTellerManagement.java
+++ b/component-test/src/main/java/io/mifos/teller/TestTellerManagement.java
@@ -15,6 +15,7 @@
  */
 package io.mifos.teller;
 
+import io.mifos.accounting.api.v1.domain.Account;
 import io.mifos.teller.api.v1.EventConstants;
 import io.mifos.teller.api.v1.client.TellerAlreadyExistsException;
 import io.mifos.teller.api.v1.client.TellerNotFoundException;
@@ -30,6 +31,7 @@ import org.mockito.Mockito;
 
 import java.util.Arrays;
 import java.util.List;
+import java.util.Optional;
 
 public class TestTellerManagement extends AbstractTellerTest {
 
@@ -45,11 +47,11 @@ public class TestTellerManagement extends AbstractTellerTest {
     Mockito.doAnswer(invocation -> true)
         .when(super.organizationServiceSpy).officeExists(Matchers.eq(officeIdentifier));
 
-    Mockito.doAnswer(invocation -> true)
-        .when(super.accountingServiceSpy).accountExists(Matchers.eq(teller.getTellerAccountIdentifier()));
+    Mockito.doAnswer(invocation -> Optional.of(new Account()))
+        .when(super.accountingServiceSpy).findAccount(Matchers.eq(teller.getTellerAccountIdentifier()));
 
-    Mockito.doAnswer(invocation -> true)
-        .when(super.accountingServiceSpy).accountExists(Matchers.eq(teller.getVaultAccountIdentifier()));
+    Mockito.doAnswer(invocation -> Optional.of(new Account()))
+        .when(super.accountingServiceSpy).findAccount(Matchers.eq(teller.getVaultAccountIdentifier()));
 
     super.testSubject.create(officeIdentifier, teller);
 
@@ -72,8 +74,8 @@ public class TestTellerManagement extends AbstractTellerTest {
     final String officeIdentifier = RandomStringUtils.randomAlphabetic(32);
     final Teller teller = TellerGenerator.createRandomTeller();
 
-    Mockito.doAnswer(invocation -> false)
-        .when(super.accountingServiceSpy).accountExists(Matchers.eq(teller.getTellerAccountIdentifier()));
+    Mockito.doAnswer(invocation -> Optional.empty())
+        .when(super.accountingServiceSpy).findAccount(Matchers.eq(teller.getTellerAccountIdentifier()));
 
     super.testSubject.create(officeIdentifier, teller);
   }
@@ -83,8 +85,8 @@ public class TestTellerManagement extends AbstractTellerTest {
     final String officeIdentifier = RandomStringUtils.randomAlphabetic(32);
     final Teller teller = TellerGenerator.createRandomTeller();
 
-    Mockito.doAnswer(invocation -> false)
-        .when(super.accountingServiceSpy).accountExists(Matchers.eq(teller.getVaultAccountIdentifier()));
+    Mockito.doAnswer(invocation -> Optional.empty())
+        .when(super.accountingServiceSpy).findAccount(Matchers.eq(teller.getVaultAccountIdentifier()));
 
     super.testSubject.create(officeIdentifier, teller);
   }
@@ -98,11 +100,11 @@ public class TestTellerManagement extends AbstractTellerTest {
     Mockito.doAnswer(invocation -> true)
         .when(super.organizationServiceSpy).officeExists(Matchers.eq(officeIdentifier));
 
-    Mockito.doAnswer(invocation -> true)
-        .when(super.accountingServiceSpy).accountExists(Matchers.eq(teller.getTellerAccountIdentifier()));
+    Mockito.doAnswer(invocation -> Optional.of(new Account()))
+        .when(super.accountingServiceSpy).findAccount(Matchers.eq(teller.getTellerAccountIdentifier()));
 
-    Mockito.doAnswer(invocation -> true)
-        .when(super.accountingServiceSpy).accountExists(Matchers.eq(teller.getVaultAccountIdentifier()));
+    Mockito.doAnswer(invocation -> Optional.of(new Account()))
+        .when(super.accountingServiceSpy).findAccount(Matchers.eq(teller.getVaultAccountIdentifier()));
 
     super.testSubject.create(officeIdentifier, teller);
 
@@ -119,11 +121,11 @@ public class TestTellerManagement extends AbstractTellerTest {
     Mockito.doAnswer(invocation -> true)
         .when(super.organizationServiceSpy).officeExists(Matchers.eq(officeIdentifier));
 
-    Mockito.doAnswer(invocation -> true)
-        .when(super.accountingServiceSpy).accountExists(Matchers.eq(teller.getTellerAccountIdentifier()));
+    Mockito.doAnswer(invocation -> Optional.of(new Account()))
+        .when(super.accountingServiceSpy).findAccount(Matchers.eq(teller.getTellerAccountIdentifier()));
 
-    Mockito.doAnswer(invocation -> true)
-        .when(super.accountingServiceSpy).accountExists(Matchers.eq(teller.getVaultAccountIdentifier()));
+    Mockito.doAnswer(invocation -> Optional.of(new Account()))
+        .when(super.accountingServiceSpy).findAccount(Matchers.eq(teller.getVaultAccountIdentifier()));
 
     super.testSubject.create(officeIdentifier, teller);
 
@@ -172,11 +174,11 @@ public class TestTellerManagement extends AbstractTellerTest {
         .when(super.organizationServiceSpy).officeExists(Matchers.eq(officeIdentifier));
 
     tellerToCreate.forEach(teller -> {
-      Mockito.doAnswer(invocation -> true)
-          .when(super.accountingServiceSpy).accountExists(Matchers.eq(teller.getTellerAccountIdentifier()));
+      Mockito.doAnswer(invocation -> Optional.of(new Account()))
+          .when(super.accountingServiceSpy).findAccount(Matchers.eq(teller.getTellerAccountIdentifier()));
 
-      Mockito.doAnswer(invocation -> true)
-          .when(super.accountingServiceSpy).accountExists(Matchers.eq(teller.getVaultAccountIdentifier()));
+      Mockito.doAnswer(invocation -> Optional.of(new Account()))
+          .when(super.accountingServiceSpy).findAccount(Matchers.eq(teller.getVaultAccountIdentifier()));
 
       super.testSubject.create(officeIdentifier, teller);
 
@@ -210,11 +212,11 @@ public class TestTellerManagement extends AbstractTellerTest {
     Mockito.doAnswer(invocation -> true)
         .when(super.organizationServiceSpy).officeExists(Matchers.eq(officeIdentifier));
 
-    Mockito.doAnswer(invocation -> true)
-        .when(super.accountingServiceSpy).accountExists(Matchers.eq(teller.getTellerAccountIdentifier()));
+    Mockito.doAnswer(invocation -> Optional.of(new Account()))
+        .when(super.accountingServiceSpy).findAccount(Matchers.eq(teller.getTellerAccountIdentifier()));
 
-    Mockito.doAnswer(invocation -> true)
-        .when(super.accountingServiceSpy).accountExists(Matchers.eq(teller.getVaultAccountIdentifier()));
+    Mockito.doAnswer(invocation -> Optional.of(new Account()))
+        .when(super.accountingServiceSpy).findAccount(Matchers.eq(teller.getVaultAccountIdentifier()));
 
     super.testSubject.create(officeIdentifier, teller);
 
@@ -240,11 +242,11 @@ public class TestTellerManagement extends AbstractTellerTest {
     Mockito.doAnswer(invocation -> true)
         .when(super.organizationServiceSpy).officeExists(Matchers.eq(officeIdentifier));
 
-    Mockito.doAnswer(invocation -> true)
-        .when(super.accountingServiceSpy).accountExists(Matchers.eq(teller.getTellerAccountIdentifier()));
+    Mockito.doAnswer(invocation -> Optional.of(new Account()))
+        .when(super.accountingServiceSpy).findAccount(Matchers.eq(teller.getTellerAccountIdentifier()));
 
-    Mockito.doAnswer(invocation -> true)
-        .when(super.accountingServiceSpy).accountExists(Matchers.eq(teller.getVaultAccountIdentifier()));
+    Mockito.doAnswer(invocation -> Optional.of(new Account()))
+        .when(super.accountingServiceSpy).findAccount(Matchers.eq(teller.getVaultAccountIdentifier()));
 
     super.testSubject.create(officeIdentifier, teller);
 
@@ -264,11 +266,11 @@ public class TestTellerManagement extends AbstractTellerTest {
     Mockito.doAnswer(invocation -> true)
         .when(super.organizationServiceSpy).officeExists(Matchers.eq(officeIdentifier));
 
-    Mockito.doAnswer(invocation -> true)
-        .when(super.accountingServiceSpy).accountExists(Matchers.eq(teller.getTellerAccountIdentifier()));
+    Mockito.doAnswer(invocation -> Optional.of(new Account()))
+        .when(super.accountingServiceSpy).findAccount(Matchers.eq(teller.getTellerAccountIdentifier()));
 
-    Mockito.doAnswer(invocation -> true)
-        .when(super.accountingServiceSpy).accountExists(Matchers.eq(teller.getVaultAccountIdentifier()));
+    Mockito.doAnswer(invocation -> Optional.of(new Account()))
+        .when(super.accountingServiceSpy).findAccount(Matchers.eq(teller.getVaultAccountIdentifier()));
 
     super.testSubject.create(officeIdentifier, teller);
 
@@ -276,8 +278,8 @@ public class TestTellerManagement extends AbstractTellerTest {
 
     teller.setTellerAccountIdentifier(RandomStringUtils.randomAlphanumeric(32));
 
-    Mockito.doAnswer(invocation -> false)
-        .when(super.accountingServiceSpy).accountExists(Matchers.eq(teller.getTellerAccountIdentifier()));
+    Mockito.doAnswer(invocation -> Optional.empty())
+        .when(super.accountingServiceSpy).findAccount(Matchers.eq(teller.getTellerAccountIdentifier()));
 
     super.testSubject.change(officeIdentifier, teller.getCode(), teller);
   }
@@ -290,11 +292,11 @@ public class TestTellerManagement extends AbstractTellerTest {
     Mockito.doAnswer(invocation -> true)
         .when(super.organizationServiceSpy).officeExists(Matchers.eq(officeIdentifier));
 
-    Mockito.doAnswer(invocation -> true)
-        .when(super.accountingServiceSpy).accountExists(Matchers.eq(teller.getTellerAccountIdentifier()));
+    Mockito.doAnswer(invocation -> Optional.of(new Account()))
+        .when(super.accountingServiceSpy).findAccount(Matchers.eq(teller.getTellerAccountIdentifier()));
 
-    Mockito.doAnswer(invocation -> true)
-        .when(super.accountingServiceSpy).accountExists(Matchers.eq(teller.getVaultAccountIdentifier()));
+    Mockito.doAnswer(invocation -> Optional.of(new Account()))
+        .when(super.accountingServiceSpy).findAccount(Matchers.eq(teller.getVaultAccountIdentifier()));
 
     super.testSubject.create(officeIdentifier, teller);
 
@@ -302,8 +304,8 @@ public class TestTellerManagement extends AbstractTellerTest {
 
     teller.setVaultAccountIdentifier(RandomStringUtils.randomAlphanumeric(32));
 
-    Mockito.doAnswer(invocation -> false)
-        .when(super.accountingServiceSpy).accountExists(Matchers.eq(teller.getVaultAccountIdentifier()));
+    Mockito.doAnswer(invocation -> Optional.empty())
+        .when(super.accountingServiceSpy).findAccount(Matchers.eq(teller.getVaultAccountIdentifier()));
 
     super.testSubject.change(officeIdentifier, teller.getCode(), teller);
   }
@@ -318,11 +320,11 @@ public class TestTellerManagement extends AbstractTellerTest {
     Mockito.doAnswer(invocation -> true)
         .when(super.organizationServiceSpy).officeExists(Matchers.eq(officeIdentifier));
 
-    Mockito.doAnswer(invocation -> true)
-        .when(super.accountingServiceSpy).accountExists(Matchers.eq(teller.getTellerAccountIdentifier()));
+    Mockito.doAnswer(invocation -> Optional.of(new Account()))
+        .when(super.accountingServiceSpy).findAccount(Matchers.eq(teller.getTellerAccountIdentifier()));
 
-    Mockito.doAnswer(invocation -> true)
-        .when(super.accountingServiceSpy).accountExists(Matchers.eq(teller.getVaultAccountIdentifier()));
+    Mockito.doAnswer(invocation -> Optional.of(new Account()))
+        .when(super.accountingServiceSpy).findAccount(Matchers.eq(teller.getVaultAccountIdentifier()));
 
     super.testSubject.create(officeIdentifier, teller);
 
@@ -349,11 +351,11 @@ public class TestTellerManagement extends AbstractTellerTest {
     Mockito.doAnswer(invocation -> true)
         .when(super.organizationServiceSpy).officeExists(Matchers.eq(officeIdentifier));
 
-    Mockito.doAnswer(invocation -> true)
-        .when(super.accountingServiceSpy).accountExists(Matchers.eq(teller.getTellerAccountIdentifier()));
+    Mockito.doAnswer(invocation -> Optional.of(new Account()))
+        .when(super.accountingServiceSpy).findAccount(Matchers.eq(teller.getTellerAccountIdentifier()));
 
-    Mockito.doAnswer(invocation -> true)
-        .when(super.accountingServiceSpy).accountExists(Matchers.eq(teller.getVaultAccountIdentifier()));
+    Mockito.doAnswer(invocation -> Optional.of(new Account()))
+        .when(super.accountingServiceSpy).findAccount(Matchers.eq(teller.getVaultAccountIdentifier()));
 
     super.testSubject.create(officeIdentifier, teller);
 
@@ -384,11 +386,11 @@ public class TestTellerManagement extends AbstractTellerTest {
     Mockito.doAnswer(invocation -> true)
         .when(super.organizationServiceSpy).officeExists(Matchers.eq(officeIdentifier));
 
-    Mockito.doAnswer(invocation -> true)
-        .when(super.accountingServiceSpy).accountExists(Matchers.eq(teller.getTellerAccountIdentifier()));
+    Mockito.doAnswer(invocation -> Optional.of(new Account()))
+        .when(super.accountingServiceSpy).findAccount(Matchers.eq(teller.getTellerAccountIdentifier()));
 
-    Mockito.doAnswer(invocation -> true)
-        .when(super.accountingServiceSpy).accountExists(Matchers.eq(teller.getVaultAccountIdentifier()));
+    Mockito.doAnswer(invocation -> Optional.of(new Account()))
+        .when(super.accountingServiceSpy).findAccount(Matchers.eq(teller.getVaultAccountIdentifier()));
 
     super.testSubject.create(officeIdentifier, teller);
 
@@ -425,11 +427,11 @@ public class TestTellerManagement extends AbstractTellerTest {
     Mockito.doAnswer(invocation -> true)
         .when(super.organizationServiceSpy).officeExists(Matchers.eq(officeIdentifier));
 
-    Mockito.doAnswer(invocation -> true)
-        .when(super.accountingServiceSpy).accountExists(Matchers.eq(teller.getTellerAccountIdentifier()));
+    Mockito.doAnswer(invocation -> Optional.of(new Account()))
+        .when(super.accountingServiceSpy).findAccount(Matchers.eq(teller.getTellerAccountIdentifier()));
 
-    Mockito.doAnswer(invocation -> true)
-        .when(super.accountingServiceSpy).accountExists(Matchers.eq(teller.getVaultAccountIdentifier()));
+    Mockito.doAnswer(invocation -> Optional.of(new Account()))
+        .when(super.accountingServiceSpy).findAccount(Matchers.eq(teller.getVaultAccountIdentifier()));
 
     super.testSubject.create(officeIdentifier, teller);
 
@@ -450,11 +452,11 @@ public class TestTellerManagement extends AbstractTellerTest {
     Mockito.doAnswer(invocation -> true)
         .when(super.organizationServiceSpy).officeExists(Matchers.eq(officeIdentifier));
 
-    Mockito.doAnswer(invocation -> true)
-        .when(super.accountingServiceSpy).accountExists(Matchers.eq(teller.getTellerAccountIdentifier()));
+    Mockito.doAnswer(invocation -> Optional.of(new Account()))
+        .when(super.accountingServiceSpy).findAccount(Matchers.eq(teller.getTellerAccountIdentifier()));
 
-    Mockito.doAnswer(invocation -> true)
-        .when(super.accountingServiceSpy).accountExists(Matchers.eq(teller.getVaultAccountIdentifier()));
+    Mockito.doAnswer(invocation -> Optional.of(new Account()))
+        .when(super.accountingServiceSpy).findAccount(Matchers.eq(teller.getVaultAccountIdentifier()));
 
     super.testSubject.create(officeIdentifier, teller);
 
diff --git a/component-test/src/main/java/io/mifos/teller/TestTellerOperation.java b/component-test/src/main/java/io/mifos/teller/TestTellerOperation.java
index 18589cf..7d3e1da 100644
--- a/component-test/src/main/java/io/mifos/teller/TestTellerOperation.java
+++ b/component-test/src/main/java/io/mifos/teller/TestTellerOperation.java
@@ -15,14 +15,16 @@
  */
 package io.mifos.teller;
 
+import io.mifos.accounting.api.v1.domain.Account;
 import io.mifos.core.lang.DateConverter;
 import io.mifos.teller.api.v1.EventConstants;
 import io.mifos.teller.api.v1.client.TellerNotFoundException;
 import io.mifos.teller.api.v1.client.TellerValidationException;
+import io.mifos.teller.api.v1.client.TransactionProcessingException;
 import io.mifos.teller.api.v1.domain.Teller;
-import io.mifos.teller.api.v1.domain.UnlockDrawerCommand;
 import io.mifos.teller.api.v1.domain.TellerManagementCommand;
 import io.mifos.teller.api.v1.domain.TellerTransaction;
+import io.mifos.teller.api.v1.domain.UnlockDrawerCommand;
 import io.mifos.teller.util.TellerGenerator;
 import org.apache.commons.lang3.RandomStringUtils;
 import org.junit.Assert;
@@ -33,6 +35,7 @@ import org.mockito.Mockito;
 import java.time.Clock;
 import java.time.LocalDateTime;
 import java.util.Collections;
+import java.util.Optional;
 
 public class TestTellerOperation extends AbstractTellerTest {
 
@@ -119,12 +122,12 @@ public class TestTellerOperation extends AbstractTellerTest {
     tellerTransaction.setClerk(AbstractTellerTest.TEST_USER);
     tellerTransaction.setAmount(1234.56D);
 
-    Mockito.doAnswer(invocation -> true)
-        .when(super.accountingServiceSpy).accountExists(tellerTransaction.getCustomerAccountIdentifier());
+    Mockito.doAnswer(invocation -> Optional.of(new Account()))
+        .when(super.accountingServiceSpy).findAccount(tellerTransaction.getCustomerAccountIdentifier());
     Mockito.doAnswer(invocation -> Collections.emptyList())
         .when(super.depositAccountManagementServiceSpy).getCharges(Matchers.eq(tellerTransaction));
     Mockito.doAnswer(invocation -> Collections.emptyList())
-        .when(super.depositAccountManagementServiceSpy).getProductInstance(tellerTransaction.getCustomerIdentifier());
+        .when(super.depositAccountManagementServiceSpy).fetchProductInstances(tellerTransaction.getCustomerIdentifier());
 
     super.testSubject.post(teller.getCode(), tellerTransaction);
   }
@@ -150,12 +153,14 @@ public class TestTellerOperation extends AbstractTellerTest {
     tellerTransaction.setClerk(AbstractTellerTest.TEST_USER);
     tellerTransaction.setAmount(1234.56D);
 
-    Mockito.doAnswer(invocation -> true)
-        .when(super.accountingServiceSpy).accountExists(tellerTransaction.getCustomerAccountIdentifier());
+    final Account account = new Account();
+    account.setBalance(2000.00D);
+    Mockito.doAnswer(invocation -> Optional.of(account))
+        .when(super.accountingServiceSpy).findAccount(tellerTransaction.getCustomerAccountIdentifier());
     Mockito.doAnswer(invocation -> Collections.emptyList())
         .when(super.depositAccountManagementServiceSpy).getCharges(Matchers.eq(tellerTransaction));
     Mockito.doAnswer(invocation -> Collections.emptyList())
-        .when(super.depositAccountManagementServiceSpy).getProductInstance(tellerTransaction.getCustomerIdentifier());
+        .when(super.depositAccountManagementServiceSpy).fetchProductInstances(tellerTransaction.getCustomerIdentifier());
 
     super.testSubject.post(teller.getCode(), tellerTransaction);
   }
@@ -182,14 +187,16 @@ public class TestTellerOperation extends AbstractTellerTest {
     tellerTransaction.setClerk(AbstractTellerTest.TEST_USER);
     tellerTransaction.setAmount(1234.56D);
 
-    Mockito.doAnswer(invocation -> true)
-        .when(super.accountingServiceSpy).accountExists(tellerTransaction.getCustomerAccountIdentifier());
-    Mockito.doAnswer(invocation -> true)
-        .when(super.accountingServiceSpy).accountExists(tellerTransaction.getTargetAccountIdentifier());
+    final Account account = new Account();
+    account.setBalance(2000.00D);
+    Mockito.doAnswer(invocation -> Optional.of(account))
+        .when(super.accountingServiceSpy).findAccount(tellerTransaction.getCustomerAccountIdentifier());
+    Mockito.doAnswer(invocation -> Optional.of(new Account()))
+        .when(super.accountingServiceSpy).findAccount(tellerTransaction.getTargetAccountIdentifier());
     Mockito.doAnswer(invocation -> Collections.emptyList())
         .when(super.depositAccountManagementServiceSpy).getCharges(Matchers.eq(tellerTransaction));
     Mockito.doAnswer(invocation -> Collections.emptyList())
-        .when(super.depositAccountManagementServiceSpy).getProductInstance(tellerTransaction.getCustomerIdentifier());
+        .when(super.depositAccountManagementServiceSpy).fetchProductInstances(tellerTransaction.getCustomerIdentifier());
 
     super.testSubject.post(teller.getCode(), tellerTransaction);
   }
@@ -215,12 +222,12 @@ public class TestTellerOperation extends AbstractTellerTest {
     tellerTransaction.setClerk(AbstractTellerTest.TEST_USER);
     tellerTransaction.setAmount(1234.56D);
 
-    Mockito.doAnswer(invocation -> true)
-        .when(super.accountingServiceSpy).accountExists(tellerTransaction.getCustomerAccountIdentifier());
+    Mockito.doAnswer(invocation -> Optional.of(new Account()))
+        .when(super.accountingServiceSpy).findAccount(tellerTransaction.getCustomerAccountIdentifier());
     Mockito.doAnswer(invocation -> Collections.emptyList())
         .when(super.depositAccountManagementServiceSpy).getCharges(Matchers.eq(tellerTransaction));
     Mockito.doAnswer(invocation -> Collections.emptyList())
-        .when(super.depositAccountManagementServiceSpy).getProductInstance(tellerTransaction.getCustomerIdentifier());
+        .when(super.depositAccountManagementServiceSpy).fetchProductInstances(tellerTransaction.getCustomerIdentifier());
 
     super.testSubject.post(teller.getCode(), tellerTransaction);
   }
@@ -246,16 +253,85 @@ public class TestTellerOperation extends AbstractTellerTest {
     tellerTransaction.setClerk(AbstractTellerTest.TEST_USER);
     tellerTransaction.setAmount(1234.56D);
 
-    Mockito.doAnswer(invocation -> true)
-        .when(super.accountingServiceSpy).accountExists(tellerTransaction.getCustomerAccountIdentifier());
+    final Account account = new Account();
+    account.setBalance(2000.00D);
+    Mockito.doAnswer(invocation -> Optional.of(account))
+        .when(super.accountingServiceSpy).findAccount(tellerTransaction.getCustomerAccountIdentifier());
     Mockito.doAnswer(invocation -> Collections.emptyList())
         .when(super.depositAccountManagementServiceSpy).getCharges(Matchers.eq(tellerTransaction));
     Mockito.doAnswer(invocation -> Collections.emptyList())
-        .when(super.depositAccountManagementServiceSpy).getProductInstance(tellerTransaction.getCustomerIdentifier());
+        .when(super.depositAccountManagementServiceSpy).fetchProductInstances(tellerTransaction.getCustomerIdentifier());
 
     super.testSubject.post(teller.getCode(), tellerTransaction);
   }
 
+  @Test(expected = TransactionProcessingException.class)
+  public void shouldNotWithdrawLackingBalance() throws Exception {
+    final Teller teller = this.prepareTeller();
+
+    final UnlockDrawerCommand unlockDrawerCommand = new UnlockDrawerCommand();
+    unlockDrawerCommand.setEmployeeIdentifier(AbstractTellerTest.TEST_USER);
+    unlockDrawerCommand.setPassword(teller.getPassword());
+
+    super.testSubject.unlockDrawer(teller.getCode(), unlockDrawerCommand);
+
+    super.eventRecorder.wait(EventConstants.AUTHENTICATE_TELLER, teller.getCode());
+
+    final TellerTransaction tellerTransaction =  new TellerTransaction();
+    tellerTransaction.setTransactionType(ServiceConstants.TX_CASH_WITHDRAWAL);
+    tellerTransaction.setTransactionDate(DateConverter.toIsoString(LocalDateTime.now(Clock.systemUTC())));
+    tellerTransaction.setProductIdentifier(RandomStringUtils.randomAlphanumeric(32));
+    tellerTransaction.setCustomerAccountIdentifier(RandomStringUtils.randomAlphanumeric(32));
+    tellerTransaction.setCustomerIdentifier(RandomStringUtils.randomAlphanumeric(32));
+    tellerTransaction.setClerk(AbstractTellerTest.TEST_USER);
+    tellerTransaction.setAmount(5000.00D);
+
+    final Account account = new Account();
+    account.setBalance(2000.00D);
+    Mockito.doAnswer(invocation -> Optional.of(account))
+        .when(super.accountingServiceSpy).findAccount(tellerTransaction.getCustomerAccountIdentifier());
+    Mockito.doAnswer(invocation -> Collections.emptyList())
+        .when(super.depositAccountManagementServiceSpy).getCharges(Matchers.eq(tellerTransaction));
+    Mockito.doAnswer(invocation -> Collections.emptyList())
+        .when(super.depositAccountManagementServiceSpy).fetchProductInstances(tellerTransaction.getCustomerIdentifier());
+
+    super.testSubject.post(teller.getCode(), tellerTransaction);
+  }
+
+  @Test(expected = TransactionProcessingException.class)
+  public void shouldNotWithdrawExceedsCashDrawLimit() throws Exception {
+    final Teller teller = this.prepareTeller();
+
+    final UnlockDrawerCommand unlockDrawerCommand = new UnlockDrawerCommand();
+    unlockDrawerCommand.setEmployeeIdentifier(AbstractTellerTest.TEST_USER);
+    unlockDrawerCommand.setPassword(teller.getPassword());
+
+    super.testSubject.unlockDrawer(teller.getCode(), unlockDrawerCommand);
+
+    super.eventRecorder.wait(EventConstants.AUTHENTICATE_TELLER, teller.getCode());
+
+    final TellerTransaction tellerTransaction =  new TellerTransaction();
+    tellerTransaction.setTransactionType(ServiceConstants.TX_CASH_WITHDRAWAL);
+    tellerTransaction.setTransactionDate(DateConverter.toIsoString(LocalDateTime.now(Clock.systemUTC())));
+    tellerTransaction.setProductIdentifier(RandomStringUtils.randomAlphanumeric(32));
+    tellerTransaction.setCustomerAccountIdentifier(RandomStringUtils.randomAlphanumeric(32));
+    tellerTransaction.setCustomerIdentifier(RandomStringUtils.randomAlphanumeric(32));
+    tellerTransaction.setClerk(AbstractTellerTest.TEST_USER);
+    tellerTransaction.setAmount(15000.00D);
+
+    final Account account = new Account();
+    account.setBalance(20000.00D);
+    Mockito.doAnswer(invocation -> Optional.of(account))
+        .when(super.accountingServiceSpy).findAccount(tellerTransaction.getCustomerAccountIdentifier());
+    Mockito.doAnswer(invocation -> Collections.emptyList())
+        .when(super.depositAccountManagementServiceSpy).getCharges(Matchers.eq(tellerTransaction));
+    Mockito.doAnswer(invocation -> Collections.emptyList())
+        .when(super.depositAccountManagementServiceSpy).fetchProductInstances(tellerTransaction.getCustomerIdentifier());
+
+    super.testSubject.post(teller.getCode(), tellerTransaction);
+  }
+
+
   private Teller prepareTeller() throws Exception {
     final String officeIdentifier = RandomStringUtils.randomAlphabetic(32);
     final Teller teller = TellerGenerator.createRandomTeller();
@@ -263,11 +339,11 @@ public class TestTellerOperation extends AbstractTellerTest {
     Mockito.doAnswer(invocation -> true)
         .when(super.organizationServiceSpy).officeExists(Matchers.eq(officeIdentifier));
 
-    Mockito.doAnswer(invocation -> true)
-        .when(super.accountingServiceSpy).accountExists(Matchers.eq(teller.getTellerAccountIdentifier()));
+    Mockito.doAnswer(invocation -> Optional.of(new Account()))
+        .when(super.accountingServiceSpy).findAccount(Matchers.eq(teller.getTellerAccountIdentifier()));
 
-    Mockito.doAnswer(invocation -> true)
-        .when(super.accountingServiceSpy).accountExists(Matchers.eq(teller.getVaultAccountIdentifier()));
+    Mockito.doAnswer(invocation -> Optional.of(new Account()))
+        .when(super.accountingServiceSpy).findAccount(Matchers.eq(teller.getVaultAccountIdentifier()));
 
     super.testSubject.create(officeIdentifier, teller);
 
@@ -296,11 +372,11 @@ public class TestTellerOperation extends AbstractTellerTest {
     Mockito.doAnswer(invocation -> true)
         .when(super.organizationServiceSpy).officeExists(Matchers.eq(officeIdentifier));
 
-    Mockito.doAnswer(invocation -> true)
-        .when(super.accountingServiceSpy).accountExists(Matchers.eq(teller.getTellerAccountIdentifier()));
+    Mockito.doAnswer(invocation -> Optional.of(new Account()))
+        .when(super.accountingServiceSpy).findAccount(Matchers.eq(teller.getTellerAccountIdentifier()));
 
-    Mockito.doAnswer(invocation -> true)
-        .when(super.accountingServiceSpy).accountExists(Matchers.eq(teller.getVaultAccountIdentifier()));
+    Mockito.doAnswer(invocation -> Optional.of(new Account()))
+        .when(super.accountingServiceSpy).findAccount(Matchers.eq(teller.getVaultAccountIdentifier()));
 
     super.testSubject.create(officeIdentifier, teller);
 
diff --git a/service/src/main/java/io/mifos/teller/service/internal/command/handler/TellerAggregate.java b/service/src/main/java/io/mifos/teller/service/internal/command/handler/TellerAggregate.java
index fb43fbc..53e0a55 100644
--- a/service/src/main/java/io/mifos/teller/service/internal/command/handler/TellerAggregate.java
+++ b/service/src/main/java/io/mifos/teller/service/internal/command/handler/TellerAggregate.java
@@ -28,12 +28,12 @@ import io.mifos.core.lang.ServiceException;
 import io.mifos.teller.ServiceConstants;
 import io.mifos.teller.api.v1.EventConstants;
 import io.mifos.teller.api.v1.domain.Teller;
-import io.mifos.teller.api.v1.domain.UnlockDrawerCommand;
 import io.mifos.teller.api.v1.domain.TellerManagementCommand;
-import io.mifos.teller.service.internal.command.DrawerUnlockCommand;
+import io.mifos.teller.api.v1.domain.UnlockDrawerCommand;
 import io.mifos.teller.service.internal.command.ChangeTellerCommand;
 import io.mifos.teller.service.internal.command.CloseTellerCommand;
 import io.mifos.teller.service.internal.command.CreateTellerCommand;
+import io.mifos.teller.service.internal.command.DrawerUnlockCommand;
 import io.mifos.teller.service.internal.command.OpenTellerCommand;
 import io.mifos.teller.service.internal.command.PauseTellerCommand;
 import io.mifos.teller.service.internal.mapper.TellerMapper;
@@ -275,12 +275,12 @@ public class TellerAggregate {
       pass = false;
     }
 
-    if (!this.accountingService.accountExists(teller.getTellerAccountIdentifier())) {
+    if (!this.accountingService.findAccount(teller.getTellerAccountIdentifier()).isPresent()) {
       this.logger.warn("Teller account {} not found.", teller.getTellerAccountIdentifier());
       pass = false;
     }
 
-    if (!this.accountingService.accountExists(teller.getVaultAccountIdentifier())) {
+    if (!this.accountingService.findAccount(teller.getVaultAccountIdentifier()).isPresent()) {
       this.logger.warn("Vault account {} not found.", teller.getVaultAccountIdentifier());
       pass = false;
     }
diff --git a/service/src/main/java/io/mifos/teller/service/internal/processor/TellerTransactionProcessor.java b/service/src/main/java/io/mifos/teller/service/internal/processor/TellerTransactionProcessor.java
index 105df99..f429425 100644
--- a/service/src/main/java/io/mifos/teller/service/internal/processor/TellerTransactionProcessor.java
+++ b/service/src/main/java/io/mifos/teller/service/internal/processor/TellerTransactionProcessor.java
@@ -19,6 +19,7 @@ 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.core.api.util.UserContextHolder;
+import io.mifos.deposit.api.v1.definition.domain.ProductDefinition;
 import io.mifos.deposit.api.v1.instance.domain.ProductInstance;
 import io.mifos.teller.ServiceConstants;
 import io.mifos.teller.api.v1.domain.Charge;
@@ -144,7 +145,6 @@ public class TellerTransactionProcessor {
 
     final TellerEntity tellerEntity = optionalTeller.get();
     final JournalEntry journalEntry = this.prepareJournalEntry(tellerTransaction);
-    journalEntry.setMessage(tellerTransaction.getTransactionType());
     final TellerTransactionCosts tellerTransactionCosts = this.depositAccountCosts(tellerTransaction);
 
     final HashSet<Debtor> debtors = new HashSet<>();
@@ -214,7 +214,7 @@ public class TellerTransactionProcessor {
 
   private void processDepositAccountClosing(final String tellerCode, final TellerTransaction tellerTransaction) {
     final List<ProductInstance> productInstances =
-        this.depositAccountManagementService.getProductInstance(tellerTransaction.getCustomerIdentifier());
+        this.depositAccountManagementService.fetchProductInstances(tellerTransaction.getCustomerIdentifier());
 
     this.processCashWithdrawal(tellerCode, tellerTransaction);
 
@@ -227,17 +227,18 @@ public class TellerTransactionProcessor {
   }
 
   private void processDepositAccountOpening(final String tellerCode, final TellerTransaction tellerTransaction) {
-    final List<ProductInstance> productInstances =
-        this.depositAccountManagementService.getProductInstance(tellerTransaction.getCustomerIdentifier());
+    final ProductInstance productInstances =
+        this.depositAccountManagementService.findProductInstance(tellerTransaction.getCustomerAccountIdentifier());
+
+    final ProductDefinition productDefinition =
+        this.depositAccountManagementService.findProductDefinition(productInstances.getProductIdentifier());
 
     this.processCashDeposit(tellerCode, tellerTransaction);
 
-    productInstances.forEach(productInstance -> {
-      if (productInstance.getAccountIdentifier().equals(tellerTransaction.getCustomerAccountIdentifier())) {
-        this.depositAccountManagementService.activateProductInstance(tellerTransaction.getCustomerAccountIdentifier());
-        this.accountingService.openAccount(tellerTransaction.getCustomerAccountIdentifier());
-      }
-    });
+    if ((tellerTransaction.getAmount() + productInstances.getBalance()) >= productDefinition.getMinimumBalance()) {
+      this.depositAccountManagementService.activateProductInstance(tellerTransaction.getCustomerAccountIdentifier());
+      this.accountingService.openAccount(tellerTransaction.getCustomerAccountIdentifier());
+    }
   }
 
   private JournalEntry prepareJournalEntry(final TellerTransaction tellerTransaction) {
@@ -245,6 +246,7 @@ public class TellerTransactionProcessor {
     journalEntry.setTransactionIdentifier(tellerTransaction.getIdentifier());
     journalEntry.setTransactionDate(tellerTransaction.getTransactionDate());
     journalEntry.setTransactionType(tellerTransaction.getTransactionType());
+    journalEntry.setMessage(tellerTransaction.getTransactionType());
     journalEntry.setClerk(UserContextHolder.checkedGetUser());
 
     return journalEntry;
diff --git a/service/src/main/java/io/mifos/teller/service/internal/service/helper/AccountingService.java b/service/src/main/java/io/mifos/teller/service/internal/service/helper/AccountingService.java
index 2926910..e5fce56 100644
--- a/service/src/main/java/io/mifos/teller/service/internal/service/helper/AccountingService.java
+++ b/service/src/main/java/io/mifos/teller/service/internal/service/helper/AccountingService.java
@@ -17,6 +17,7 @@ package io.mifos.teller.service.internal.service.helper;
 
 import io.mifos.accounting.api.v1.client.AccountNotFoundException;
 import io.mifos.accounting.api.v1.client.LedgerManager;
+import io.mifos.accounting.api.v1.domain.Account;
 import io.mifos.accounting.api.v1.domain.AccountCommand;
 import io.mifos.accounting.api.v1.domain.AccountEntryPage;
 import io.mifos.accounting.api.v1.domain.JournalEntry;
@@ -27,6 +28,8 @@ import org.springframework.beans.factory.annotation.Qualifier;
 import org.springframework.data.domain.Sort;
 import org.springframework.stereotype.Service;
 
+import java.util.Optional;
+
 @Service
 public class AccountingService {
 
@@ -41,13 +44,12 @@ public class AccountingService {
     this.ledgerManager = ledgerManager;
   }
 
-  public boolean accountExists(final String accountIdentifier) {
+  public Optional<Account> findAccount(final String accountIdentifier) {
     try {
-      this.ledgerManager.findAccount(accountIdentifier);
-      return true;
+      return Optional.of(this.ledgerManager.findAccount(accountIdentifier));
     } catch (final AccountNotFoundException anfex) {
       this.logger.warn("Account {} not found.", accountIdentifier);
-      return false;
+      return Optional.empty();
     }
   }
 
diff --git a/service/src/main/java/io/mifos/teller/service/internal/service/helper/DepositAccountManagementService.java b/service/src/main/java/io/mifos/teller/service/internal/service/helper/DepositAccountManagementService.java
index 891641f..2843195 100644
--- a/service/src/main/java/io/mifos/teller/service/internal/service/helper/DepositAccountManagementService.java
+++ b/service/src/main/java/io/mifos/teller/service/internal/service/helper/DepositAccountManagementService.java
@@ -46,10 +46,14 @@ public class DepositAccountManagementService {
     this.depositAccountManager = depositAccountManager;
   }
 
-  public List<ProductInstance> getProductInstance(final String customerIdentifier) {
+  public List<ProductInstance> fetchProductInstances(final String customerIdentifier) {
     return this.depositAccountManager.fetchProductInstances(customerIdentifier);
   }
 
+  public ProductInstance findProductInstance(final String accountIdentifier) {
+    return this.depositAccountManager.findProductInstance(accountIdentifier);
+  }
+
   public List<Charge> getCharges(final TellerTransaction tellerTransaction) {
     final List<Charge> charges = new ArrayList<>();
     final ProductDefinition productDefinition =
@@ -87,4 +91,8 @@ public class DepositAccountManagementService {
   public void closeProductInstance(final String customerAccountIdentifier) {
     this.depositAccountManager.postProductInstanceCommand(customerAccountIdentifier, EventConstants.CLOSE_PRODUCT_INSTANCE_COMMAND);
   }
+
+  public ProductDefinition findProductDefinition(final String productIdentifier) {
+    return this.depositAccountManager.findProductDefinition(productIdentifier);
+  }
 }
diff --git a/service/src/main/java/io/mifos/teller/service/rest/TellerManagementRestController.java b/service/src/main/java/io/mifos/teller/service/rest/TellerManagementRestController.java
index feef72a..454d02c 100644
--- a/service/src/main/java/io/mifos/teller/service/rest/TellerManagementRestController.java
+++ b/service/src/main/java/io/mifos/teller/service/rest/TellerManagementRestController.java
@@ -209,7 +209,7 @@ public class TellerManagementRestController {
   }
 
   private void verifyAccount(final String accountIdentifier) {
-    if (!this.accountingService.accountExists(accountIdentifier)) {
+    if (!this.accountingService.findAccount(accountIdentifier).isPresent()) {
       throw ServiceException.badRequest("Account {0} not found.", accountIdentifier);
     }
   }
diff --git a/service/src/main/java/io/mifos/teller/service/rest/TellerOperationRestController.java b/service/src/main/java/io/mifos/teller/service/rest/TellerOperationRestController.java
index 68d6876..2a2ca8d 100644
--- a/service/src/main/java/io/mifos/teller/service/rest/TellerOperationRestController.java
+++ b/service/src/main/java/io/mifos/teller/service/rest/TellerOperationRestController.java
@@ -15,6 +15,7 @@
  */
 package io.mifos.teller.service.rest;
 
+import io.mifos.accounting.api.v1.domain.Account;
 import io.mifos.anubis.annotation.AcceptedTokenType;
 import io.mifos.anubis.annotation.Permittable;
 import io.mifos.core.api.util.UserContextHolder;
@@ -23,12 +24,12 @@ import io.mifos.core.lang.ServiceException;
 import io.mifos.teller.ServiceConstants;
 import io.mifos.teller.api.v1.PermittableGroupIds;
 import io.mifos.teller.api.v1.domain.Teller;
-import io.mifos.teller.api.v1.domain.UnlockDrawerCommand;
 import io.mifos.teller.api.v1.domain.TellerTransaction;
 import io.mifos.teller.api.v1.domain.TellerTransactionCosts;
-import io.mifos.teller.service.internal.command.DrawerUnlockCommand;
+import io.mifos.teller.api.v1.domain.UnlockDrawerCommand;
 import io.mifos.teller.service.internal.command.CancelTellerTransactionCommand;
 import io.mifos.teller.service.internal.command.ConfirmTellerTransactionCommand;
+import io.mifos.teller.service.internal.command.DrawerUnlockCommand;
 import io.mifos.teller.service.internal.command.InitializeTellerTransactionCommand;
 import io.mifos.teller.service.internal.command.PauseTellerCommand;
 import io.mifos.teller.service.internal.service.TellerManagementService;
@@ -155,12 +156,33 @@ public class TellerOperationRestController {
       throw ServiceException.conflict("Teller {0} ist not active.", tellerCode);
     }
 
-    if (!this.accountingService.accountExists(tellerTransaction.getCustomerAccountIdentifier())) {
+    final String transactionType = tellerTransaction.getTransactionType();
+
+    if (transactionType.equals(ServiceConstants.TX_CASH_WITHDRAWAL)
+        || transactionType.equals(ServiceConstants.TX_CLOSE_ACCOUNT)) {
+      if (tellerTransaction.getAmount() > teller.getCashdrawLimit()) {
+        throw ServiceException.conflict("Amount exceeds cash drawl limit.");
+      }
+    }
+
+    final Optional<Account> optionalCustomerAccount =
+        this.accountingService.findAccount(tellerTransaction.getCustomerAccountIdentifier());
+    if (!optionalCustomerAccount.isPresent()) {
       throw ServiceException.badRequest("Customer account {0} not found.");
+    } else {
+      if (transactionType.equals(ServiceConstants.TX_ACCOUNT_TRANSFER)
+          || transactionType.equals(ServiceConstants.TX_CASH_WITHDRAWAL)
+          || transactionType.equals(ServiceConstants.TX_CLOSE_ACCOUNT)) {
+
+        final Account customerAccount = optionalCustomerAccount.get();
+        if (customerAccount.getBalance() < tellerTransaction.getAmount()) {
+          throw ServiceException.conflict("Not enough balance.");
+        }
+      }
     }
 
     if (tellerTransaction.getTargetAccountIdentifier() != null &&
-        !this.accountingService.accountExists(tellerTransaction.getTargetAccountIdentifier())) {
+        !this.accountingService.findAccount(tellerTransaction.getTargetAccountIdentifier()).isPresent()) {
       throw ServiceException.badRequest("Target account {0} not found.");
     }
 

-- 
To stop receiving notification emails like this one, please contact
myrle@apache.org.

[fineract-cn-teller] 30/30: Removing duplicate resource files from jar.

Posted by my...@apache.org.
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-teller.git

commit a0abc61cc95aaa617f6cf0ac1f5677e1b99d20d1
Author: Myrle Krantz <my...@apache.org>
AuthorDate: Wed Jul 12 15:07:52 2017 +0200

    Removing duplicate resource files from jar.
---
 shared.gradle | 1 +
 1 file changed, 1 insertion(+)

diff --git a/shared.gradle b/shared.gradle
index 40e691b..45f0a9c 100644
--- a/shared.gradle
+++ b/shared.gradle
@@ -58,6 +58,7 @@ dependencies {
 
 jar {
     from sourceSets.main.allSource
+    duplicatesStrategy = DuplicatesStrategy.EXCLUDE
 }
 
 license {

-- 
To stop receiving notification emails like this one, please contact
myrle@apache.org.

[fineract-cn-teller] 15/30: changed transaction types

Posted by my...@apache.org.
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-teller.git

commit 1060664ca05674fefffc2d099ca107154a361865
Author: mgeiss <mg...@mifos.org>
AuthorDate: Wed Jun 14 19:09:20 2017 +0200

    changed transaction types
---
 service/src/main/java/io/mifos/teller/ServiceConstants.java | 6 +++---
 1 file changed, 3 insertions(+), 3 deletions(-)

diff --git a/service/src/main/java/io/mifos/teller/ServiceConstants.java b/service/src/main/java/io/mifos/teller/ServiceConstants.java
index 2d5f000..6e6af9f 100644
--- a/service/src/main/java/io/mifos/teller/ServiceConstants.java
+++ b/service/src/main/java/io/mifos/teller/ServiceConstants.java
@@ -23,9 +23,9 @@ public interface ServiceConstants {
 
   String TX_OPEN_ACCOUNT = "ACCO";
   String TX_CLOSE_ACCOUNT = "ACCC";
-  String TX_ACCOUNT_TRANSFER = "BACT";
-  String TX_CASH_DEPOSIT = "BCDP";
-  String TX_CASH_WITHDRAWAL = "BCWD";
+  String TX_ACCOUNT_TRANSFER = "ACCT";
+  String TX_CASH_DEPOSIT = "CDPT";
+  String TX_CASH_WITHDRAWAL = "CWDL";
 
   String TX_DEPOSIT_ADJUSTMENT = "DAJT";
   String TX_CREDIT_ADJUSTMENT = "CAJT";

-- 
To stop receiving notification emails like this one, please contact
myrle@apache.org.

[fineract-cn-teller] 16/30: throw 400 if teller is closed while unlocking

Posted by my...@apache.org.
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-teller.git

commit e8a0e9773b17f54c4e991243897ffebc4d52ee12
Author: mgeiss <mg...@mifos.org>
AuthorDate: Wed Jun 21 20:31:50 2017 +0200

    throw 400 if teller is closed while unlocking
---
 .../java/io/mifos/teller/TestTellerOperation.java  | 25 ++++++++++++++++++++++
 .../rest/TellerOperationRestController.java        |  4 ++++
 2 files changed, 29 insertions(+)

diff --git a/component-test/src/main/java/io/mifos/teller/TestTellerOperation.java b/component-test/src/main/java/io/mifos/teller/TestTellerOperation.java
index 95b1774..18589cf 100644
--- a/component-test/src/main/java/io/mifos/teller/TestTellerOperation.java
+++ b/component-test/src/main/java/io/mifos/teller/TestTellerOperation.java
@@ -287,4 +287,29 @@ public class TestTellerOperation extends AbstractTellerTest {
 
     return teller;
   }
+
+  @Test(expected = TellerNotFoundException.class)
+  public void shouldNotUnlockTellerClosed() throws Exception {
+    final String officeIdentifier = RandomStringUtils.randomAlphabetic(32);
+    final Teller teller = TellerGenerator.createRandomTeller();
+
+    Mockito.doAnswer(invocation -> true)
+        .when(super.organizationServiceSpy).officeExists(Matchers.eq(officeIdentifier));
+
+    Mockito.doAnswer(invocation -> true)
+        .when(super.accountingServiceSpy).accountExists(Matchers.eq(teller.getTellerAccountIdentifier()));
+
+    Mockito.doAnswer(invocation -> true)
+        .when(super.accountingServiceSpy).accountExists(Matchers.eq(teller.getVaultAccountIdentifier()));
+
+    super.testSubject.create(officeIdentifier, teller);
+
+    Assert.assertTrue(super.eventRecorder.wait(EventConstants.POST_TELLER, teller.getCode()));
+
+    final UnlockDrawerCommand unlockDrawerCommand = new UnlockDrawerCommand();
+    unlockDrawerCommand.setEmployeeIdentifier(AbstractTellerTest.TEST_USER);
+    unlockDrawerCommand.setPassword(teller.getPassword());
+
+    super.testSubject.unlockDrawer(teller.getCode(), unlockDrawerCommand);
+  }
 }
diff --git a/service/src/main/java/io/mifos/teller/service/rest/TellerOperationRestController.java b/service/src/main/java/io/mifos/teller/service/rest/TellerOperationRestController.java
index 540d2c4..68d6876 100644
--- a/service/src/main/java/io/mifos/teller/service/rest/TellerOperationRestController.java
+++ b/service/src/main/java/io/mifos/teller/service/rest/TellerOperationRestController.java
@@ -86,6 +86,10 @@ public class TellerOperationRestController {
                                     @RequestBody @Valid final UnlockDrawerCommand unlockDrawerCommand) {
     final Teller teller = this.verifyTeller(tellerCode);
 
+    if (teller.getState().equals(Teller.State.CLOSED.name())) {
+      throw ServiceException.badRequest("Teller {0} is closed.", teller.getCode());
+    }
+
     if (!teller.getAssignedEmployee().equals(unlockDrawerCommand.getEmployeeIdentifier())) {
       throw ServiceException.badRequest("User {0} is not assigned to teller.", unlockDrawerCommand.getEmployeeIdentifier());
     }

-- 
To stop receiving notification emails like this one, please contact
myrle@apache.org.

[fineract-cn-teller] 29/30: Fixed query.

Posted by my...@apache.org.
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-teller.git

commit 519386a5af024217b352b798c1a136128922b41c
Author: Myrle Krantz <my...@apache.org>
AuthorDate: Tue Jul 11 12:39:29 2017 +0200

    Fixed query.
---
 .../service/internal/service/TellerManagementService.java   | 13 ++++---------
 1 file changed, 4 insertions(+), 9 deletions(-)

diff --git a/service/src/main/java/io/mifos/teller/service/internal/service/TellerManagementService.java b/service/src/main/java/io/mifos/teller/service/internal/service/TellerManagementService.java
index 0a00d76..ad56ec4 100644
--- a/service/src/main/java/io/mifos/teller/service/internal/service/TellerManagementService.java
+++ b/service/src/main/java/io/mifos/teller/service/internal/service/TellerManagementService.java
@@ -17,7 +17,6 @@ package io.mifos.teller.service.internal.service;
 
 import io.mifos.accounting.api.v1.domain.AccountEntryPage;
 import io.mifos.core.lang.DateConverter;
-import io.mifos.teller.ServiceConstants;
 import io.mifos.teller.api.v1.domain.Teller;
 import io.mifos.teller.api.v1.domain.TellerBalanceSheet;
 import io.mifos.teller.api.v1.domain.TellerEntry;
@@ -26,12 +25,11 @@ import io.mifos.teller.service.internal.mapper.TellerMapper;
 import io.mifos.teller.service.internal.repository.TellerEntity;
 import io.mifos.teller.service.internal.repository.TellerRepository;
 import io.mifos.teller.service.internal.service.helper.AccountingService;
-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.time.Clock;
+import java.time.LocalDate;
 import java.time.LocalDateTime;
 import java.time.format.DateTimeFormatter;
 import java.util.ArrayList;
@@ -42,16 +40,13 @@ import java.util.stream.Collectors;
 @Service
 public class TellerManagementService {
 
-  private final Logger logger;
   private final TellerRepository tellerRepository;
   private final AccountingService accountingService;
 
   @Autowired
-  public TellerManagementService(@Qualifier(ServiceConstants.LOGGER_NAME) final Logger logger,
-                                 final TellerRepository tellerRepository,
+  public TellerManagementService(final TellerRepository tellerRepository,
                                  final AccountingService accountingService) {
     super();
-    this.logger = logger;
     this.tellerRepository = tellerRepository;
     this.accountingService = accountingService;
   }
@@ -76,8 +71,8 @@ public class TellerManagementService {
       final String accountIdentifier = tellerEntity.getTellerAccountIdentifier();
       final LocalDateTime lastModifiedOn =
           tellerEntity.getLastModifiedOn() != null ? tellerEntity.getLastModifiedOn() : LocalDateTime.now(Clock.systemUTC());
-      final LocalDateTime startDate = lastModifiedOn.withHour(0).withMinute(0).withSecond(0).withNano(0);
-      final LocalDateTime endDate = lastModifiedOn.withHour(23).withMinute(59).withSecond(59).withNano(999);
+      final LocalDate startDate = lastModifiedOn.toLocalDate();
+      final LocalDate endDate = lastModifiedOn.toLocalDate();
       final String dateRange =
           DateConverter.toIsoString(startDate) + ".." + DateConverter.toIsoString(endDate);
 

-- 
To stop receiving notification emails like this one, please contact
myrle@apache.org.

[fineract-cn-teller] 18/30: added TX type as message to journal entry

Posted by my...@apache.org.
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-teller.git

commit 8af6853ad10b6115717a05a249ebe2ac6b3900d5
Author: mgeiss <mg...@mifos.org>
AuthorDate: Fri Jun 23 09:33:42 2017 +0200

    added TX type as message to journal entry
---
 .../teller/service/internal/processor/TellerTransactionProcessor.java    | 1 +
 1 file changed, 1 insertion(+)

diff --git a/service/src/main/java/io/mifos/teller/service/internal/processor/TellerTransactionProcessor.java b/service/src/main/java/io/mifos/teller/service/internal/processor/TellerTransactionProcessor.java
index 7c62568..105df99 100644
--- a/service/src/main/java/io/mifos/teller/service/internal/processor/TellerTransactionProcessor.java
+++ b/service/src/main/java/io/mifos/teller/service/internal/processor/TellerTransactionProcessor.java
@@ -144,6 +144,7 @@ public class TellerTransactionProcessor {
 
     final TellerEntity tellerEntity = optionalTeller.get();
     final JournalEntry journalEntry = this.prepareJournalEntry(tellerTransaction);
+    journalEntry.setMessage(tellerTransaction.getTransactionType());
     final TellerTransactionCosts tellerTransactionCosts = this.depositAccountCosts(tellerTransaction);
 
     final HashSet<Debtor> debtors = new HashSet<>();

-- 
To stop receiving notification emails like this one, please contact
myrle@apache.org.

[fineract-cn-teller] 27/30: Fixing compile error caused by my changes to the signature of accounting.

Posted by my...@apache.org.
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-teller.git

commit 41ac0e1dbb8e7d82cc8963314f414455a22b7811
Author: Myrle Krantz <my...@apache.org>
AuthorDate: Tue Jul 11 12:34:12 2017 +0200

    Fixing compile error caused by my changes to the signature of accounting.
---
 .../mifos/teller/service/internal/service/helper/AccountingService.java | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/service/src/main/java/io/mifos/teller/service/internal/service/helper/AccountingService.java b/service/src/main/java/io/mifos/teller/service/internal/service/helper/AccountingService.java
index e5fce56..b64ce5b 100644
--- a/service/src/main/java/io/mifos/teller/service/internal/service/helper/AccountingService.java
+++ b/service/src/main/java/io/mifos/teller/service/internal/service/helper/AccountingService.java
@@ -55,7 +55,7 @@ public class AccountingService {
 
   public AccountEntryPage fetchAccountEntries(final String accountIdentifier, final String dateRange, final Integer pageIndex,
                                               final Integer pageSize) {
-    return this.ledgerManager.fetchAccountEntries(accountIdentifier, dateRange, pageIndex, pageSize, "identifier",
+    return this.ledgerManager.fetchAccountEntries(accountIdentifier, dateRange, null, pageIndex, pageSize, "identifier",
         Sort.Direction.DESC.name());
   }
 

-- 
To stop receiving notification emails like this one, please contact
myrle@apache.org.

[fineract-cn-teller] 28/30: Introduced a TestSuite to make running all component-tests a hands-free process.

Posted by my...@apache.org.
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-teller.git

commit 5b3e4cc75d73e7b0dba68f763b47def01ce044d6
Author: Myrle Krantz <my...@apache.org>
AuthorDate: Tue Jul 11 12:34:57 2017 +0200

    Introduced a TestSuite to make running all component-tests a hands-free process.
---
 .../java/io/mifos/teller/AbstractTellerTest.java   | 20 ++---------
 .../java/io/mifos/teller/SuiteTestEnvironment.java | 40 ++++++++++++++++++++++
 .../src/main/java/io/mifos/teller/TestSuite.java   | 30 ++++++++++++++++
 3 files changed, 73 insertions(+), 17 deletions(-)

diff --git a/component-test/src/main/java/io/mifos/teller/AbstractTellerTest.java b/component-test/src/main/java/io/mifos/teller/AbstractTellerTest.java
index 9a86a73..0d364f4 100644
--- a/component-test/src/main/java/io/mifos/teller/AbstractTellerTest.java
+++ b/component-test/src/main/java/io/mifos/teller/AbstractTellerTest.java
@@ -18,10 +18,7 @@ package io.mifos.teller;
 import io.mifos.anubis.test.v1.TenantApplicationSecurityEnvironmentTestRule;
 import io.mifos.core.api.context.AutoUserContext;
 import io.mifos.core.lang.ApplicationName;
-import io.mifos.core.test.env.TestEnvironment;
 import io.mifos.core.test.fixture.TenantDataStoreContextTestRule;
-import io.mifos.core.test.fixture.cassandra.CassandraInitializer;
-import io.mifos.core.test.fixture.mariadb.MariaDBInitializer;
 import io.mifos.core.test.listener.EnableEventRecording;
 import io.mifos.core.test.listener.EventRecorder;
 import io.mifos.teller.api.v1.EventConstants;
@@ -34,8 +31,6 @@ import org.junit.After;
 import org.junit.Before;
 import org.junit.ClassRule;
 import org.junit.Rule;
-import org.junit.rules.RuleChain;
-import org.junit.rules.TestRule;
 import org.junit.runner.RunWith;
 import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
@@ -58,9 +53,8 @@ import java.security.interfaces.RSAPrivateKey;
     webEnvironment = SpringBootTest.WebEnvironment.DEFINED_PORT,
     classes = {AbstractTellerTest.TestConfiguration.class}
 )
-public class AbstractTellerTest {
+public class AbstractTellerTest extends SuiteTestEnvironment {
 
-  private static final String APP_NAME = "teller-v1";
   public static final String LOGGER_NAME = "test-logger";
 
   @Configuration
@@ -82,17 +76,8 @@ public class AbstractTellerTest {
 
   static final String TEST_USER = "homer";
 
-  private final static TestEnvironment testEnvironment = new TestEnvironment(APP_NAME);
-  private final static CassandraInitializer cassandraInitializer = new CassandraInitializer();
-  private final static MariaDBInitializer mariaDBInitializer = new MariaDBInitializer();
-  final static TenantDataStoreContextTestRule tenantDataStoreContext = TenantDataStoreContextTestRule.forRandomTenantName(cassandraInitializer, mariaDBInitializer);
-
   @ClassRule
-  public static TestRule orderClassRules = RuleChain
-      .outerRule(testEnvironment)
-      .around(cassandraInitializer)
-      .around(mariaDBInitializer)
-      .around(tenantDataStoreContext);
+  public static TenantDataStoreContextTestRule tenantDataStoreContext = TenantDataStoreContextTestRule.forRandomTenantName(cassandraInitializer, mariaDBInitializer);
 
   @Rule
   public final TenantApplicationSecurityEnvironmentTestRule tenantApplicationSecurityEnvironment
@@ -121,6 +106,7 @@ public class AbstractTellerTest {
   @Autowired
   private ApplicationName applicationName;
 
+  @SuppressWarnings("WeakerAccess")
   @Autowired
   @Qualifier(LOGGER_NAME)
   Logger logger;
diff --git a/component-test/src/main/java/io/mifos/teller/SuiteTestEnvironment.java b/component-test/src/main/java/io/mifos/teller/SuiteTestEnvironment.java
new file mode 100644
index 0000000..da58655
--- /dev/null
+++ b/component-test/src/main/java/io/mifos/teller/SuiteTestEnvironment.java
@@ -0,0 +1,40 @@
+/*
+ * 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.
+ */
+package io.mifos.teller;
+
+import io.mifos.core.test.env.TestEnvironment;
+import io.mifos.core.test.fixture.cassandra.CassandraInitializer;
+import io.mifos.core.test.fixture.mariadb.MariaDBInitializer;
+import org.junit.ClassRule;
+import org.junit.rules.RuleChain;
+import org.junit.rules.RunExternalResourceOnce;
+import org.junit.rules.TestRule;
+
+/**
+ * @author Myrle Krantz
+ */
+public class SuiteTestEnvironment {
+  static final String APP_NAME = "teller-v1";
+  static final TestEnvironment testEnvironment = new TestEnvironment(APP_NAME);
+  static final CassandraInitializer cassandraInitializer = new CassandraInitializer();
+  static final MariaDBInitializer mariaDBInitializer = new MariaDBInitializer();
+
+  @ClassRule
+  public static TestRule orderClassRules = RuleChain
+      .outerRule(new RunExternalResourceOnce(testEnvironment))
+      .around(new RunExternalResourceOnce(cassandraInitializer))
+      .around(new RunExternalResourceOnce(mariaDBInitializer));
+}
diff --git a/component-test/src/main/java/io/mifos/teller/TestSuite.java b/component-test/src/main/java/io/mifos/teller/TestSuite.java
new file mode 100644
index 0000000..5c52ab0
--- /dev/null
+++ b/component-test/src/main/java/io/mifos/teller/TestSuite.java
@@ -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.
+ */
+package io.mifos.teller;
+
+import org.junit.runner.RunWith;
+import org.junit.runners.Suite;
+
+/**
+ * @author Myrle Krantz
+ */
+@RunWith(Suite.class)
+@Suite.SuiteClasses({
+    TestTellerManagement.class,
+    TestTellerOperation.class,
+})
+public class TestSuite extends SuiteTestEnvironment {
+}

-- 
To stop receiving notification emails like this one, please contact
myrle@apache.org.

[fineract-cn-teller] 05/30: replaced dot with dash in version number

Posted by my...@apache.org.
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-teller.git

commit c3a63e3e4727ceaf87eb446838db051281dd1330
Author: mgeiss <mg...@mifos.org>
AuthorDate: Sun Jun 11 14:16:42 2017 +0200

    replaced dot with dash in version number
---
 shared.gradle | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/shared.gradle b/shared.gradle
index 4006bc4..40e691b 100644
--- a/shared.gradle
+++ b/shared.gradle
@@ -1,5 +1,5 @@
 group 'io.mifos.teller'
-version '0.1.0.BUILD-SNAPSHOT'
+version '0.1.0-BUILD-SNAPSHOT'
 
 ext.versions = [
         frameworkapi : '0.1.0-BUILD-SNAPSHOT',

-- 
To stop receiving notification emails like this one, please contact
myrle@apache.org.

[fineract-cn-teller] 06/30: refactored default date range

Posted by my...@apache.org.
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-teller.git

commit c851ae086bbe7a3fb748603a98cce388a2cfd5de
Author: mgeiss <mg...@mifos.org>
AuthorDate: Sun Jun 11 17:15:18 2017 +0200

    refactored default date range
---
 .../mifos/teller/service/internal/service/TellerManagementService.java | 3 ++-
 1 file changed, 2 insertions(+), 1 deletion(-)

diff --git a/service/src/main/java/io/mifos/teller/service/internal/service/TellerManagementService.java b/service/src/main/java/io/mifos/teller/service/internal/service/TellerManagementService.java
index e2b4ac3..ceb497a 100644
--- a/service/src/main/java/io/mifos/teller/service/internal/service/TellerManagementService.java
+++ b/service/src/main/java/io/mifos/teller/service/internal/service/TellerManagementService.java
@@ -16,6 +16,7 @@
 package io.mifos.teller.service.internal.service;
 
 import io.mifos.accounting.api.v1.domain.AccountEntryPage;
+import io.mifos.core.lang.DateConverter;
 import io.mifos.teller.ServiceConstants;
 import io.mifos.teller.api.v1.domain.Teller;
 import io.mifos.teller.api.v1.domain.TellerBalanceSheet;
@@ -76,7 +77,7 @@ public class TellerManagementService {
       final LocalDateTime startDate = lastModifiedOn.withHour(0).withMinute(0).withSecond(0).withNano(0);
       final LocalDateTime endDate = lastModifiedOn.withHour(23).withMinute(59).withSecond(59).withNano(999);
       final String dateRange =
-          startDate.format(DateTimeFormatter.BASIC_ISO_DATE) + ".." + endDate.format(DateTimeFormatter.BASIC_ISO_DATE);
+          DateConverter.toIsoString(startDate) + ".." + DateConverter.toIsoString(endDate);
 
       final List<TellerEntry> tellerEntries = this.fetchTellerEntries(accountIdentifier, dateRange, 0);
 

-- 
To stop receiving notification emails like this one, please contact
myrle@apache.org.

[fineract-cn-teller] 03/30: edited during review

Posted by my...@apache.org.
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-teller.git

commit d66dbe2dba8540aaae497bee9cc8b659216cddd1
Author: mgeiss <mg...@mifos.org>
AuthorDate: Wed Jun 7 09:56:43 2017 +0200

    edited during review
---
 .../java/io/mifos/teller/client/TellerManager.java | 32 +++++++++++++++-------
 .../main/java/io/mifos/teller/domain/Teller.java   |  6 ++--
 .../mifos/teller/domain/TellerAuthentication.java  |  6 ++--
 .../teller/domain/TellerManagementCommand.java     |  6 ++++
 .../io/mifos/teller/domain/TellerTransaction.java  | 20 ++++++++++----
 5 files changed, 49 insertions(+), 21 deletions(-)

diff --git a/api/src/main/java/io/mifos/teller/client/TellerManager.java b/api/src/main/java/io/mifos/teller/client/TellerManager.java
index e392f28..2b9b0b4 100644
--- a/api/src/main/java/io/mifos/teller/client/TellerManager.java
+++ b/api/src/main/java/io/mifos/teller/client/TellerManager.java
@@ -25,7 +25,7 @@ import java.util.List;
 public interface TellerManager {
 
   @RequestMapping(
-      value = "/management/{officeIdentifier}",
+      value = "/offices/{officeIdentifier}",
       method = RequestMethod.POST,
       consumes = MediaType.APPLICATION_JSON_VALUE,
       produces = MediaType.APPLICATION_JSON_VALUE
@@ -38,7 +38,7 @@ public interface TellerManager {
   void create(@PathVariable("officeIdentifier") final String officeIdentifier, @RequestBody @Valid final Teller teller);
 
   @RequestMapping(
-      value = "/management/{officeIdentifier}/teller/{tellerCode}",
+      value = "/offices/{officeIdentifier}/teller/{tellerCode}",
       method = RequestMethod.GET,
       consumes = MediaType.APPLICATION_JSON_VALUE,
       produces = MediaType.ALL_VALUE
@@ -50,7 +50,7 @@ public interface TellerManager {
               @PathVariable("tellerCode") final String tellerCode);
 
   @RequestMapping(
-      value = "/management/{officeIdentifier}/teller",
+      value = "/offices/{officeIdentifier}/teller",
       method = RequestMethod.GET,
       consumes = MediaType.APPLICATION_JSON_VALUE,
       produces = MediaType.ALL_VALUE
@@ -61,7 +61,7 @@ public interface TellerManager {
   List<Teller> fetch(@PathVariable("officeIdentifier") final String officeIdentifier);
 
   @RequestMapping(
-      value = "/management/{officeIdentifier}/teller/{tellerCode}",
+      value = "/offices/{officeIdentifier}/teller/{tellerCode}",
       method = RequestMethod.PUT,
       consumes = MediaType.APPLICATION_JSON_VALUE,
       produces = MediaType.APPLICATION_JSON_VALUE
@@ -75,7 +75,7 @@ public interface TellerManager {
               @RequestBody @Valid final Teller teller);
 
   @RequestMapping(
-      value = "/management/{officeIdentifier}/teller/{tellerCode}/commands",
+      value = "/offices/{officeIdentifier}/teller/{tellerCode}/commands",
       method = RequestMethod.POST,
       consumes = MediaType.APPLICATION_JSON_VALUE,
       produces = MediaType.APPLICATION_JSON_VALUE
@@ -89,7 +89,7 @@ public interface TellerManager {
             @RequestBody @Valid final TellerManagementCommand tellerManagementCommand);
 
   @RequestMapping(
-      value = "/management/{officeIdentifier}/teller/{tellerCode}/balance",
+      value = "/offices/{officeIdentifier}/teller/{tellerCode}/balance",
       method = RequestMethod.GET,
       consumes = MediaType.APPLICATION_JSON_VALUE,
       produces = MediaType.ALL_VALUE
@@ -101,7 +101,7 @@ public interface TellerManager {
                                 @PathVariable("tellerCode") final String tellerCode);
 
   @RequestMapping(
-      value = "/operations/{tellerCode}/auth",
+      value = "/teller/{tellerCode}/auth",
       method = RequestMethod.POST,
       consumes = MediaType.APPLICATION_JSON_VALUE,
       produces = MediaType.APPLICATION_JSON_VALUE
@@ -114,7 +114,7 @@ public interface TellerManager {
             @RequestBody @Valid final TellerAuthentication tellerAuthentication);
 
   @RequestMapping(
-      value = "/operations/{tellerCode}",
+      value = "/teller/{tellerCode}",
       method = RequestMethod.POST,
       consumes = MediaType.APPLICATION_JSON_VALUE,
       produces = MediaType.APPLICATION_JSON_VALUE
@@ -126,7 +126,7 @@ public interface TellerManager {
             @RequestParam(value = "command", required = true) final String command);
 
   @RequestMapping(
-      value = "/operations/{tellerCode}/transactions",
+      value = "/teller/{tellerCode}/transactions",
       method = RequestMethod.POST,
       consumes = MediaType.APPLICATION_JSON_VALUE,
       produces = MediaType.APPLICATION_JSON_VALUE
@@ -139,7 +139,7 @@ public interface TellerManager {
                               @RequestBody @Valid final TellerTransaction tellerTransaction);
 
   @RequestMapping(
-      value = "/operations/{tellerCode}/transactions/{identifier}",
+      value = "/teller/{tellerCode}/transactions/{identifier}",
       method = RequestMethod.POST,
       consumes = MediaType.APPLICATION_JSON_VALUE,
       produces = MediaType.APPLICATION_JSON_VALUE
@@ -150,4 +150,16 @@ public interface TellerManager {
   void confirm(@PathVariable("tellerCode") final String tellerCode,
                @PathVariable("identifier") final String tellerTransactionIdentifier,
                @RequestParam(value = "command", required = true) final String command);
+
+  @RequestMapping(
+      value = "/teller/{tellerCode}/transactions",
+      method = RequestMethod.GET,
+      consumes = MediaType.APPLICATION_JSON_VALUE,
+      produces = MediaType.ALL_VALUE
+  )
+  @ThrowsExceptions({
+      @ThrowsException(status = HttpStatus.NOT_FOUND, exception = TellerNotFoundException.class)
+  })
+  List<TellerTransaction> fetch(@PathVariable("tellerCode") final String tellerCode,
+                                @RequestParam(value = "status", required = false) final String status);
 }
diff --git a/api/src/main/java/io/mifos/teller/domain/Teller.java b/api/src/main/java/io/mifos/teller/domain/Teller.java
index 688f37f..b1fa3b4 100644
--- a/api/src/main/java/io/mifos/teller/domain/Teller.java
+++ b/api/src/main/java/io/mifos/teller/domain/Teller.java
@@ -26,7 +26,7 @@ public class Teller {
   private String tellerAccountIdentifier;
   @ValidIdentifier
   private String vaultAccountIdentifier;
-  private String status;
+  private Status status;
   private String createdBy;
   private String createdOn;
   private String lastModifiedBy;
@@ -77,11 +77,11 @@ public class Teller {
   }
 
   public String getStatus() {
-    return this.status;
+    return this.status.name();
   }
 
   public void setStatus(final String status) {
-    this.status = status;
+    this.status = Status.valueOf(status);
   }
 
   public String getCreatedBy() {
diff --git a/api/src/main/java/io/mifos/teller/domain/TellerAuthentication.java b/api/src/main/java/io/mifos/teller/domain/TellerAuthentication.java
index 135d73b..e6578c8 100644
--- a/api/src/main/java/io/mifos/teller/domain/TellerAuthentication.java
+++ b/api/src/main/java/io/mifos/teller/domain/TellerAuthentication.java
@@ -3,7 +3,7 @@ package io.mifos.teller.domain;
 public class TellerAuthentication {
 
   private String employeeIdentifier;
-  private String password;
+  private byte[] password;
 
   public TellerAuthentication() {
     super();
@@ -17,11 +17,11 @@ public class TellerAuthentication {
     this.employeeIdentifier = employeeIdentifier;
   }
 
-  public String getPassword() {
+  public byte[] getPassword() {
     return this.password;
   }
 
-  public void setPassword(final String password) {
+  public void setPassword(final byte[] password) {
     this.password = password;
   }
 }
diff --git a/api/src/main/java/io/mifos/teller/domain/TellerManagementCommand.java b/api/src/main/java/io/mifos/teller/domain/TellerManagementCommand.java
index 41f29f5..c974451 100644
--- a/api/src/main/java/io/mifos/teller/domain/TellerManagementCommand.java
+++ b/api/src/main/java/io/mifos/teller/domain/TellerManagementCommand.java
@@ -1,5 +1,9 @@
 package io.mifos.teller.domain;
 
+import io.mifos.core.lang.validation.constraints.ValidIdentifier;
+
+import javax.validation.constraints.NotNull;
+
 public class TellerManagementCommand {
 
   public enum Action {
@@ -12,9 +16,11 @@ public class TellerManagementCommand {
     CREDIT
   }
 
+  @NotNull
   private Action action;
   private Adjustment adjustment;
   private Double amount;
+  @ValidIdentifier(optional = true)
   private String assignedEmployeeIdentifier;
 
   public TellerManagementCommand() {
diff --git a/api/src/main/java/io/mifos/teller/domain/TellerTransaction.java b/api/src/main/java/io/mifos/teller/domain/TellerTransaction.java
index a00e7cc..e3d3a81 100644
--- a/api/src/main/java/io/mifos/teller/domain/TellerTransaction.java
+++ b/api/src/main/java/io/mifos/teller/domain/TellerTransaction.java
@@ -2,6 +2,9 @@ package io.mifos.teller.domain;
 
 import io.mifos.core.lang.validation.constraints.ValidIdentifier;
 
+import javax.validation.constraints.DecimalMin;
+import javax.validation.constraints.NotNull;
+
 public class TellerTransaction {
 
   public enum State {
@@ -12,11 +15,18 @@ public class TellerTransaction {
 
   @ValidIdentifier(optional = true)
   private String identifier;
+  @NotNull
   private String transactionType;
+  @NotNull
   private String transactionDate;
+  @ValidIdentifier
   private String productIdentifier;
-  private String accountIdentifier;
+  @ValidIdentifier
+  private String customerAccountIdentifier;
+  @ValidIdentifier
   private String clerk;
+  @NotNull
+  @DecimalMin("0.00")
   private Double amount;
   private State state;
 
@@ -56,12 +66,12 @@ public class TellerTransaction {
     this.productIdentifier = productIdentifier;
   }
 
-  public String getAccountIdentifier() {
-    return this.accountIdentifier;
+  public String getCustomerAccountIdentifier() {
+    return this.customerAccountIdentifier;
   }
 
-  public void setAccountIdentifier(final String accountIdentifier) {
-    this.accountIdentifier = accountIdentifier;
+  public void setCustomerAccountIdentifier(final String customerAccountIdentifier) {
+    this.customerAccountIdentifier = customerAccountIdentifier;
   }
 
   public String getClerk() {

-- 
To stop receiving notification emails like this one, please contact
myrle@apache.org.

[fineract-cn-teller] 14/30: fixed command type for activation and closing of product instances

Posted by my...@apache.org.
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-teller.git

commit 94c898e96fdf1df51c6e63956b2f46f91ce966c3
Author: mgeiss <mg...@mifos.org>
AuthorDate: Wed Jun 14 17:45:34 2017 +0200

    fixed command type for activation and closing of product instances
---
 .../internal/service/helper/DepositAccountManagementService.java      | 4 ++--
 1 file changed, 2 insertions(+), 2 deletions(-)

diff --git a/service/src/main/java/io/mifos/teller/service/internal/service/helper/DepositAccountManagementService.java b/service/src/main/java/io/mifos/teller/service/internal/service/helper/DepositAccountManagementService.java
index 5c8a0aa..891641f 100644
--- a/service/src/main/java/io/mifos/teller/service/internal/service/helper/DepositAccountManagementService.java
+++ b/service/src/main/java/io/mifos/teller/service/internal/service/helper/DepositAccountManagementService.java
@@ -81,10 +81,10 @@ public class DepositAccountManagementService {
   }
 
   public void activateProductInstance(final String customerAccountIdentifier) {
-    this.depositAccountManager.postProductInstanceCommand(customerAccountIdentifier, EventConstants.ACTIVATE_PRODUCT_INSTANCE);
+    this.depositAccountManager.postProductInstanceCommand(customerAccountIdentifier, EventConstants.ACTIVATE_PRODUCT_INSTANCE_COMMAND);
   }
 
   public void closeProductInstance(final String customerAccountIdentifier) {
-    this.depositAccountManager.postProductInstanceCommand(customerAccountIdentifier, EventConstants.CLOSE_PRODUCT_INSTANCE);
+    this.depositAccountManager.postProductInstanceCommand(customerAccountIdentifier, EventConstants.CLOSE_PRODUCT_INSTANCE_COMMAND);
   }
 }

-- 
To stop receiving notification emails like this one, please contact
myrle@apache.org.