added ceque receivable account for teller tx
diff --git a/api/src/main/java/io/mifos/teller/api/v1/domain/Teller.java b/api/src/main/java/io/mifos/teller/api/v1/domain/Teller.java
index dc59d4f..e807d85 100644
--- a/api/src/main/java/io/mifos/teller/api/v1/domain/Teller.java
+++ b/api/src/main/java/io/mifos/teller/api/v1/domain/Teller.java
@@ -38,10 +38,12 @@
   @DecimalMin("0.00")
   @DecimalMax("1000000000.00")
   private BigDecimal cashdrawLimit;
-  @ValidIdentifier
+  @ValidIdentifier(maxLength = 34)
   private String tellerAccountIdentifier;
-  @ValidIdentifier
+  @ValidIdentifier(maxLength = 34)
   private String vaultAccountIdentifier;
+  @ValidIdentifier(maxLength = 34)
+  private String chequesReceivableAccount;
   private String assignedEmployee;
   private State state;
   private String createdBy;
@@ -93,6 +95,14 @@
     this.vaultAccountIdentifier = vaultAccountIdentifier;
   }
 
+  public String getChequesReceivableAccount() {
+    return this.chequesReceivableAccount;
+  }
+
+  public void setChequesReceivableAccount(final String chequesReceivableAccount) {
+    this.chequesReceivableAccount = chequesReceivableAccount;
+  }
+
   public String getAssignedEmployee() {
     return this.assignedEmployee;
   }
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 387c4a3..f37bb9f 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
@@ -17,6 +17,7 @@
 
 import io.mifos.core.lang.validation.constraints.ValidIdentifier;
 
+import javax.validation.constraints.DecimalMax;
 import javax.validation.constraints.DecimalMin;
 import javax.validation.constraints.NotNull;
 import java.math.BigDecimal;
@@ -39,6 +40,7 @@
   @NotNull
   private Adjustment adjustment;
   @DecimalMin("0.00")
+  @DecimalMax("9999999999.99999")
   private BigDecimal amount;
   @ValidIdentifier(optional = true)
   private String assignedEmployeeIdentifier;
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 5079d01..9581f14 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
@@ -43,14 +43,14 @@
   private String productIdentifier;
   @ValidIdentifier(optional = true)
   private String productCaseIdentifier;
-  @ValidIdentifier
+  @ValidIdentifier(maxLength = 34)
   private String customerAccountIdentifier;
-  @ValidIdentifier(optional = true)
+  @ValidIdentifier(maxLength = 34, optional = true)
   private String targetAccountIdentifier;
   @ValidIdentifier
   private String clerk;
   @NotNull
-  @DecimalMin(value = "0.001")
+  @DecimalMin(value = "0.000")
   @DecimalMax(value = "9999999999.99999")
   private BigDecimal amount;
   private State state;
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 39f8399..d3ac3f8 100644
--- a/component-test/src/main/java/io/mifos/teller/TestTellerOperation.java
+++ b/component-test/src/main/java/io/mifos/teller/TestTellerOperation.java
@@ -160,7 +160,75 @@
     tellerTransaction.setCustomerAccountIdentifier(RandomStringUtils.randomAlphanumeric(32));
     tellerTransaction.setCustomerIdentifier(RandomStringUtils.randomAlphanumeric(32));
     tellerTransaction.setClerk(AbstractTellerTest.TEST_USER);
-    tellerTransaction.setAmount(commonAmount);
+    tellerTransaction.setAmount(this.commonAmount);
+
+    final Account account = new Account();
+    account.setBalance(this.commonAmount.doubleValue());
+    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));
+    Mockito.doAnswer(invocation -> Collections.emptyList())
+        .when(super.depositAccountManagementServiceSpy).fetchProductInstances(tellerTransaction.getCustomerIdentifier());
+
+    super.testSubject.post(teller.getCode(), tellerTransaction);
+  }
+
+  @Test
+  public void shouldCloseAccountZeroBalance() 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_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(BigDecimal.ZERO);
+
+    final Account account = new Account();
+    account.setBalance(0.00D);
+    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));
+    Mockito.doAnswer(invocation -> Collections.emptyList())
+        .when(super.depositAccountManagementServiceSpy).fetchProductInstances(tellerTransaction.getCustomerIdentifier());
+
+    super.testSubject.post(teller.getCode(), tellerTransaction);
+  }
+
+  @Test(expected = TransactionProcessingException.class)
+  public void shouldNotCloseAccountRemainingBalance() 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_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(this.commonAmount);
 
     final Account account = new Account();
     account.setBalance(2000.00D);
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
index 799f2b9..fbd029f 100644
--- a/component-test/src/main/java/io/mifos/teller/util/TellerGenerator.java
+++ b/component-test/src/main/java/io/mifos/teller/util/TellerGenerator.java
@@ -30,8 +30,9 @@
     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.setTellerAccountIdentifier(RandomStringUtils.randomAlphanumeric(34));
+    teller.setVaultAccountIdentifier(RandomStringUtils.randomAlphanumeric(34));
+    teller.setChequesReceivableAccount(RandomStringUtils.randomAlphanumeric(34));
     teller.setCashdrawLimit(BigDecimal.valueOf(10000L));
 
     return 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 67099ea..571b92f 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
@@ -124,6 +124,7 @@
 
         tellerEntity.setTellerAccountIdentifier(teller.getTellerAccountIdentifier());
         tellerEntity.setVaultAccountIdentifier(teller.getVaultAccountIdentifier());
+        tellerEntity.setChequesReceivableAccount(teller.getChequesReceivableAccount());
         tellerEntity.setCashdrawLimit(teller.getCashdrawLimit());
         tellerEntity.setLastModifiedBy(UserContextHolder.checkedGetUser());
         tellerEntity.setLastModifiedOn(LocalDateTime.now(Clock.systemUTC()));
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 d1902a4..3ff7665 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
@@ -32,6 +32,7 @@
     teller.setVaultAccountIdentifier(tellerEntity.getVaultAccountIdentifier());
     teller.setCashdrawLimit(tellerEntity.getCashdrawLimit());
     teller.setAssignedEmployee(tellerEntity.getAssignedEmployeeIdentifier());
+    teller.setChequesReceivableAccount(tellerEntity.getChequesReceivableAccount());
     teller.setState(tellerEntity.getState());
     if (tellerEntity.getCreatedBy() != null) {
       teller.setCreatedBy(tellerEntity.getCreatedBy());
@@ -52,6 +53,7 @@
     tellerEntity.setOfficeIdentifier(officeIdentifier);
     tellerEntity.setTellerAccountIdentifier(teller.getTellerAccountIdentifier());
     tellerEntity.setVaultAccountIdentifier(teller.getVaultAccountIdentifier());
+    tellerEntity.setChequesReceivableAccount(teller.getChequesReceivableAccount());
     tellerEntity.setCashdrawLimit(teller.getCashdrawLimit());
     tellerEntity.setAssignedEmployeeIdentifier(teller.getAssignedEmployee());
     if (teller.getState() != null) {
diff --git a/service/src/main/java/io/mifos/teller/service/internal/processor/ChequeTransactionHandler.java b/service/src/main/java/io/mifos/teller/service/internal/processor/ChequeTransactionHandler.java
index 3951e0c..0456fa1 100644
--- a/service/src/main/java/io/mifos/teller/service/internal/processor/ChequeTransactionHandler.java
+++ b/service/src/main/java/io/mifos/teller/service/internal/processor/ChequeTransactionHandler.java
@@ -19,6 +19,7 @@
 import io.mifos.teller.ServiceConstants;
 import io.mifos.teller.api.v1.domain.TellerTransaction;
 import io.mifos.teller.service.internal.mapper.ChequeMapper;
+import io.mifos.teller.service.internal.repository.TellerEntity;
 import io.mifos.teller.service.internal.repository.TellerRepository;
 import io.mifos.teller.service.internal.service.helper.ChequeService;
 import org.slf4j.Logger;
@@ -26,6 +27,8 @@
 import org.springframework.beans.factory.annotation.Qualifier;
 import org.springframework.stereotype.Component;
 
+import java.util.Optional;
+
 @Component
 public class ChequeTransactionHandler {
 
@@ -42,8 +45,11 @@
     this.tellerRepository = tellerRepository;
   }
 
-  public void processCheque(final TellerTransaction tellerTransaction) {
+  public void processCheque(final String tellerCode, final TellerTransaction tellerTransaction) {
+    final Optional<TellerEntity> optionalTeller = this.tellerRepository.findByIdentifier(tellerCode);
     final ChequeTransaction chequeTransaction = new ChequeTransaction();
+    optionalTeller.ifPresent(tellerEntity ->
+        chequeTransaction.setChequesReceivableAccount(tellerEntity.getChequesReceivableAccount()));
     chequeTransaction.setCreditorAccountNumber(tellerTransaction.getCustomerAccountIdentifier());
     chequeTransaction.setCheque(ChequeMapper.map(tellerTransaction.getCheque()));
 
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 48f5c38..efd6a69 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
@@ -64,7 +64,7 @@
         this.portfolioTransactionHandler.processRepayment(tellerCode, tellerTransaction);
         break;
       case ServiceConstants.TX_CHEQUE:
-        this.chequeTransactionHandler.processCheque(tellerTransaction);
+        this.chequeTransactionHandler.processCheque(tellerCode, tellerTransaction);
         break;
       default:
         throw new IllegalArgumentException("Unsupported TX type " + tellerTransaction.getTransactionType());
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
index 8cf0591..949abf1 100644
--- 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
@@ -45,10 +45,12 @@
   private String officeIdentifier;
   @Column(name = "cashdraw_limit", nullable = false)
   private BigDecimal cashdrawLimit;
-  @Column(name = "teller_account_identifier", nullable = false, length = 32)
+  @Column(name = "teller_account_identifier", nullable = false, length = 34)
   private String tellerAccountIdentifier;
-  @Column(name = "vault_account_identifier", nullable = false, length = 32)
+  @Column(name = "vault_account_identifier", nullable = false, length = 34)
   private String vaultAccountIdentifier;
+  @Column(name = "cheques_receivable_account", nullable = false, length = 34)
+  private String chequesReceivableAccount;
   @Column(name = "assigned_employee_identifier", nullable = true, length = 32)
   private String assignedEmployeeIdentifier;
   @Column(name = "a_state", nullable = false, length = 256)
@@ -132,6 +134,14 @@
     this.vaultAccountIdentifier = vaultAccountIdentifier;
   }
 
+  public String getChequesReceivableAccount() {
+    return this.chequesReceivableAccount;
+  }
+
+  public void setChequesReceivableAccount(final String chequesReceivableAccount) {
+    this.chequesReceivableAccount = chequesReceivableAccount;
+  }
+
   public String getAssignedEmployeeIdentifier() {
     return this.assignedEmployeeIdentifier;
   }
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 3c94a02..2d80e90 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
@@ -29,6 +29,8 @@
 import org.springframework.stereotype.Service;
 
 import java.math.BigDecimal;
+import java.math.MathContext;
+import java.math.RoundingMode;
 import java.util.ArrayList;
 import java.util.HashMap;
 import java.util.List;
@@ -65,23 +67,28 @@
     final HashMap<String, Action> mappedActions = new HashMap<>(actions.size());
     actions.forEach(action -> mappedActions.put(action.getIdentifier(), action));
 
+    final MathContext mathContext = new MathContext(2, RoundingMode.HALF_EVEN);
     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
-          && 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()) {
-          charge.setAmount(
-              tellerTransaction.getAmount().divide(BigDecimal.valueOf(100)).multiply(BigDecimal.valueOf(productCharge.getAmount()))
-          );
-        } else {
-          charge.setAmount(BigDecimal.valueOf(productCharge.getAmount()));
+      if (productCharge.getAmount() > 0.00D) {
+        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()) {
+            charge.setAmount(
+                tellerTransaction.getAmount().multiply(
+                    BigDecimal.valueOf(productCharge.getAmount()).divide(BigDecimal.valueOf(100.00D), mathContext)
+                )
+            );
+          } else {
+            charge.setAmount(BigDecimal.valueOf(productCharge.getAmount()));
+          }
+          charges.add(charge);
         }
-        charges.add(charge);
       }
     });
     return charges;
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 0903f12..48ea9c0 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
@@ -20,6 +20,7 @@
 import io.mifos.anubis.annotation.Permittable;
 import io.mifos.core.api.util.UserContextHolder;
 import io.mifos.core.command.gateway.CommandGateway;
+import io.mifos.core.lang.DateConverter;
 import io.mifos.core.lang.ServiceException;
 import io.mifos.teller.ServiceConstants;
 import io.mifos.teller.api.v1.PermittableGroupIds;
@@ -50,6 +51,8 @@
 
 import javax.validation.Valid;
 import java.math.BigDecimal;
+import java.time.Clock;
+import java.time.LocalDate;
 import java.util.List;
 import java.util.Optional;
 
@@ -166,6 +169,14 @@
       }
     }
 
+    if (transactionType.equals(ServiceConstants.TX_CHEQUE)) {
+      final LocalDate dateIssued = DateConverter.dateFromIsoString(tellerTransaction.getCheque().getDateIssued());
+      final LocalDate sixMonth = LocalDate.now(Clock.systemUTC()).minusMonths(6);
+      if (dateIssued.isBefore(sixMonth)) {
+        throw ServiceException.conflict("Cheque is older than 6 month.");
+      }
+    }
+
     final Optional<Account> optionalCustomerAccount =
         this.accountingService.findAccount(tellerTransaction.getCustomerAccountIdentifier());
     if (!optionalCustomerAccount.isPresent()) {
@@ -180,12 +191,18 @@
       if (transactionType.equals(ServiceConstants.TX_ACCOUNT_TRANSFER)
           || transactionType.equals(ServiceConstants.TX_CASH_WITHDRAWAL)
           || transactionType.equals(ServiceConstants.TX_CLOSE_ACCOUNT)) {
-
-
         if (tellerTransaction.getAmount().compareTo(BigDecimal.valueOf(customerAccount.getBalance())) > 0 ) {
           throw ServiceException.conflict("Not enough balance.");
         }
       }
+
+      if (transactionType.equals(ServiceConstants.TX_CLOSE_ACCOUNT)) {
+        final BigDecimal newBalance =
+            BigDecimal.valueOf(customerAccount.getBalance()).subtract(tellerTransaction.getAmount());
+        if (newBalance.compareTo(BigDecimal.ZERO) > 0) {
+          throw ServiceException.conflict("Account has remaining balance");
+        }
+      }
     }
 
     if (tellerTransaction.getTargetAccountIdentifier() != null &&
diff --git a/service/src/main/resources/db/migrations/mariadb/V3__add_cheques_receivable_to_teller.sql b/service/src/main/resources/db/migrations/mariadb/V3__add_cheques_receivable_to_teller.sql
new file mode 100644
index 0000000..2d1b802
--- /dev/null
+++ b/service/src/main/resources/db/migrations/mariadb/V3__add_cheques_receivable_to_teller.sql
@@ -0,0 +1,23 @@
+--
+-- 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.
+--
+
+ALTER TABLE tajet_teller MODIFY teller_account_identifier VARCHAR(34);
+ALTER TABLE tajet_teller MODIFY vault_account_identifier VARCHAR(34);
+ALTER TABLE tajet_teller ADD cheques_receivable_account VARCHAR(34);
+
+
+ALTER TABLE tajet_teller_transactions MODIFY customer_account_identifier VARCHAR(34);
+ALTER TABLE tajet_teller_transactions MODIFY target_account_identifier VARCHAR(34);
\ No newline at end of file