block account/amount/credit/debit

Project: http://git-wip-us.apache.org/repos/asf/fineract/repo
Commit: http://git-wip-us.apache.org/repos/asf/fineract/commit/fe3741c2
Tree: http://git-wip-us.apache.org/repos/asf/fineract/tree/fe3741c2
Diff: http://git-wip-us.apache.org/repos/asf/fineract/diff/fe3741c2

Branch: refs/heads/develop
Commit: fe3741c2cebfcceb4615f07dd0a7a7260410c149
Parents: 18e8585
Author: ShruthiRajaram <[email protected]>
Authored: Wed Jun 21 13:21:36 2017 +0530
Committer: ShruthiRajaram <[email protected]>
Committed: Wed Jun 21 13:21:36 2017 +0530

----------------------------------------------------------------------
 api-docs/apiLive.htm                            | 426 ++++++++++++++++++-
 .../ClientSavingsIntegrationTest.java           | 111 +++++
 .../common/savings/SavingsAccountHelper.java    |  85 +++-
 .../common/savings/SavingsStatusChecker.java    |  25 ++
 .../commands/service/CommandWrapperBuilder.java |  73 ++++
 .../savings/SavingsAccountTransactionType.java  |  22 +-
 .../portfolio/savings/SavingsApiConstants.java  |  20 +
 .../SavingsAccountTransactionsApiResource.java  |  11 +-
 .../savings/api/SavingsAccountsApiResource.java |  22 +-
 .../data/SavingsAccountSubStatusEnumData.java   |  11 +-
 .../savings/data/SavingsAccountSummaryData.java |   4 +-
 .../SavingsAccountTransactionDataValidator.java |  71 ++++
 .../data/SavingsAccountTransactionEnumData.java |  12 +
 .../savings/domain/SavingsAccount.java          | 191 ++++++++-
 .../domain/SavingsAccountDomainServiceJpa.java  |   4 +
 .../domain/SavingsAccountSubStatusEnum.java     |  26 +-
 .../domain/SavingsAccountTransaction.java       |  34 ++
 .../SavingsAccountBlockedException.java         |  29 ++
 .../SavingsAccountCreditsBlockedException.java  |  29 ++
 .../SavingsAccountDebitsBlockedException.java   |  30 ++
 ...ckCreditsToSavingsAccountCommandHandler.java |  47 ++
 ...kDebitsFromSavingsAccountCommandHandler.java |  47 ++
 .../BlockSavingsAccountCommandHandler.java      |  47 ++
 .../HoldAmountSavingsAccountCommandHandler.java |  47 ++
 ...leaseAmountSavingsAccountCommandHandler.java |  48 +++
 ...ckCreditsToSavingsAccountCommandHandler.java |  47 ++
 ...kDebitsFromSavingsAccountCommandHandler.java |  46 ++
 .../UnblockSavingsAccountCommandHandler.java    |  46 ++
 .../DepositAccountReadPlatformServiceImpl.java  |   3 +-
 .../SavingsAccountReadPlatformServiceImpl.java  |   8 +-
 .../SavingsAccountWritePlatformService.java     |  16 +
 ...ntWritePlatformServiceJpaRepositoryImpl.java | 137 ++++++
 .../savings/service/SavingsEnumerations.java    |  31 +-
 ...9__savings_account_transaction_releaseId.sql |  44 ++
 34 files changed, 1824 insertions(+), 26 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/fineract/blob/fe3741c2/api-docs/apiLive.htm
----------------------------------------------------------------------
diff --git a/api-docs/apiLive.htm b/api-docs/apiLive.htm
index 41ad457..bc0c43e 100644
--- a/api-docs/apiLive.htm
+++ b/api-docs/apiLive.htm
@@ -630,6 +630,54 @@
                                                                <td></td>
                                                        </tr>
                                                        <tr>
+                                                               <td></td>
+                                                               
<td>savingsaccounts/{accountId}?command=block</td>
+                                                               <td><a 
href="#savingsaccounts_block">Block savings account</a></td>
+                                                               <td></td>
+                                                               <td></td>
+                                                               <td></td>
+                                                       </tr>
+                                                       <tr>
+                                                               <td></td>
+                                                               
<td>savingsaccounts/{accountId}?command=unblock</td>
+                                                               <td><a 
href="#savingsaccounts_unblock">Unblock savings account</a></td>
+                                                               <td></td>
+                                                               <td></td>
+                                                               <td></td>
+                                                       </tr>
+                                                       <tr>
+                                                               <td></td>
+                                                               
<td>savingsaccounts/{accountId}?command=blockCredit</td>
+                                                               <td><a 
href="#savingsaccounts_block_credit">Block Savings Account Credit 
Transactions</a></td>
+                                                               <td></td>
+                                                               <td></td>
+                                                               <td></td>
+                                                       </tr>
+                                                       <tr>
+                                                               <td></td>
+                                                               
<td>savingsaccounts/{accountId}?command=unblockCredit</td>
+                                                               <td><a 
href="#savingsaccounts_unblock_credit">Unblock Savings Account Credit 
Transactions</a></td>
+                                                               <td></td>
+                                                               <td></td>
+                                                               <td></td>
+                                                       </tr>
+                                                       <tr>
+                                                               <td></td>
+                                                               
<td>savingsaccounts/{accountId}?command=blockDebit</td>
+                                                               <td><a 
href="#savingsaccounts_block_debit">Block Savings Account Debit 
Transactions</a></td>
+                                                               <td></td>
+                                                               <td></td>
+                                                               <td></td>
+                                                       </tr>
+                                                       <tr>
+                                                               <td></td>
+                                                               
<td>savingsaccounts/{accountId}?command=unblockDebit</td>
+                                                               <td><a 
href="#savingsaccounts_unblock_debit">Unblock Savings Account Debit 
Transactions</a></td>
+                                                               <td></td>
+                                                               <td></td>
+                                                               <td></td>
+                                                       </tr>
+                                                       <tr>
                                                                <td><a 
href="#savingsaccounts_transactions">Savings Transactions</a></td>
                                                                
<td>savingsaccounts/{accountId}/transactions?command=deposit</td>
                                                                <td><a 
href="#savingsaccounts_deposit">Make a deposit</a></td>
@@ -663,6 +711,22 @@
                                                        </tr>
                                                        <tr>
                                                                <td></td>
+                                                               
<td>savingsaccounts/{accountId}/transactions/{transactionId}?command=holdAmount</td>
+                                                               <td><a 
href="#savingsaccounts_hold_amount">Hold Amount</a></td>
+                                                               <td></td>
+                                                               <td></td>
+                                                               <td></td>
+                                                       </tr>
+                                                       <tr>
+                                                               <td></td>
+                                                               
<td>savingsaccounts/{accountId}/transactions/{transactionId}?command=releaseAmount</td>
+                                                               <td><a 
href="#savingsaccounts_release_amount">Release Amount</a></td>
+                                                               <td></td>
+                                                               <td></td>
+                                                               <td></td>
+                                                       </tr>
+                                                       <tr>
+                                                               <td></td>
                                                                
<td>savingsaccounts/{accountId}/transactions/template</td>
                                                                <td></td>
                                                                <td><a 
href="#savingsaccounts_transactions_template">Retrieve savings account 
transaction template</a></td>
@@ -26243,7 +26307,248 @@ Request Body:
                </code>
            </div>
        </div>
+<a id="savingsaccounts_block" name="savingsaccounts_block" 
class="old-syle-anchor">&nbsp;</a>
+       <div class="method-section">
+           <div class="method-description">
+               <h2>Block Savings Account</h2>
+               <p>
+                       Blocks Savings account from all types of credit and 
debit transactions
+               </p>
+           </div>
+           <div class="method-example">
+               <code class="method-declaration">POST https://Domain 
Name/api/v1/savingsaccounts/{savingsId}?command=block</code>
+               <code class="method-request">POST savingsaccount/1?command=block
+Content-Type: application/json
+Request Body:
+{
+}
+                       </code>
+               <code class="method-response">
+{  
+   "officeId":1,
+   "clientId":1,
+   "savingsId":1,
+   "resourceId":1,
+   "changes":{  
+      "subStatus":{  
+         "id":400,
+         "code":"SavingsAccountSubStatusEnum.block",
+         "value":"Block",
+         "none":false,
+         "inactive":false,
+         "dormant":false,
+         "escheat":false,
+         "block":true,
+         "blockCredit":false,
+         "blockDebit":false
+      }
+   }
+}
+               </code>
+           </div>
+       </div>
+
+<a id="savingsaccounts_unblock" name="savingsaccounts_unblock" 
class="old-syle-anchor">&nbsp;</a>
+       <div class="method-section">
+           <div class="method-description">
+               <h2>Unblock Savings Account</h2>
+               <p>
+                       Unblock a blocked account. On unblocking account, user 
can perform debit and credit transactions
+               </p>
+           </div>
+           <div class="method-example">
+               <code class="method-declaration">POST https://Domain 
Name/api/v1/savingsaccounts/{savingsId}?command=unblock</code>
+               <code class="method-request">POST 
savingsaccount/1?command=unblock
+Content-Type: application/json
+Request Body:
+{
+}
+                       </code>
+               <code class="method-response">
+{  
+   "officeId":1,
+   "clientId":1,
+   "savingsId":1,
+   "resourceId":1,
+   "changes":{  
+      "subStatus":{  
+         "id":0,
+         "code":"SavingsAccountSubStatusEnum.none",
+         "value":"None",
+         "none":true,
+         "inactive":false,
+         "dormant":false,
+         "escheat":false,
+         "block":false,
+         "blockCredit":false,
+         "blockDebit":false
+      }
+   }
+}
+               </code>
+           </div>
+       </div>
+       
+<a id="savingsaccounts_block_credit" name="savingsaccounts_block_credit" 
class="old-syle-anchor">&nbsp;</a>
+       <div class="method-section">
+           <div class="method-description">
+               <h2>Block Savings Account Credit transactions</h2>
+               <p>
+                       Savings account will be blocked from all types of 
credit transactions.
+               </p>
+           </div>
+           <div class="method-example">
+               <code class="method-declaration">POST https://Domain 
Name/api/v1/savingsaccounts/{savingsId}?command=blockCredit</code>
+               <code class="method-request">POST 
savingsaccount/1?command=blockCredit
+Content-Type: application/json
+Request Body:
+{
+}
+                       </code>
+               <code class="method-response">
+{  
+   "officeId":1,
+   "clientId":1,
+   "savingsId":1,
+   "resourceId":1,
+   "changes":{  
+      "subStatus":{  
+        "id":500,
+         "code":"SavingsAccountSubStatusEnum.blockcredit",
+         "value":"BlockCredit",
+         "none":false,
+         "inactive":false,
+         "dormant":false,
+         "escheat":false,
+         "block":false,
+         "blockCredit":true,
+         "blockDebit":false
+      }
+   }
+}
+               </code>
+           </div>
+       </div>
+       
+<a id="savingsaccounts_unblock_credit" name="savingsaccounts_unblock_credit" 
class="old-syle-anchor">&nbsp;</a>
+       <div class="method-section">
+           <div class="method-description">
+               <h2>Unblock Savings Account Credit transactions</h2>
+               <p>It unblocks the Saving account's credit operations. Now all 
types of credits can be transacted to Savings account
+               </p>
+           </div>
+           <div class="method-example">
+               <code class="method-declaration">POST https://Domain 
Name/api/v1/savingsaccounts/{savingsId}?command=unblockCredit</code>
+               <code class="method-request">POST 
savingsaccount/1?command=unblockCredit
+Content-Type: application/json
+Request Body:
+{
+}
+                       </code>
+               <code class="method-response">
+{  
+   "officeId":1,
+   "clientId":1,
+   "savingsId":1,
+   "resourceId":1,
+   "changes":{  
+      "subStatus":{  
+        "id":0,
+         "code":"SavingsAccountSubStatusEnum.none",
+         "value":"None",
+         "none":true,
+         "inactive":false,
+         "dormant":false,
+         "escheat":false,
+         "block":false,
+         "blockCredit":false,
+         "blockDebit":false
+      }
+   }
+}
+               </code>
+           </div>
+       </div>
+       
+       
+<a id="savingsaccounts_block_debit" name="savingsaccounts_block_debit" 
class="old-syle-anchor">&nbsp;</a>
+       <div class="method-section">
+           <div class="method-description">
+               <h2>Block Savings Account Debit transactions</h2>
+               <p> All types of debit operations from Savings account wil be 
blocked</p>
+           </div>
+           <div class="method-example">
+               <code class="method-declaration">POST https://Domain 
Name/api/v1/savingsaccounts/{savingsId}?command=blockDebit</code>
+               <code class="method-request">POST 
savingsaccount/1?command=blockDebit
+Content-Type: application/json
+Request Body:
+{
+}
+                       </code>
+               <code class="method-response">
+{  
+   "officeId":1,
+   "clientId":1,
+   "savingsId":1,
+   "resourceId":1,
+   "changes":{  
+      "subStatus":{  
+        "id":600,
+         "code":"SavingsAccountSubStatusEnum.blockdebit",
+         "value":"BlockDebit",
+         "none":false,
+         "inactive":false,
+         "dormant":false,
+         "escheat":false,
+         "block":false,
+         "blockCredit":false,
+         "blockDebit":true
+      }
+   }
+}
+                       </code>
+               </div>
+       </div>
 
+<a id="savingsaccounts_unblock_debit" name="savingsaccounts_unblock_debit" 
class="old-syle-anchor">&nbsp;</a>
+       <div class="method-section">
+           <div class="method-description">
+               <h2>Unblock Savings Account debit transactions</h2>
+               <p>It unblocks the Saving account's debit operations. Now all 
types of debits can be transacted from Savings account
+               </p>
+           </div>
+           <div class="method-example">
+               <code class="method-declaration">POST https://Domain 
Name/api/v1/savingsaccounts/{savingsId}?command=unblockDebit</code>
+               <code class="method-request">POST 
savingsaccount/1?command=unblockDebit
+Content-Type: application/json
+Request Body:
+{
+}
+                       </code>
+               <code class="method-response">
+{  
+   "officeId":1,
+   "clientId":1,
+   "savingsId":1,
+   "resourceId":1,
+   "changes":{  
+      "subStatus":{  
+        "id":0,
+         "code":"SavingsAccountSubStatusEnum.none",
+         "value":"None",
+         "none":true,
+         "inactive":false,
+         "dormant":false,
+         "escheat":false,
+         "block":false,
+         "blockCredit":false,
+         "blockDebit":false
+      }
+   }
+}
+               </code>
+           </div>
+       </div>
        <a id="savingsaccounts_list" name="savingsaccounts_list" 
class="old-syle-anchor">&nbsp;</a>
     <div class="method-section">
         <div class="method-description">
@@ -26417,7 +26722,8 @@ Request Body:
       "nameCode": "currency.USD",
       "displayLabel": "US Dollar ($)"
     },
-    "accountBalance": 0
+    "accountBalance": 0,
+       "availableBalance": 0
   }
 }
                </code>
@@ -26787,6 +27093,60 @@ No Request Body:
                </code>
            </div>
        </div>
+<a id="savingsaccounts_hold_amount" name="savingsaccounts_hold_amount" 
class="old-syle-anchor">&nbsp;</a>
+       <div class="method-section">
+           <div class="method-description">
+               <h2>Hold Amount</h2>
+               <p>Hold amount enables the user to hold/block/lien the 
specified amount from the account</p>
+           </div>
+           <div class="method-example">
+               <code class="method-declaration">POST https://Domain 
Name/api/v1/savingsaccounts/4/transactions?command=holdAmount</code>
+               <code class="method-request">POST 
savingsaccounts/4/transactions?command=holdAmount
+Content-Type: application/json
+Request Body:
+{
+   transactionDate:"15 June 2017",
+   transactionAmount:"200",
+   locale:"en",
+   dateFormat:"dd MMMM yyyy"
+}
+               </code>
+               <code class="method-response">
+{
+  "officeId":1,
+  "clientId":2,
+  "savingsId":4,
+  "resourceId":35
+}
+               </code>
+           </div>
+       </div>
+<a id="savingsaccounts_release_amount" name="savingsaccounts_release_amount" 
class="old-syle-anchor">&nbsp;</a>
+       <div class="method-section">
+           <div class="method-description">
+               <h2>Release Amount</h2>
+               <p>Release amount removes the hold/block/lien already placed on 
an amount in the account. </p>
+           </div>
+           <div class="method-example">
+               <code class="method-declaration">POST https://Domain 
Name/api/v1/savingsaccounts/4/transactions/35?command=releaseAmount</code>
+               <code class="method-request">POST 
savingsaccounts/4/transactions/35?command=releaseAmount
+Content-Type: application/json
+No Request Body:
+{
+  
+}
+               </code>
+               <code class="method-response">
+{
+   "officeId":1,
+   "clientId":2,
+   "savingsId":4,
+   "resourceId":36
+}
+               </code>
+           </div>
+       </div>
+
 <!-- end of savings accounts api -->
 
 <!-- start of Savings charges content-->
@@ -48362,6 +48722,54 @@ No Request Body:
                                        <td></td>
                                </tr>
                                <tr>
+                                       <td></td>
+                                       
<td>savingsaccounts/{accountId}?command=block</td>
+                                       <td><a 
href="#savingsaccounts_block">Block savings account</a></td>
+                                       <td></td>
+                                       <td></td>
+                                       <td></td>
+                               </tr>
+                               <tr>
+                                       <td></td>
+                                       
<td>savingsaccounts/{accountId}?command=unblock</td>
+                                       <td><a 
href="#savingsaccounts_unblock">UnBlock savings account</a></td>
+                                       <td></td>
+                                       <td></td>
+                                       <td></td>
+                               </tr>
+                               <tr>
+                                       <td></td>
+                                       
<td>savingsaccounts/{accountId}?command=blockCredit</td>
+                                       <td><a 
href="#savingsaccounts_block_credit">Block Savings Account Credit 
transactions</a></td>
+                                       <td></td>
+                                       <td></td>
+                                       <td></td>
+                               </tr>
+                               <tr>
+                                       <td></td>
+                                       
<td>savingsaccounts/{accountId}?command=unblockCredit</td>
+                                       <td><a 
href="#savingsaccounts_unblock_credit">Unblock Savings Account Credit 
transactions</a></td>
+                                       <td></td>
+                                       <td></td>
+                                       <td></td>
+                               </tr>
+                               <tr>
+                                       <td></td>
+                                       
<td>savingsaccounts/{accountId}?command=blockDebit</td>
+                                       <td><a 
href="#savingsaccounts_block_debit">Block Savings Account Debit 
transactions</a></td>
+                                       <td></td>
+                                       <td></td>
+                                       <td></td>
+                               </tr>
+                               <tr>
+                                       <td></td>
+                                       
<td>savingsaccounts/{accountId}?command=unblockDebit</td>
+                                       <td><a 
href="#savingsaccounts_unblock_debit">Unblock Savings Account Debit 
transactions</a></td>
+                                       <td></td>
+                                       <td></td>
+                                       <td></td>
+                               </tr>   
+                               <tr>
                                        <td><a 
href="#savingsaccounts_transactions">Savings Transactions</a></td>
                                        
<td>savingsaccounts/{accountId}/transactions?command=deposit</td>
                                        <td><a 
href="#savingsaccounts_deposit">Make a deposit</a></td>
@@ -48395,6 +48803,22 @@ No Request Body:
                                </tr>
                                <tr>
                                        <td></td>
+                                       
<td>savingsaccounts/{accountId}/transactions/{transactionId}?command=holdAmount</td>
+                                       <td><a 
href="#savingsaccounts_hold_amount">Hold Amount</a></td>
+                                       <td></td>
+                                       <td></td>
+                                       <td></td>
+                               </tr>
+                               <tr>
+                                       <td></td>
+                                       
<td>savingsaccounts/{accountId}/transactions/{transactionId}?command=releaseAmount</td>
+                                       <td><a 
href="#savingsaccounts_release_amount">Release Amount</a></td>
+                                       <td></td>
+                                       <td></td>
+                                       <td></td>
+                               </tr>
+                               <tr>
+                                       <td></td>
                                        
<td>savingsaccounts/{accountId}/transactions/template</td>
                                        <td></td>
                                        <td><a 
href="#savingsaccounts_transactions_template">Retrieve savings account 
transaction template</a></td>

http://git-wip-us.apache.org/repos/asf/fineract/blob/fe3741c2/fineract-provider/src/integrationTest/java/org/apache/fineract/integrationtests/ClientSavingsIntegrationTest.java
----------------------------------------------------------------------
diff --git 
a/fineract-provider/src/integrationTest/java/org/apache/fineract/integrationtests/ClientSavingsIntegrationTest.java
 
b/fineract-provider/src/integrationTest/java/org/apache/fineract/integrationtests/ClientSavingsIntegrationTest.java
index 7a49c76..b279163 100755
--- 
a/fineract-provider/src/integrationTest/java/org/apache/fineract/integrationtests/ClientSavingsIntegrationTest.java
+++ 
b/fineract-provider/src/integrationTest/java/org/apache/fineract/integrationtests/ClientSavingsIntegrationTest.java
@@ -2115,4 +2115,115 @@ public class ClientSavingsIntegrationTest {
      * assertEquals("Verifying Interest Calculation", new Float("238.3399"),
      * savingsInterest); }
      */
+    
+    @SuppressWarnings("unchecked")
+    @Test
+    public void testSavingsAccountBlockStatus() {
+        this.savingsAccountHelper = new SavingsAccountHelper(this.requestSpec, 
this.responseSpec);
+        SavingsAccountHelper savingsAccountHelperValidationError = new 
SavingsAccountHelper(this.requestSpec,
+                new ResponseSpecBuilder().build());
+
+        final Integer clientID = ClientHelper.createClient(this.requestSpec, 
this.responseSpec);
+        Assert.assertNotNull(clientID);
+        final String minBalanceForInterestCalculation = null;
+        final String minRequiredBalance = null;
+        final String enforceMinRequiredBalance = "false";
+        final boolean allowOverdraft = false;
+        final Integer savingsProductID = 
createSavingsProduct(this.requestSpec, this.responseSpec, 
MINIMUM_OPENING_BALANCE,
+                minBalanceForInterestCalculation, minRequiredBalance, 
enforceMinRequiredBalance, allowOverdraft);
+        Assert.assertNotNull(savingsProductID);
+
+        final Integer savingsId = 
this.savingsAccountHelper.applyForSavingsApplication(clientID, 
savingsProductID, ACCOUNT_TYPE_INDIVIDUAL);
+        Assert.assertNotNull(savingsProductID);
+
+        HashMap savingsStatusHashMap = 
SavingsStatusChecker.getStatusOfSavings(this.requestSpec, this.responseSpec, 
savingsId);
+        SavingsStatusChecker.verifySavingsIsPending(savingsStatusHashMap);
+
+        savingsStatusHashMap = 
this.savingsAccountHelper.approveSavings(savingsId);
+        SavingsStatusChecker.verifySavingsIsApproved(savingsStatusHashMap);
+
+        savingsStatusHashMap = 
this.savingsAccountHelper.activateSavings(savingsId);
+        SavingsStatusChecker.verifySavingsIsActive(savingsStatusHashMap);
+
+        HashMap summary = 
this.savingsAccountHelper.getSavingsSummary(savingsId);
+        Float balance = new Float(MINIMUM_OPENING_BALANCE);
+
+        savingsStatusHashMap = 
this.savingsAccountHelper.blockSavings(savingsId);
+        SavingsStatusChecker.verifySavingsSubStatusblock(savingsStatusHashMap);
+
+        List<HashMap> error = (List) 
savingsAccountHelperValidationError.withdrawalFromSavingsAccount(savingsId, 
"100",
+                SavingsAccountHelper.TRANSACTION_DATE, 
CommonConstants.RESPONSE_ERROR);
+        
assertEquals("error.msg.saving.account.blocked.transaction.not.allowed",
+                error.get(0).get(CommonConstants.RESPONSE_ERROR_MESSAGE_CODE));
+
+        error = (List) 
savingsAccountHelperValidationError.depositToSavingsAccount(savingsId, "100", 
SavingsAccountHelper.TRANSACTION_DATE,
+                CommonConstants.RESPONSE_ERROR);
+        
assertEquals("error.msg.saving.account.blocked.transaction.not.allowed",
+                error.get(0).get(CommonConstants.RESPONSE_ERROR_MESSAGE_CODE));
+
+        savingsStatusHashMap = 
this.savingsAccountHelper.unblockSavings(savingsId);
+        
SavingsStatusChecker.verifySavingsSubStatusIsNone(savingsStatusHashMap);
+        Integer depositTransactionId = (Integer) 
this.savingsAccountHelper.depositToSavingsAccount(savingsId, DEPOSIT_AMOUNT,
+                SavingsAccountHelper.TRANSACTION_DATE, 
CommonConstants.RESPONSE_RESOURCE_ID);
+        HashMap depositTransaction = 
this.savingsAccountHelper.getSavingsTransaction(savingsId, 
depositTransactionId);
+        balance += new Float(DEPOSIT_AMOUNT);
+        assertEquals("Verifying Deposit Amount", new Float(DEPOSIT_AMOUNT), 
depositTransaction.get("amount"));
+
+        savingsStatusHashMap = this.savingsAccountHelper.blockDebit(savingsId);
+        
SavingsStatusChecker.verifySavingsSubStatusIsDebitBlocked(savingsStatusHashMap);
+        error = (List) 
savingsAccountHelperValidationError.withdrawalFromSavingsAccount(savingsId, 
"100",
+                SavingsAccountHelper.TRANSACTION_DATE, 
CommonConstants.RESPONSE_ERROR);
+        assertEquals("error.msg.savings.account.debit.transaction.not.allowed",
+                error.get(0).get(CommonConstants.RESPONSE_ERROR_MESSAGE_CODE));
+        
+        depositTransactionId = (Integer) 
this.savingsAccountHelper.depositToSavingsAccount(savingsId, DEPOSIT_AMOUNT,
+                SavingsAccountHelper.TRANSACTION_DATE, 
CommonConstants.RESPONSE_RESOURCE_ID);
+        depositTransaction = 
this.savingsAccountHelper.getSavingsTransaction(savingsId, 
depositTransactionId);
+        balance += new Float(DEPOSIT_AMOUNT);
+        assertEquals("Verifying Deposit Amount", new Float(DEPOSIT_AMOUNT), 
depositTransaction.get("amount"));
+
+        savingsStatusHashMap = 
this.savingsAccountHelper.unblockDebit(savingsId);
+        
SavingsStatusChecker.verifySavingsSubStatusIsNone(savingsStatusHashMap);
+        Integer withdrawTransactionId = (Integer) 
this.savingsAccountHelper.withdrawalFromSavingsAccount(savingsId, 
WITHDRAW_AMOUNT,
+                SavingsAccountHelper.TRANSACTION_DATE, 
CommonConstants.RESPONSE_RESOURCE_ID);
+        HashMap withdrawTransaction = 
this.savingsAccountHelper.getSavingsTransaction(savingsId, 
withdrawTransactionId);
+        balance -= new Float(WITHDRAW_AMOUNT);
+        assertEquals("Verifying Withdrawal Amount", new 
Float(WITHDRAW_AMOUNT), withdrawTransaction.get("amount"));
+
+        savingsStatusHashMap = 
this.savingsAccountHelper.blockCredit(savingsId);
+        
SavingsStatusChecker.verifySavingsSubStatusIsCreditBlocked(savingsStatusHashMap);
+        error = (List) 
savingsAccountHelperValidationError.depositToSavingsAccount(savingsId, "100", 
SavingsAccountHelper.TRANSACTION_DATE,
+                CommonConstants.RESPONSE_ERROR);
+        
assertEquals("error.msg.savings.account.credit.transaction.not.allowed",
+                error.get(0).get(CommonConstants.RESPONSE_ERROR_MESSAGE_CODE));
+        
+        withdrawTransactionId = (Integer) 
this.savingsAccountHelper.withdrawalFromSavingsAccount(savingsId, 
WITHDRAW_AMOUNT,
+                SavingsAccountHelper.TRANSACTION_DATE, 
CommonConstants.RESPONSE_RESOURCE_ID);
+        withdrawTransaction = 
this.savingsAccountHelper.getSavingsTransaction(savingsId, 
withdrawTransactionId);
+        balance -= new Float(WITHDRAW_AMOUNT);
+        assertEquals("Verifying Withdrawal Amount", new 
Float(WITHDRAW_AMOUNT), withdrawTransaction.get("amount"));
+
+        savingsStatusHashMap = 
this.savingsAccountHelper.unblockCredit(savingsId);
+        
SavingsStatusChecker.verifySavingsSubStatusIsNone(savingsStatusHashMap);
+        depositTransactionId = (Integer) 
this.savingsAccountHelper.depositToSavingsAccount(savingsId, DEPOSIT_AMOUNT,
+                SavingsAccountHelper.TRANSACTION_DATE, 
CommonConstants.RESPONSE_RESOURCE_ID);
+        depositTransaction = 
this.savingsAccountHelper.getSavingsTransaction(savingsId, 
depositTransactionId);
+        balance += new Float(DEPOSIT_AMOUNT);
+        assertEquals("Verifying Deposit Amount", new Float(DEPOSIT_AMOUNT), 
depositTransaction.get("amount"));
+
+        Integer holdTransactionId = (Integer) 
this.savingsAccountHelper.holdAmountInSavingsAccount(savingsId, 
String.valueOf(balance - 100),
+                SavingsAccountHelper.TRANSACTION_DATE, 
CommonConstants.RESPONSE_RESOURCE_ID);
+        error = (List) 
savingsAccountHelperValidationError.withdrawalFromSavingsAccount(savingsId, 
"300",
+                SavingsAccountHelper.TRANSACTION_DATE, 
CommonConstants.RESPONSE_ERROR);
+        
assertEquals("error.msg.savingsaccount.transaction.insufficient.account.balance",
+                error.get(0).get(CommonConstants.RESPONSE_ERROR_MESSAGE_CODE));
+
+        Integer releaseTransactionId = 
this.savingsAccountHelper.releaseAmount(savingsId, holdTransactionId);
+        withdrawTransactionId = (Integer) 
this.savingsAccountHelper.withdrawalFromSavingsAccount(savingsId, "300",
+                SavingsAccountHelper.TRANSACTION_DATE, 
CommonConstants.RESPONSE_RESOURCE_ID);
+        withdrawTransaction = 
this.savingsAccountHelper.getSavingsTransaction(savingsId, 
withdrawTransactionId);
+        balance -= new Float("300");
+        assertEquals("Verifying Withdrawal Amount", new Float("300"), 
withdrawTransaction.get("amount"));
+
+    }
 }
\ No newline at end of file

http://git-wip-us.apache.org/repos/asf/fineract/blob/fe3741c2/fineract-provider/src/integrationTest/java/org/apache/fineract/integrationtests/common/savings/SavingsAccountHelper.java
----------------------------------------------------------------------
diff --git 
a/fineract-provider/src/integrationTest/java/org/apache/fineract/integrationtests/common/savings/SavingsAccountHelper.java
 
b/fineract-provider/src/integrationTest/java/org/apache/fineract/integrationtests/common/savings/SavingsAccountHelper.java
index 0b24cb8..c2cd4f9 100644
--- 
a/fineract-provider/src/integrationTest/java/org/apache/fineract/integrationtests/common/savings/SavingsAccountHelper.java
+++ 
b/fineract-provider/src/integrationTest/java/org/apache/fineract/integrationtests/common/savings/SavingsAccountHelper.java
@@ -55,6 +55,15 @@ public class SavingsAccountHelper {
     private static final String WITHDRAW_SAVINGS_COMMAND = "withdrawal";
     private static final String MODIFY_TRASACTION_COMMAND = "modify";
     private static final String UNDO_TRASACTION_COMMAND = "undo";
+    
+    private static final String BLOCK_SAVINGS_COMMAND = "block";
+    private static final String UNBLOCK_SAVINGS_COMMAND = "unblock";
+    private static final String BLOCK_DEBITS_SAVINGS_COMMAND = "blockDebit";
+    private static final String UNBLOCK_DEBITS_SAVINGS_COMMAND = 
"unblockDebit";
+    private static final String BLOCK_CREDITS_SAVINGS_COMMAND = "blockCredit";
+    private static final String UNBLOCK_CREDITS_SAVINGS_COMMAND = 
"unblockCredit";
+    private static final String HOLD_AMOUNT_SAVINGS_COMMAND = "holdAmount";
+    private static final String RELEASE_AMOUNT_SAVINGS_COMMAND = 
"releaseAmount";
 
     public static final String CREATED_DATE = "08 January 2013";
     public static final String CREATED_DATE_PLUS_ONE = "09 January 2013";
@@ -64,6 +73,7 @@ public class SavingsAccountHelper {
     public static final String ACCOUNT_TYPE_INDIVIDUAL = "INDIVIDUAL";
 
     public static final String DATE_TIME_FORMAT = "dd MMMM yyyy HH:mm";
+    private static final Boolean isBlock = false;
 
     public SavingsAccountHelper(final RequestSpecification requestSpec, final 
ResponseSpecification responseSpec) {
         this.requestSpec = requestSpec;
@@ -138,20 +148,20 @@ public class SavingsAccountHelper {
         System.out.println("--------------------------------- APPROVING 
SAVINGS APPLICATION ------------------------------------");
         final String savingsOperationURL = 
createSavingsOperationURL(APPROVE_SAVINGS_COMMAND, savingsID);
         if (approvalDate == null || approvalDate == "")
-            return performSavingApplicationActions(savingsOperationURL, 
getApproveSavingsAsJSON());
-        return performSavingApplicationActions(savingsOperationURL, 
getApproveSavingsAsJsonOnDate(approvalDate));
+            return performSavingApplicationActions(savingsOperationURL, 
getApproveSavingsAsJSON(), isBlock);
+        return performSavingApplicationActions(savingsOperationURL, 
getApproveSavingsAsJsonOnDate(approvalDate), isBlock);
     }
 
     public HashMap undoApproval(final Integer savingsID) {
         System.out.println("--------------------------------- UNDO APPROVING 
SAVINGS APPLICATION -------------------------------");
         final String undoBodyJson = "{'note':'UNDO APPROVAL'}";
-        return 
performSavingApplicationActions(createSavingsOperationURL(UNDO_APPROVAL_SAVINGS_COMMAND,
 savingsID), undoBodyJson);
+        return 
performSavingApplicationActions(createSavingsOperationURL(UNDO_APPROVAL_SAVINGS_COMMAND,
 savingsID), undoBodyJson, isBlock);
     }
 
     public HashMap rejectApplication(final Integer savingsID) {
         System.out.println("--------------------------------- REJECT SAVINGS 
APPLICATION -------------------------------");
         return 
performSavingApplicationActions(createSavingsOperationURL(REJECT_SAVINGS_COMMAND,
 savingsID),
-                getRejectedSavingsAsJSON(CREATED_DATE_PLUS_ONE));
+                getRejectedSavingsAsJSON(CREATED_DATE_PLUS_ONE), isBlock);
     }
 
     public List rejectApplicationWithErrorCode(final Integer savingsId, final 
String date) {
@@ -163,18 +173,18 @@ public class SavingsAccountHelper {
     public HashMap withdrawApplication(final Integer savingsID) {
         System.out.println("--------------------------------- Withdraw SAVINGS 
APPLICATION -------------------------------");
         return 
performSavingApplicationActions(createSavingsOperationURL(WITHDRAWN_BY_CLIENT_SAVINGS_COMMAND,
 savingsID),
-                getWithdrawnSavingsAsJSON());
+                getWithdrawnSavingsAsJSON(), isBlock);
     }
 
     public HashMap activateSavings(final Integer savingsID) {
         System.out.println("---------------------------------- ACTIVATING 
SAVINGS APPLICATION ----------------------------------");
-        return 
performSavingApplicationActions(createSavingsOperationURL(ACTIVATE_SAVINGS_COMMAND,
 savingsID), getActivatedSavingsAsJSON());
+        return 
performSavingApplicationActions(createSavingsOperationURL(ACTIVATE_SAVINGS_COMMAND,
 savingsID), getActivatedSavingsAsJSON(), isBlock);
     }
 
     public HashMap closeSavingsAccount(final Integer savingsID, String 
withdrawBalance) {
         System.out.println("---------------------------------- CLOSE SAVINGS 
APPLICATION ----------------------------------");
         return 
performSavingApplicationActions(createSavingsOperationURL(CLOSE_SAVINGS_COMMAND,
 savingsID),
-                getCloseAccountJSON(withdrawBalance, LAST_TRANSACTION_DATE));
+                getCloseAccountJSON(withdrawBalance, LAST_TRANSACTION_DATE), 
isBlock);
     }
 
     public Object deleteSavingsApplication(final Integer savingsId, final 
String jsonAttributeToGetBack) {
@@ -251,6 +261,60 @@ public class SavingsAccountHelper {
         return Utils.performServerDelete(this.requestSpec, this.responseSpec, 
SAVINGS_ACCOUNT_URL + "/" + savingsId + "/charges/"
                 + chargeId + "?" + Utils.TENANT_IDENTIFIER, 
CommonConstants.RESPONSE_RESOURCE_ID);
     }
+    
+    public HashMap blockSavings(final Integer savingsID) {
+        System.out.println("---------------------------------- BLOCKING 
SAVINGS ACCOUNT ----------------------------------");
+        Boolean isBlock = true;
+        return 
performSavingApplicationActions(createSavingsOperationURL(BLOCK_SAVINGS_COMMAND,
 savingsID),
+                getActivatedSavingsAsJSON(), isBlock);
+    }
+
+    public HashMap unblockSavings(final Integer savingsID) {
+        System.out.println("---------------------------------- UNBLOCKING 
SAVINGS ACCOUNT ----------------------------------");
+        Boolean isBlock = true;
+        return 
performSavingApplicationActions(createSavingsOperationURL(UNBLOCK_SAVINGS_COMMAND,
 savingsID),
+                getActivatedSavingsAsJSON(), isBlock);
+    }
+
+    public HashMap blockDebit(final Integer savingsID) {
+        System.out.println("---------------------------------- BLOCKING DEBIT 
TRANSACTIONS ----------------------------------");
+        Boolean isBlock = true;
+        return 
performSavingApplicationActions(createSavingsOperationURL(BLOCK_DEBITS_SAVINGS_COMMAND,
 savingsID),
+                getActivatedSavingsAsJSON(), isBlock);
+    }
+
+    public HashMap unblockDebit(final Integer savingsID) {
+        System.out.println("---------------------------------- UNBLOCKING 
DEBIT TRANSACTIONS ----------------------------------");
+        Boolean isBlock = true;
+        return 
performSavingApplicationActions(createSavingsOperationURL(UNBLOCK_DEBITS_SAVINGS_COMMAND,
 savingsID),
+                getActivatedSavingsAsJSON(), isBlock);
+    }
+
+    public HashMap blockCredit(final Integer savingsID) {
+        System.out.println("---------------------------------- BLOCKING CREDIT 
TRANSACTIONS ----------------------------------");
+        Boolean isBlock = true;
+        return 
performSavingApplicationActions(createSavingsOperationURL(BLOCK_CREDITS_SAVINGS_COMMAND,
 savingsID),
+                getActivatedSavingsAsJSON(), isBlock);
+    }
+
+    public HashMap unblockCredit(final Integer savingsID) {
+        System.out.println("---------------------------------- UNBLOCKING 
CREDIT TRANSACTIONS ----------------------------------");
+        Boolean isBlock = true;
+        return 
performSavingApplicationActions(createSavingsOperationURL(UNBLOCK_CREDITS_SAVINGS_COMMAND,
 savingsID),
+                getActivatedSavingsAsJSON(), isBlock);
+    }
+
+    public Object holdAmountInSavingsAccount(final Integer savingsID, final 
String amount, String date, String jsonAttributeToGetback) {
+        System.out.println("--------------------------------- SAVINGS 
TRANSACTION HOLD AMOUNT--------------------------------");
+        return 
performSavingActions(createSavingsTransactionURL(HOLD_AMOUNT_SAVINGS_COMMAND, 
savingsID),
+                getSavingsTransactionJSON(amount, date), 
jsonAttributeToGetback);
+    }
+
+    public Integer releaseAmount(final Integer savingsId, final Integer 
transactionId) {
+        System.out.println("\n--------------------------------- SAVINGS 
TRANSACTION RELEASE AMOUNT--------------------------------");
+        return (Integer) 
performSavingActions(createAdjustTransactionURL(RELEASE_AMOUNT_SAVINGS_COMMAND, 
savingsId, transactionId),
+                getSavingsTransactionJSON("1000", LAST_TRANSACTION_DATE), 
CommonConstants.RESPONSE_RESOURCE_ID);
+    }
 
     private String getApproveSavingsAsJSON() {
         return getApproveSavingsAsJsonOnDate(CREATED_DATE_PLUS_ONE);
@@ -454,12 +518,15 @@ public class SavingsAccountHelper {
         return response;
     }
 
-    private HashMap performSavingApplicationActions(final String 
postURLForSavingsTransaction, final String jsonToBeSent) {
+    private HashMap performSavingApplicationActions(final String 
postURLForSavingsTransaction, final String jsonToBeSent, final Boolean isBlock) 
{
         HashMap status = null;
         final HashMap response = Utils.performServerPost(this.requestSpec, 
this.responseSpec, postURLForSavingsTransaction, jsonToBeSent,
                 CommonConstants.RESPONSE_CHANGES);
         if (response != null) {
             status = (HashMap) response.get("status");
+            if (isBlock != null && isBlock) {
+                status = (HashMap) response.get("subStatus");
+            }
         }
         return status;
     }
@@ -510,7 +577,7 @@ public class SavingsAccountHelper {
 
     public HashMap activateSavingsAccount(Integer savingsID, String 
activationDate) {
         return 
performSavingApplicationActions(createSavingsOperationURL(ACTIVATE_SAVINGS_COMMAND,
 savingsID),
-                getAccountActivationJSON(activationDate));
+                getAccountActivationJSON(activationDate), isBlock);
     }
 
     public Object inactivateCharge(final Integer chargeId, final Integer 
savingsId, final String jsonAttributeToGetBack) {

http://git-wip-us.apache.org/repos/asf/fineract/blob/fe3741c2/fineract-provider/src/integrationTest/java/org/apache/fineract/integrationtests/common/savings/SavingsStatusChecker.java
----------------------------------------------------------------------
diff --git 
a/fineract-provider/src/integrationTest/java/org/apache/fineract/integrationtests/common/savings/SavingsStatusChecker.java
 
b/fineract-provider/src/integrationTest/java/org/apache/fineract/integrationtests/common/savings/SavingsStatusChecker.java
index 3c6c387..4a7f636 100755
--- 
a/fineract-provider/src/integrationTest/java/org/apache/fineract/integrationtests/common/savings/SavingsStatusChecker.java
+++ 
b/fineract-provider/src/integrationTest/java/org/apache/fineract/integrationtests/common/savings/SavingsStatusChecker.java
@@ -113,5 +113,30 @@ public class SavingsStatusChecker {
         assertTrue("UNEXPECTED SAVINGS ACCOUNT SUB STATUS", 
getStatus(savingsStatusHashMap, "none"));
         System.out.println("Savings Application Sub Status:" + 
savingsStatusHashMap + "\n");
        }
+       
+       public static void verifySavingsSubStatusblock(HashMap 
savingsStatusHashMap) {
+        System.out.println(
+                "\n-------------------------------------- VERIFYING SAVINGS 
ACCOUNT IS BLOCKED ------------------------------------");
+        assertTrue("block", getStatus(savingsStatusHashMap, "block"));
+        System.out.println("Savings Application Sub Status:" + 
savingsStatusHashMap + "\n");
+    }
+
+       public static void verifySavingsSubStatusIsNone(HashMap 
savingsStatusHashMap) {
+        System.out.println("\n------------------------- VERIFYING SAVINGS 
ACCOUNT IS NOT BLOCKED FOR ANY TYPE OF TRANSACTIONS 
---------------------------");
+        assertTrue("none", getStatus(savingsStatusHashMap, "none"));
+        System.out.println("Savings Application Sub Status:" + 
savingsStatusHashMap + "\n");
+    }
+
+    public static void verifySavingsSubStatusIsDebitBlocked(HashMap 
savingsStatusHashMap) {
+        System.out.println("\n--------------------- VERIFYING SAVINGS 
APPLICATION IS BLOCKED FOR DEBIT TRANSACTIONS ---------------------");
+        assertTrue("status is blockDebit", getStatus(savingsStatusHashMap, 
"blockDebit"));
+        System.out.println("Savings Application Sub Status:" + 
savingsStatusHashMap + "\n");
+    }
+
+    public static void verifySavingsSubStatusIsCreditBlocked(HashMap 
savingsStatusHashMap) {
+        System.out.println("\n---------------------- VERIFYING SAVINGS 
APPLICATION IS BLOCKED FOR CREDIT TRANSACTIONS ---------------");
+        assertTrue("blockCredit ", getStatus(savingsStatusHashMap, 
"blockCredit"));
+        System.out.println("Savings Application Sub Status:" + 
savingsStatusHashMap + "\n");
+    }
 
 }
\ No newline at end of file

http://git-wip-us.apache.org/repos/asf/fineract/blob/fe3741c2/fineract-provider/src/main/java/org/apache/fineract/commands/service/CommandWrapperBuilder.java
----------------------------------------------------------------------
diff --git 
a/fineract-provider/src/main/java/org/apache/fineract/commands/service/CommandWrapperBuilder.java
 
b/fineract-provider/src/main/java/org/apache/fineract/commands/service/CommandWrapperBuilder.java
index 5bcd21a..46c585b 100755
--- 
a/fineract-provider/src/main/java/org/apache/fineract/commands/service/CommandWrapperBuilder.java
+++ 
b/fineract-provider/src/main/java/org/apache/fineract/commands/service/CommandWrapperBuilder.java
@@ -2904,4 +2904,77 @@ public class CommandWrapperBuilder {
         this.href = "/smscampaigns/"+resourceId;
         return this;
     }
+    
+    public CommandWrapperBuilder holdAmount(final Long accountId) {
+        this.actionName = "HOLDAMOUNT";
+        this.entityName = "SAVINGSACCOUNT";
+        this.savingsId = accountId;
+        this.entityId = null;
+        this.href = "/savingsaccounts/" + accountId + 
"/transactions?command=holdAmount";
+        return this;
+    }
+
+    public CommandWrapperBuilder releaseAmount(final Long accountId, final 
Long transactionId) {
+        this.actionName = "RELEASEAMOUNT";
+        this.entityName = "SAVINGSACCOUNT";
+        this.entityId = null;
+        this.savingsId = accountId;
+        this.transactionId = transactionId.toString();
+        this.href = "/savingsaccounts/" + accountId + "/transactions/" + 
transactionId + "?command=releaseAmount";
+        return this;
+    }
+
+    public CommandWrapperBuilder blockDebitsFromSavingsAccount(final Long 
accountId) {
+        this.actionName = "BLOCKDEBIT";
+        this.entityName = "SAVINGSACCOUNT";
+        this.savingsId = accountId;
+        this.entityId = null;
+        this.href = "/savingsaccounts/" + accountId + "?command=blockDebit";
+        return this;
+    }
+
+    public CommandWrapperBuilder unblockDebitsFromSavingsAccount(final Long 
accountId) {
+        this.actionName = "UNBLOCKDEBIT";
+        this.entityName = "SAVINGSACCOUNT";
+        this.savingsId = accountId;
+        this.entityId = null;
+        this.href = "/savingsaccounts/" + accountId + "?command=unblockDebit";
+        return this;
+    }
+
+    public CommandWrapperBuilder blockCreditsToSavingsAccount(final Long 
accountId) {
+        this.actionName = "BLOCKCREDIT";
+        this.entityName = "SAVINGSACCOUNT";
+        this.savingsId = accountId;
+        this.entityId = null;
+        this.href = "/savingsaccounts/" + accountId + "?command=blockCredit";
+        return this;
+    }
+
+    public CommandWrapperBuilder unblockCreditsToSavingsAccount(final Long 
accountId) {
+        this.actionName = "UNBLOCKCREDIT";
+        this.entityName = "SAVINGSACCOUNT";
+        this.savingsId = accountId;
+        this.entityId = null;
+        this.href = "/savingsaccounts/" + accountId + "?command=unblockCredit";
+        return this;
+    }
+
+    public CommandWrapperBuilder blockSavingsAccount(final Long accountId) {
+        this.actionName = "BLOCK";
+        this.entityName = "SAVINGSACCOUNT";
+        this.savingsId = accountId;
+        this.entityId = null;
+        this.href = "/savingsaccounts/" + accountId + "?command=block";
+        return this;
+    }
+
+    public CommandWrapperBuilder unblockSavingsAccount(final Long accountId) {
+        this.actionName = "UNBLOCK";
+        this.entityName = "SAVINGSACCOUNT";
+        this.savingsId = accountId;
+        this.entityId = null;
+        this.href = "/savingsaccounts/" + accountId + "?command=unblock";
+        return this;
+    }
 }

http://git-wip-us.apache.org/repos/asf/fineract/blob/fe3741c2/fineract-provider/src/main/java/org/apache/fineract/portfolio/savings/SavingsAccountTransactionType.java
----------------------------------------------------------------------
diff --git 
a/fineract-provider/src/main/java/org/apache/fineract/portfolio/savings/SavingsAccountTransactionType.java
 
b/fineract-provider/src/main/java/org/apache/fineract/portfolio/savings/SavingsAccountTransactionType.java
index 85b267d..dc51e1f 100644
--- 
a/fineract-provider/src/main/java/org/apache/fineract/portfolio/savings/SavingsAccountTransactionType.java
+++ 
b/fineract-provider/src/main/java/org/apache/fineract/portfolio/savings/SavingsAccountTransactionType.java
@@ -41,7 +41,9 @@ public enum SavingsAccountTransactionType {
     REJECT_TRANSFER(15, "savingsAccountTransactionType.rejectTransfer"), 
WRITTEN_OFF(16, "savingsAccountTransactionType.writtenoff"), //
     OVERDRAFT_INTEREST(17, "savingsAccountTransactionType.overdraftInterest"), 
//
     WITHHOLD_TAX(18, "savingsAccountTransactionType.withholdTax"),
-    ESCHEAT(19, "savingsAccountTransactionType.escheat");
+    ESCHEAT(19, "savingsAccountTransactionType.escheat"),
+    AMOUNT_HOLD(20, "savingsAccountTransactionType.onHold"),
+    AMOUNT_RELEASE(21, "savingsAccountTransactionType.release");
 
     private final Integer value;
     private final String code;
@@ -113,6 +115,12 @@ public enum SavingsAccountTransactionType {
             case 19:
                savingsAccountTransactionType = 
SavingsAccountTransactionType.ESCHEAT;
             break;
+            case 20:
+                savingsAccountTransactionType = 
SavingsAccountTransactionType.AMOUNT_HOLD;
+            break;
+            case 21:
+                savingsAccountTransactionType = 
SavingsAccountTransactionType.AMOUNT_RELEASE;
+            break;
         }
         return savingsAccountTransactionType;
     }
@@ -188,12 +196,20 @@ public enum SavingsAccountTransactionType {
     public boolean isEscheat() {
         return 
this.value.equals(SavingsAccountTransactionType.ESCHEAT.getValue());
     }
+    
+    public boolean isAmountOnHold() {
+        return 
this.value.equals(SavingsAccountTransactionType.AMOUNT_HOLD.getValue());
+    }
+
+    public boolean isAmountRelease() {
+        return 
this.value.equals(SavingsAccountTransactionType.AMOUNT_RELEASE.getValue());
+    }
 
     public boolean isDebit() {
-        return isWithdrawal() || isWithdrawalFee() || isAnnualFee() || 
isPayCharge() || isIncomeFromInterest() || isWithHoldTax() || isEscheat();
+        return isWithdrawal() || isWithdrawalFee() || isAnnualFee() || 
isPayCharge() || isIncomeFromInterest() || isWithHoldTax() || isEscheat() || 
isAmountOnHold();
     }
 
     public boolean isCredit() {
-        return isDeposit() || isInterestPosting() || isDividendPayout();
+        return isDeposit() || isInterestPosting() || isDividendPayout() || 
isAmountRelease();
     }
 }
\ No newline at end of file

http://git-wip-us.apache.org/repos/asf/fineract/blob/fe3741c2/fineract-provider/src/main/java/org/apache/fineract/portfolio/savings/SavingsApiConstants.java
----------------------------------------------------------------------
diff --git 
a/fineract-provider/src/main/java/org/apache/fineract/portfolio/savings/SavingsApiConstants.java
 
b/fineract-provider/src/main/java/org/apache/fineract/portfolio/savings/SavingsApiConstants.java
index 7416831..1b8aa53 100644
--- 
a/fineract-provider/src/main/java/org/apache/fineract/portfolio/savings/SavingsApiConstants.java
+++ 
b/fineract-provider/src/main/java/org/apache/fineract/portfolio/savings/SavingsApiConstants.java
@@ -50,6 +50,12 @@ public class SavingsApiConstants {
     public static final String payChargeTransactionAction = ".paycharge";
     public static final String waiveChargeTransactionAction = ".waivecharge";
     public static final String updateMaturityDetailsAction = 
".updateMaturityDetails";
+    public static final String blockAction = ".block";
+    public static final String unblockAction = ".unblock";
+    public static final String blockCreditsAction = ".blockCredits";
+    public static final String unblockCreditsAction = ".unblockCredits";
+    public static final String blockDebitsAction = ".blockDebits";
+    public static final String unblockDebitsAction = ".unblockDebits";
 
     // command
     public static final String COMMAND_UNDO_TRANSACTION = "undo";
@@ -57,6 +63,14 @@ public class SavingsApiConstants {
     public static final String COMMAND_WAIVE_CHARGE = "waive";
     public static final String COMMAND_PAY_CHARGE = "paycharge";
     public static final String COMMAND_INACTIVATE_CHARGE = "inactivate";
+    public static final String COMMAND_HOLD_AMOUNT = "holdAmount";
+    public static final String COMMAND_RELEASE_AMOUNT = "releaseAmount";
+    public static final String COMMAND_UNBLOCK_ACCOUNT= "unblock";
+    public static final String COMMAND_BLOCK_ACCOUNT = "block";
+    public static final String COMMAND_BLOCK_CREDIT = "blockCredit";
+    public static final String COMMAND_BLOCK_DEBIT = "blockDebit";
+    public static final String COMMAND_UNBLOCK_DEBIT = "unblockDebit";
+    public static final String COMMAND_UNBLOCK_CREDIT = "unblockCredit";
 
     // general
     public static final String localeParamName = "locale";
@@ -69,6 +83,7 @@ public class SavingsApiConstants {
     public static final String accountNoParamName = "accountNo";
     public static final String externalIdParamName = "externalId";
     public static final String statusParamName = "status";
+    public static final String subStatusParamName = "subStatus";
     public static final String clientIdParamName = "clientId";
     public static final String groupIdParamName = "groupId";
     public static final String productIdParamName = "productId";
@@ -169,4 +184,9 @@ public class SavingsApiConstants {
     public static final String daysToEscheatParamName = "daysToEscheat";
 
     public static final String datatables = "datatables";
+    
+    public static final String ERROR_MSG_SAVINGS_ACCOUNT_NOT_ACTIVE = 
"not.in.active.state";
+    
+    public static final Set<String> 
SAVINGS_ACCOUNT_HOLD_AMOUNT_REQUEST_DATA_PARAMETERS = new HashSet<>(
+            Arrays.asList(transactionDateParamName, dateFormatParamName, 
localeParamName, transactionAmountParamName));
 }
\ No newline at end of file

http://git-wip-us.apache.org/repos/asf/fineract/blob/fe3741c2/fineract-provider/src/main/java/org/apache/fineract/portfolio/savings/api/SavingsAccountTransactionsApiResource.java
----------------------------------------------------------------------
diff --git 
a/fineract-provider/src/main/java/org/apache/fineract/portfolio/savings/api/SavingsAccountTransactionsApiResource.java
 
b/fineract-provider/src/main/java/org/apache/fineract/portfolio/savings/api/SavingsAccountTransactionsApiResource.java
index 5204db2..a50a083 100644
--- 
a/fineract-provider/src/main/java/org/apache/fineract/portfolio/savings/api/SavingsAccountTransactionsApiResource.java
+++ 
b/fineract-provider/src/main/java/org/apache/fineract/portfolio/savings/api/SavingsAccountTransactionsApiResource.java
@@ -145,11 +145,14 @@ public class SavingsAccountTransactionsApiResource {
             } else if (is(commandParam, "postInterestAsOn")) {
                 final CommandWrapper commandRequest = 
builder.savingsAccountInterestPosting(savingsId).build();
                 result = 
this.commandsSourceWritePlatformService.logCommandSource(commandRequest);
+            } else if (is(commandParam, 
SavingsApiConstants.COMMAND_HOLD_AMOUNT)) {
+                final CommandWrapper commandRequest = 
builder.holdAmount(savingsId).build();
+                result = 
this.commandsSourceWritePlatformService.logCommandSource(commandRequest);
             }
 
             if (result == null) {
                 //
-                throw new UnrecognizedQueryParamException("command", 
commandParam, new Object[] { "deposit", "withdrawal" });
+                throw new UnrecognizedQueryParamException("command", 
commandParam, new Object[] { "deposit", "withdrawal", 
SavingsApiConstants.COMMAND_HOLD_AMOUNT });
             }
 
             return this.toApiJsonSerializer.serialize(result);
@@ -183,11 +186,15 @@ public class SavingsAccountTransactionsApiResource {
         } else if (is(commandParam, 
SavingsApiConstants.COMMAND_ADJUST_TRANSACTION)) {
             final CommandWrapper commandRequest = 
builder.adjustSavingsAccountTransaction(savingsId, transactionId).build();
             result = 
this.commandsSourceWritePlatformService.logCommandSource(commandRequest);
+        } else if 
(is(commandParam,SavingsApiConstants.COMMAND_RELEASE_AMOUNT)) {
+            final CommandWrapper commandRequest = 
builder.releaseAmount(savingsId, transactionId).build();
+            result = 
this.commandsSourceWritePlatformService.logCommandSource(commandRequest);
         }
 
         if (result == null) {
             //
-            throw new UnrecognizedQueryParamException("command", commandParam, 
new Object[] { "undo" });
+            throw new UnrecognizedQueryParamException("command", commandParam, 
new Object[] { SavingsApiConstants.COMMAND_UNDO_TRANSACTION,
+                    SavingsApiConstants.COMMAND_ADJUST_TRANSACTION, 
SavingsApiConstants.COMMAND_RELEASE_AMOUNT});
         }
 
         return this.toApiJsonSerializer.serialize(result);

http://git-wip-us.apache.org/repos/asf/fineract/blob/fe3741c2/fineract-provider/src/main/java/org/apache/fineract/portfolio/savings/api/SavingsAccountsApiResource.java
----------------------------------------------------------------------
diff --git 
a/fineract-provider/src/main/java/org/apache/fineract/portfolio/savings/api/SavingsAccountsApiResource.java
 
b/fineract-provider/src/main/java/org/apache/fineract/portfolio/savings/api/SavingsAccountsApiResource.java
index 8a3ecc1..05feb63 100644
--- 
a/fineract-provider/src/main/java/org/apache/fineract/portfolio/savings/api/SavingsAccountsApiResource.java
+++ 
b/fineract-provider/src/main/java/org/apache/fineract/portfolio/savings/api/SavingsAccountsApiResource.java
@@ -279,13 +279,33 @@ public class SavingsAccountsApiResource {
             final CommandWrapper commandRequest = 
builder.unassignSavingsOfficer(accountId).build();
             result = 
this.commandsSourceWritePlatformService.logCommandSource(commandRequest);
             return this.toApiJsonSerializer.serialize(result);
+        } else if (is(commandParam, SavingsApiConstants.COMMAND_BLOCK_DEBIT)) {
+            final CommandWrapper commandRequest = 
builder.blockDebitsFromSavingsAccount(accountId).build();
+            result = 
this.commandsSourceWritePlatformService.logCommandSource(commandRequest);
+        } else if (is(commandParam, 
SavingsApiConstants.COMMAND_UNBLOCK_DEBIT)) {
+            final CommandWrapper commandRequest = 
builder.unblockDebitsFromSavingsAccount(accountId).build();
+            result = 
this.commandsSourceWritePlatformService.logCommandSource(commandRequest);
+        } else if (is(commandParam, SavingsApiConstants.COMMAND_BLOCK_CREDIT)) 
{
+            final CommandWrapper commandRequest = 
builder.blockCreditsToSavingsAccount(accountId).build();
+            result = 
this.commandsSourceWritePlatformService.logCommandSource(commandRequest);
+        } else if (is(commandParam, 
SavingsApiConstants.COMMAND_UNBLOCK_CREDIT)) {
+            final CommandWrapper commandRequest = 
builder.unblockCreditsToSavingsAccount(accountId).build();
+            result = 
this.commandsSourceWritePlatformService.logCommandSource(commandRequest);
+        } else if (is(commandParam, 
SavingsApiConstants.COMMAND_BLOCK_ACCOUNT)) {
+            final CommandWrapper commandRequest = 
builder.withNoJsonBody().blockSavingsAccount(accountId).build();
+            result = 
this.commandsSourceWritePlatformService.logCommandSource(commandRequest);
+        } else if (is(commandParam, 
SavingsApiConstants.COMMAND_UNBLOCK_ACCOUNT)) {
+            final CommandWrapper commandRequest = 
builder.withNoJsonBody().unblockSavingsAccount(accountId).build();
+            result = 
this.commandsSourceWritePlatformService.logCommandSource(commandRequest);
         }
 
         if (result == null) {
             //
             throw new UnrecognizedQueryParamException("command", commandParam, 
new Object[] { "reject", "withdrawnByApplicant", "approve",
                     "undoapproval", "activate", "calculateInterest", 
"postInterest", "close", "assignSavingsOfficer",
-                    "unassignSavingsOfficer" });
+                    "unassignSavingsOfficer", 
SavingsApiConstants.COMMAND_BLOCK_DEBIT, 
SavingsApiConstants.COMMAND_UNBLOCK_DEBIT,
+                    SavingsApiConstants.COMMAND_BLOCK_CREDIT, 
SavingsApiConstants.COMMAND_UNBLOCK_CREDIT,
+                    SavingsApiConstants.COMMAND_BLOCK_ACCOUNT, 
SavingsApiConstants.COMMAND_UNBLOCK_ACCOUNT });
         }
 
         return this.toApiJsonSerializer.serialize(result);

http://git-wip-us.apache.org/repos/asf/fineract/blob/fe3741c2/fineract-provider/src/main/java/org/apache/fineract/portfolio/savings/data/SavingsAccountSubStatusEnumData.java
----------------------------------------------------------------------
diff --git 
a/fineract-provider/src/main/java/org/apache/fineract/portfolio/savings/data/SavingsAccountSubStatusEnumData.java
 
b/fineract-provider/src/main/java/org/apache/fineract/portfolio/savings/data/SavingsAccountSubStatusEnumData.java
index 4981113..3a7347a 100644
--- 
a/fineract-provider/src/main/java/org/apache/fineract/portfolio/savings/data/SavingsAccountSubStatusEnumData.java
+++ 
b/fineract-provider/src/main/java/org/apache/fineract/portfolio/savings/data/SavingsAccountSubStatusEnumData.java
@@ -36,9 +36,15 @@ public class SavingsAccountSubStatusEnumData {
     private final boolean dormant;
     @SuppressWarnings("unused")
     private final boolean escheat;
+    @SuppressWarnings("unused")
+    private final boolean block;
+    @SuppressWarnings("unused")
+    private final boolean blockCredit;
+    @SuppressWarnings("unused")
+    private final boolean blockDebit;
 
     public SavingsAccountSubStatusEnumData(final Long id, final String code, 
final String value, final boolean none,
-            final boolean inactive, final boolean dormant, final boolean 
escheat) {
+            final boolean inactive, final boolean dormant, final boolean 
escheat, final boolean block, final boolean blockCredit, final boolean 
blockDebit) {
         this.id = id;
         this.code = code;
         this.value = value;
@@ -46,6 +52,9 @@ public class SavingsAccountSubStatusEnumData {
         this.inactive = inactive;
         this.dormant = dormant;
         this.escheat = escheat;
+        this.block = block;
+        this.blockCredit = blockCredit;
+        this.blockDebit = blockDebit;
     }
 
     public Long id() {

http://git-wip-us.apache.org/repos/asf/fineract/blob/fe3741c2/fineract-provider/src/main/java/org/apache/fineract/portfolio/savings/data/SavingsAccountSummaryData.java
----------------------------------------------------------------------
diff --git 
a/fineract-provider/src/main/java/org/apache/fineract/portfolio/savings/data/SavingsAccountSummaryData.java
 
b/fineract-provider/src/main/java/org/apache/fineract/portfolio/savings/data/SavingsAccountSummaryData.java
index 21d23b7..a3637c7 100644
--- 
a/fineract-provider/src/main/java/org/apache/fineract/portfolio/savings/data/SavingsAccountSummaryData.java
+++ 
b/fineract-provider/src/main/java/org/apache/fineract/portfolio/savings/data/SavingsAccountSummaryData.java
@@ -43,12 +43,13 @@ public class SavingsAccountSummaryData {
     private final BigDecimal totalWithholdTax;
     private final BigDecimal interestNotPosted;
     private final LocalDate lastInterestCalculationDate;
+    private final BigDecimal availableBalance;
 
     public SavingsAccountSummaryData(final CurrencyData currency, final 
BigDecimal totalDeposits, final BigDecimal totalWithdrawals,
             final BigDecimal totalWithdrawalFees, final BigDecimal 
totalAnnualFees, final BigDecimal totalInterestEarned,
             final BigDecimal totalInterestPosted, final BigDecimal 
accountBalance, final BigDecimal totalFeeCharge,
             final BigDecimal totalPenaltyCharge, final BigDecimal 
totalOverdraftInterestDerived,final BigDecimal totalWithholdTax,
-            final BigDecimal interestNotPosted, final LocalDate 
lastInterestCalculationDate) {
+            final BigDecimal interestNotPosted, final LocalDate 
lastInterestCalculationDate, final BigDecimal availableBalance) {
         this.currency = currency;
         this.totalDeposits = totalDeposits;
         this.totalWithdrawals = totalWithdrawals;
@@ -63,5 +64,6 @@ public class SavingsAccountSummaryData {
         this.totalWithholdTax = totalWithholdTax;
         this.interestNotPosted = interestNotPosted;
         this.lastInterestCalculationDate = lastInterestCalculationDate;
+        this.availableBalance = availableBalance;
     }
 }
\ No newline at end of file

http://git-wip-us.apache.org/repos/asf/fineract/blob/fe3741c2/fineract-provider/src/main/java/org/apache/fineract/portfolio/savings/data/SavingsAccountTransactionDataValidator.java
----------------------------------------------------------------------
diff --git 
a/fineract-provider/src/main/java/org/apache/fineract/portfolio/savings/data/SavingsAccountTransactionDataValidator.java
 
b/fineract-provider/src/main/java/org/apache/fineract/portfolio/savings/data/SavingsAccountTransactionDataValidator.java
index 936ba9d..fcd7a88 100644
--- 
a/fineract-provider/src/main/java/org/apache/fineract/portfolio/savings/data/SavingsAccountTransactionDataValidator.java
+++ 
b/fineract-provider/src/main/java/org/apache/fineract/portfolio/savings/data/SavingsAccountTransactionDataValidator.java
@@ -29,6 +29,8 @@ import static 
org.apache.fineract.portfolio.savings.SavingsApiConstants.transact
 import static 
org.apache.fineract.portfolio.savings.SavingsApiConstants.transactionAmountParamName;
 import static 
org.apache.fineract.portfolio.savings.SavingsApiConstants.transactionDateParamName;
 import static 
org.apache.fineract.portfolio.savings.SavingsApiConstants.withdrawBalanceParamName;
+import static 
org.apache.fineract.portfolio.savings.SavingsApiConstants.SAVINGS_ACCOUNT_HOLD_AMOUNT_REQUEST_DATA_PARAMETERS;
+import static 
org.apache.fineract.portfolio.savings.SavingsApiConstants.SAVINGS_ACCOUNT_RESOURCE_NAME;
 
 import java.lang.reflect.Type;
 import java.math.BigDecimal;
@@ -38,6 +40,7 @@ import java.util.HashSet;
 import java.util.List;
 import java.util.Map;
 import java.util.Set;
+import java.util.Date;
 
 import org.apache.commons.lang.StringUtils;
 import org.apache.fineract.infrastructure.core.api.JsonCommand;
@@ -46,10 +49,16 @@ import 
org.apache.fineract.infrastructure.core.data.DataValidatorBuilder;
 import org.apache.fineract.infrastructure.core.exception.InvalidJsonException;
 import 
org.apache.fineract.infrastructure.core.exception.PlatformApiDataValidationException;
 import org.apache.fineract.infrastructure.core.serialization.FromJsonHelper;
+import org.apache.fineract.infrastructure.core.service.DateUtils;
+import org.apache.fineract.portfolio.paymentdetail.domain.PaymentDetail;
 import org.apache.fineract.portfolio.savings.SavingsApiConstants;
+import org.apache.fineract.portfolio.savings.domain.SavingsAccount;
+import org.apache.fineract.portfolio.savings.domain.SavingsAccountTransaction;
+import org.apache.fineract.useradministration.domain.AppUser;
 import org.joda.time.LocalDate;
 import org.springframework.beans.factory.annotation.Autowired;
 import org.springframework.stereotype.Component;
+import org.apache.fineract.organisation.monetary.domain.Money;
 
 import com.google.gson.JsonElement;
 import com.google.gson.reflect.TypeToken;
@@ -160,6 +169,68 @@ public class SavingsAccountTransactionDataValidator {
         }
 
     }
+    
+    public SavingsAccountTransaction validateHoldAndAssembleForm(final String 
json, final SavingsAccount account, final AppUser createdUser) {
+        if (StringUtils.isBlank(json)) { throw new InvalidJsonException(); }
+
+        final Type typeOfMap = new TypeToken<Map<String, Object>>() 
{}.getType();
+        this.fromApiJsonHelper.checkForUnsupportedParameters(typeOfMap, json, 
SAVINGS_ACCOUNT_HOLD_AMOUNT_REQUEST_DATA_PARAMETERS);
+
+        final List<ApiParameterError> dataValidationErrors = new ArrayList<>();
+        final DataValidatorBuilder baseDataValidator = new 
DataValidatorBuilder(dataValidationErrors)
+                .resource(SAVINGS_ACCOUNT_RESOURCE_NAME);
+
+        final JsonElement element = this.fromApiJsonHelper.parse(json);
+
+        final BigDecimal amount = 
this.fromApiJsonHelper.extractBigDecimalWithLocaleNamed(transactionAmountParamName,
 element);
+        
baseDataValidator.reset().parameter(transactionAmountParamName).value(amount).notNull().positiveAmount();
+        final LocalDate transactionDate = 
this.fromApiJsonHelper.extractLocalDateNamed(transactionDateParamName, element);
+        
baseDataValidator.reset().parameter(transactionDateParamName).value(transactionDate).notNull();
+        boolean isActive = account.isActive();
+        
+        if (!isActive) {
+            
baseDataValidator.reset().parameter(SavingsApiConstants.statusParamName)
+                    
.failWithCodeNoParameterAddedToErrorCode(SavingsApiConstants.ERROR_MSG_SAVINGS_ACCOUNT_NOT_ACTIVE);
+        }
+        account.holdFunds(amount);
+        if (account.getWithdrawableBalance().compareTo(BigDecimal.ZERO) == -1) 
{
+            
baseDataValidator.reset().failWithCodeNoParameterAddedToErrorCode("insufficient 
balance", account.getId());
+            
baseDataValidator.failWithCode("validation.msg.savingsaccount.insufficient 
balance", "Insufficient balance");
+        }
+        LocalDate lastTransactionDate = account.retrieveLastTransactionDate();
+        // compare two dates now
+        if (lastTransactionDate != null && 
transactionDate.isBefore(lastTransactionDate)) {
+            
baseDataValidator.parameter(SavingsApiConstants.dateParamName).value(lastTransactionDate).failWithCode(
+                    
"validation.msg.date.can.not.be.before.last.transaction.date", "Amount can be 
put on hold only after last transaction");
+        }
+
+        throwExceptionIfValidationWarningsExist(dataValidationErrors);
+        final PaymentDetail paymentDetails = null;
+        Date createdDate = DateUtils.getDateOfTenant();
+        SavingsAccountTransaction transaction = 
SavingsAccountTransaction.holdAmount(account, account.office(), paymentDetails,
+                transactionDate, Money.of(account.getCurrency(), amount), 
createdDate, createdUser);
+        return transaction;
+    }
+
+    public SavingsAccountTransaction 
validateReleaseAmountAndAssembleForm(final SavingsAccountTransaction 
holdTransaction, final AppUser createdUser) {
+        final List<ApiParameterError> dataValidationErrors = new ArrayList<>();
+        final DataValidatorBuilder baseDataValidator = new 
DataValidatorBuilder(dataValidationErrors)
+                .resource(SAVINGS_ACCOUNT_RESOURCE_NAME);
+
+        if (holdTransaction == null) {
+            
baseDataValidator.failWithCode("validation.msg.validation.errors.exist", 
"Transaction not found");
+        } else if (holdTransaction.getReleaseIdOfHoldAmountTransaction() != 
null) {
+            
baseDataValidator.parameter(SavingsApiConstants.amountParamName).value(holdTransaction.getAmount()).failWithCode("validation.msg.amount.is.not.on.hold",
+                    "Transaction amount is not on hold");
+        }
+
+        throwExceptionIfValidationWarningsExist(dataValidationErrors);
+        Date createdDate = DateUtils.getDateOfTenant();
+        LocalDate transactionDate = DateUtils.getLocalDateOfTenant();
+        SavingsAccountTransaction transaction = 
SavingsAccountTransaction.releaseAmount(holdTransaction, transactionDate, 
createdDate,
+                createdUser);
+        return transaction;
+    }
 
     private void throwExceptionIfValidationWarningsExist(final 
List<ApiParameterError> dataValidationErrors) {
         if (!dataValidationErrors.isEmpty()) {

http://git-wip-us.apache.org/repos/asf/fineract/blob/fe3741c2/fineract-provider/src/main/java/org/apache/fineract/portfolio/savings/data/SavingsAccountTransactionEnumData.java
----------------------------------------------------------------------
diff --git 
a/fineract-provider/src/main/java/org/apache/fineract/portfolio/savings/data/SavingsAccountTransactionEnumData.java
 
b/fineract-provider/src/main/java/org/apache/fineract/portfolio/savings/data/SavingsAccountTransactionEnumData.java
index 2417a02..02651ce 100644
--- 
a/fineract-provider/src/main/java/org/apache/fineract/portfolio/savings/data/SavingsAccountTransactionEnumData.java
+++ 
b/fineract-provider/src/main/java/org/apache/fineract/portfolio/savings/data/SavingsAccountTransactionEnumData.java
@@ -44,6 +44,8 @@ public class SavingsAccountTransactionEnumData {
     private final boolean overdraftFee = true;
     private final boolean withholdTax;
     private final boolean escheat;
+    private final boolean amountHold;
+    private final boolean amountRelease;
 
     public SavingsAccountTransactionEnumData(final Long id, final String code, 
final String value) {
         this.id = id;
@@ -64,6 +66,8 @@ public class SavingsAccountTransactionEnumData {
         this.overdraftInterest = 
Long.valueOf(SavingsAccountTransactionType.OVERDRAFT_INTEREST.getValue()).equals(this.id);
         this.withholdTax = 
Long.valueOf(SavingsAccountTransactionType.WITHHOLD_TAX.getValue()).equals(this.id);
         this.escheat = 
Long.valueOf(SavingsAccountTransactionType.ESCHEAT.getValue()).equals(this.id);
+        this.amountHold = 
Long.valueOf(SavingsAccountTransactionType.AMOUNT_HOLD.getValue()).equals(this.id);
+        this.amountRelease = 
Long.valueOf(SavingsAccountTransactionType.AMOUNT_RELEASE.getValue()).equals(this.id);
         // this.overdraftFee =
         // 
Long.valueOf(SavingsAccountTransactionType.OVERDRAFT_INTEREST.getValue()).equals(this.id);
     }
@@ -139,5 +143,13 @@ public class SavingsAccountTransactionEnumData {
     public boolean isEscheat() {
        return this.escheat;
     }
+    
+    public boolean isAmountOnHold() {
+        return this.amountHold;
+    }
+
+    public boolean isAmountRelease() {
+        return this.amountRelease;
+    }
 
 }
\ No newline at end of file

http://git-wip-us.apache.org/repos/asf/fineract/blob/fe3741c2/fineract-provider/src/main/java/org/apache/fineract/portfolio/savings/domain/SavingsAccount.java
----------------------------------------------------------------------
diff --git 
a/fineract-provider/src/main/java/org/apache/fineract/portfolio/savings/domain/SavingsAccount.java
 
b/fineract-provider/src/main/java/org/apache/fineract/portfolio/savings/domain/SavingsAccount.java
index 9825d81..f904b09 100755
--- 
a/fineract-provider/src/main/java/org/apache/fineract/portfolio/savings/domain/SavingsAccount.java
+++ 
b/fineract-provider/src/main/java/org/apache/fineract/portfolio/savings/domain/SavingsAccount.java
@@ -100,6 +100,9 @@ import 
org.apache.fineract.portfolio.savings.SavingsPostingInterestPeriodType;
 import org.apache.fineract.portfolio.savings.data.SavingsAccountTransactionDTO;
 import org.apache.fineract.portfolio.savings.domain.interest.PostingPeriod;
 import 
org.apache.fineract.portfolio.savings.exception.InsufficientAccountBalanceException;
+import 
org.apache.fineract.portfolio.savings.exception.SavingsAccountBlockedException;
+import 
org.apache.fineract.portfolio.savings.exception.SavingsAccountCreditsBlockedException;
+import 
org.apache.fineract.portfolio.savings.exception.SavingsAccountDebitsBlockedException;
 import 
org.apache.fineract.portfolio.savings.exception.SavingsAccountTransactionNotFoundException;
 import 
org.apache.fineract.portfolio.savings.exception.SavingsActivityPriorToClientTransferException;
 import 
org.apache.fineract.portfolio.savings.exception.SavingsOfficerAssignmentDateException;
@@ -1053,7 +1056,9 @@ public class SavingsAccount extends 
AbstractPersistableCustom<Long> {
                 runningBalance = 
runningBalance.plus(transaction.getAmount(this.currency));
             } else if (transaction.isNotReversed() && transaction.isDebit()) {
                 runningBalance = 
runningBalance.minus(transaction.getAmount(this.currency));
-            } else {
+            } else if(transaction.isAmountOnHold() && 
transaction.getReleaseIdOfHoldAmountTransaction() == null){
+                runningBalance = 
runningBalance.minus(transaction.getAmount(this.currency));
+            }else {
                 continue;
             }
 
@@ -2822,4 +2827,188 @@ public class SavingsAccount extends 
AbstractPersistableCustom<Long> {
         this.summary.updateSummary(this.currency, 
this.savingsAccountTransactionSummaryWrapper, transactions);
     }
     
+    public Map<String, Object> block() {
+
+        final Map<String, Object> actualChanges = new LinkedHashMap<>();
+
+        final List<ApiParameterError> dataValidationErrors = new ArrayList<>();
+        final DataValidatorBuilder baseDataValidator = new 
DataValidatorBuilder(dataValidationErrors)
+                .resource(depositAccountType().resourceName() + 
SavingsApiConstants.blockAction);
+
+        final SavingsAccountStatusType currentStatus = 
SavingsAccountStatusType.fromInt(this.status);
+        if (!SavingsAccountStatusType.ACTIVE.hasStateOf(currentStatus)) {
+
+            
baseDataValidator.reset().parameter(SavingsApiConstants.statusParamName)
+                    
.failWithCodeNoParameterAddedToErrorCode(SavingsApiConstants.ERROR_MSG_SAVINGS_ACCOUNT_NOT_ACTIVE);
+
+            if (!dataValidationErrors.isEmpty()) { throw new 
PlatformApiDataValidationException(dataValidationErrors); }
+        }
+
+        this.sub_status = SavingsAccountSubStatusEnum.BLOCK.getValue();
+        actualChanges.put(SavingsApiConstants.subStatusParamName, 
SavingsEnumerations.subStatus(this.sub_status));
+
+        return actualChanges;
+    }
+    
+    public Map<String, Object> unblock() {
+
+        final Map<String, Object> actualChanges = new LinkedHashMap<>();
+
+        final List<ApiParameterError> dataValidationErrors = new ArrayList<>();
+        final DataValidatorBuilder baseDataValidator = new 
DataValidatorBuilder(dataValidationErrors)
+                .resource(depositAccountType().resourceName() + 
SavingsApiConstants.unblockAction);
+
+        final SavingsAccountStatusType currentStatus = 
SavingsAccountStatusType.fromInt(this.status);
+        if (!SavingsAccountStatusType.ACTIVE.hasStateOf(currentStatus)) {
+
+            
baseDataValidator.reset().parameter(SavingsApiConstants.statusParamName)
+                    
.failWithCodeNoParameterAddedToErrorCode(SavingsApiConstants.ERROR_MSG_SAVINGS_ACCOUNT_NOT_ACTIVE);
+
+        }
+
+        final SavingsAccountSubStatusEnum currentSubStatus = 
SavingsAccountSubStatusEnum.fromInt(this.sub_status);
+        if (!SavingsAccountSubStatusEnum.BLOCK.hasStateOf(currentSubStatus)) {
+            
baseDataValidator.reset().parameter(SavingsApiConstants.subStatusParamName)
+                    
.failWithCodeNoParameterAddedToErrorCode("not.in.blocked.state");
+        }
+        if (!dataValidationErrors.isEmpty()) { throw new 
PlatformApiDataValidationException(dataValidationErrors); }
+        this.sub_status = SavingsAccountSubStatusEnum.NONE.getValue();
+        actualChanges.put(SavingsApiConstants.subStatusParamName, 
SavingsEnumerations.subStatus(this.sub_status));
+        return actualChanges;
+    }
+    
+    public Map<String, Object> blockCredits(Integer currentSubstatus) {
+
+        final Map<String, Object> actualChanges = new LinkedHashMap<>();
+
+        final List<ApiParameterError> dataValidationErrors = new ArrayList<>();
+        final DataValidatorBuilder baseDataValidator = new 
DataValidatorBuilder(dataValidationErrors)
+                .resource(depositAccountType().resourceName() + 
SavingsApiConstants.blockCreditsAction);
+
+        final SavingsAccountStatusType currentStatus = 
SavingsAccountStatusType.fromInt(this.status);
+        if (!SavingsAccountStatusType.ACTIVE.hasStateOf(currentStatus)) {
+
+            
baseDataValidator.reset().parameter(SavingsApiConstants.statusParamName)
+                    
.failWithCodeNoParameterAddedToErrorCode(SavingsApiConstants.ERROR_MSG_SAVINGS_ACCOUNT_NOT_ACTIVE);
+        }
+        if 
(SavingsAccountSubStatusEnum.BLOCK.hasStateOf(SavingsAccountSubStatusEnum.fromInt(currentSubstatus))
+                || 
SavingsAccountSubStatusEnum.BLOCK_DEBIT.hasStateOf(SavingsAccountSubStatusEnum.fromInt(currentSubstatus)))
 {
+
+            
baseDataValidator.reset().parameter(SavingsApiConstants.subStatusParamName).value(SavingsAccountSubStatusEnum.fromInt(currentSubstatus))
+                    .failWithCodeNoParameterAddedToErrorCode("currently.set");
+        }
+        if (!dataValidationErrors.isEmpty()) { throw new 
PlatformApiDataValidationException(dataValidationErrors); }
+        this.sub_status = SavingsAccountSubStatusEnum.BLOCK_CREDIT.getValue();
+        actualChanges.put(SavingsApiConstants.subStatusParamName, 
SavingsEnumerations.subStatus(this.sub_status));
+
+        return actualChanges;
+    }
+    
+    public Map<String, Object> unblockCredits() {
+
+        final Map<String, Object> actualChanges = new LinkedHashMap<>();
+
+        final List<ApiParameterError> dataValidationErrors = new ArrayList<>();
+        final DataValidatorBuilder baseDataValidator = new 
DataValidatorBuilder(dataValidationErrors)
+                .resource(depositAccountType().resourceName() + 
SavingsApiConstants.unblockCreditsAction);
+
+        final SavingsAccountStatusType currentStatus = 
SavingsAccountStatusType.fromInt(this.status);
+        if (!SavingsAccountStatusType.ACTIVE.hasStateOf(currentStatus)) {
+            
baseDataValidator.reset().failWithCodeNoParameterAddedToErrorCode(SavingsApiConstants.ERROR_MSG_SAVINGS_ACCOUNT_NOT_ACTIVE);
+        }
+
+        final SavingsAccountSubStatusEnum currentSubStatus = 
SavingsAccountSubStatusEnum.fromInt(this.sub_status);
+        if 
(!SavingsAccountSubStatusEnum.BLOCK_CREDIT.hasStateOf(currentSubStatus)) {
+            
baseDataValidator.reset().parameter(SavingsApiConstants.statusParamName)
+                    
.failWithCodeNoParameterAddedToErrorCode("credits.are.not.blocked");
+        }
+        if (!dataValidationErrors.isEmpty()) { throw new 
PlatformApiDataValidationException(dataValidationErrors); }
+        this.sub_status = SavingsAccountSubStatusEnum.NONE.getValue();
+        actualChanges.put(SavingsApiConstants.subStatusParamName, 
SavingsEnumerations.subStatus(this.sub_status));
+        return actualChanges;
+    }
+    
+    public Map<String, Object> blockDebits(Integer currentSubstatus) {
+
+        final Map<String, Object> actualChanges = new LinkedHashMap<>();
+
+        final List<ApiParameterError> dataValidationErrors = new ArrayList<>();
+        final DataValidatorBuilder baseDataValidator = new 
DataValidatorBuilder(dataValidationErrors)
+                .resource(depositAccountType().resourceName() + 
SavingsApiConstants.blockDebitsAction);
+
+        final SavingsAccountStatusType currentStatus = 
SavingsAccountStatusType.fromInt(this.status);
+        if (!SavingsAccountStatusType.ACTIVE.hasStateOf(currentStatus)) {
+            
baseDataValidator.reset().parameter(SavingsApiConstants.statusParamName)
+                    
.failWithCodeNoParameterAddedToErrorCode(SavingsApiConstants.ERROR_MSG_SAVINGS_ACCOUNT_NOT_ACTIVE);
+
+        }
+        if 
(SavingsAccountSubStatusEnum.BLOCK.hasStateOf(SavingsAccountSubStatusEnum.fromInt(currentSubstatus))
+                || 
SavingsAccountSubStatusEnum.BLOCK_CREDIT.hasStateOf(SavingsAccountSubStatusEnum.fromInt(currentSubstatus)))
 {
+
+            
baseDataValidator.reset().parameter(SavingsApiConstants.subStatusParamName).value(SavingsAccountSubStatusEnum.fromInt(currentSubstatus))
+                    .failWithCodeNoParameterAddedToErrorCode("currently.set");
+        }
+        if (!dataValidationErrors.isEmpty()) { throw new 
PlatformApiDataValidationException(dataValidationErrors); }
+
+        this.sub_status = SavingsAccountSubStatusEnum.BLOCK_DEBIT.getValue();
+        actualChanges.put(SavingsApiConstants.subStatusParamName, 
SavingsEnumerations.subStatus(this.sub_status));
+
+        return actualChanges;
+    }
+
+    public Map<String, Object> unblockDebits() {
+
+        final Map<String, Object> actualChanges = new LinkedHashMap<>();
+
+        final List<ApiParameterError> dataValidationErrors = new ArrayList<>();
+        final DataValidatorBuilder baseDataValidator = new 
DataValidatorBuilder(dataValidationErrors)
+                .resource(depositAccountType().resourceName() + 
SavingsApiConstants.unblockDebitsAction);
+
+        final SavingsAccountStatusType currentStatus = 
SavingsAccountStatusType.fromInt(this.status);
+        if (!SavingsAccountStatusType.ACTIVE.hasStateOf(currentStatus)) {
+
+            
baseDataValidator.reset().parameter(SavingsApiConstants.statusParamName)
+                    
.failWithCodeNoParameterAddedToErrorCode(SavingsApiConstants.ERROR_MSG_SAVINGS_ACCOUNT_NOT_ACTIVE);
+
+        }
+
+        final SavingsAccountSubStatusEnum currentSubStatus = 
SavingsAccountSubStatusEnum.fromInt(this.sub_status);
+        if 
(!SavingsAccountSubStatusEnum.BLOCK_DEBIT.hasStateOf(currentSubStatus)) {
+            
baseDataValidator.reset().parameter(SavingsApiConstants.subStatusParamName)
+                    
.failWithCodeNoParameterAddedToErrorCode("debits.are.not.blocked");
+        }
+        if (!dataValidationErrors.isEmpty()) { throw new 
PlatformApiDataValidationException(dataValidationErrors); }
+        this.sub_status = SavingsAccountSubStatusEnum.NONE.getValue();
+        actualChanges.put(SavingsApiConstants.subStatusParamName, 
SavingsEnumerations.subStatus(this.sub_status));
+        return actualChanges;
+    }
+    
+    public Integer getSubStatus() {
+        return this.sub_status;
+    }
+    
+    public void validateForAccountBlock() {
+        final SavingsAccountSubStatusEnum currentSubStatus = 
SavingsAccountSubStatusEnum.fromInt(this.getSubStatus());
+        if (SavingsAccountSubStatusEnum.BLOCK.hasStateOf(currentSubStatus)) { 
throw new SavingsAccountBlockedException(this.getId()); }
+    }
+
+    public void validateForDebitBlock() {
+        final SavingsAccountSubStatusEnum currentSubStatus = 
SavingsAccountSubStatusEnum.fromInt(this.getSubStatus());
+        if (SavingsAccountSubStatusEnum.BLOCK_DEBIT
+                .hasStateOf(currentSubStatus)) { throw new 
SavingsAccountDebitsBlockedException(this.getId()); }
+    }
+
+    public void validateForCreditBlock() {
+        final SavingsAccountSubStatusEnum currentSubStatus = 
SavingsAccountSubStatusEnum.fromInt(this.getSubStatus());
+        if (SavingsAccountSubStatusEnum.BLOCK_CREDIT
+                .hasStateOf(currentSubStatus)) { throw new 
SavingsAccountCreditsBlockedException(this.getId()); }
+    }
+
+    public LocalDate retrieveLastTransactionDate() {
+        final List<SavingsAccountTransaction> transactionsSortedByDate = 
retreiveListOfTransactions();
+        SavingsAccountTransaction lastTransaction = 
transactionsSortedByDate.get(transactionsSortedByDate.size() - 1);
+        return lastTransaction.transactionLocalDate();
+    }
+    
+    
 }
\ No newline at end of file

http://git-wip-us.apache.org/repos/asf/fineract/blob/fe3741c2/fineract-provider/src/main/java/org/apache/fineract/portfolio/savings/domain/SavingsAccountDomainServiceJpa.java
----------------------------------------------------------------------
diff --git 
a/fineract-provider/src/main/java/org/apache/fineract/portfolio/savings/domain/SavingsAccountDomainServiceJpa.java
 
b/fineract-provider/src/main/java/org/apache/fineract/portfolio/savings/domain/SavingsAccountDomainServiceJpa.java
index 32fdcd2..b3ea4db 100755
--- 
a/fineract-provider/src/main/java/org/apache/fineract/portfolio/savings/domain/SavingsAccountDomainServiceJpa.java
+++ 
b/fineract-provider/src/main/java/org/apache/fineract/portfolio/savings/domain/SavingsAccountDomainServiceJpa.java
@@ -86,6 +86,8 @@ public class SavingsAccountDomainServiceJpa implements 
SavingsAccountDomainServi
             final SavingsTransactionBooleanValues transactionBooleanValues) {
 
         AppUser user = getAppUserIfPresent();
+        account.validateForAccountBlock();
+        account.validateForDebitBlock();
         final boolean isSavingsInterestPostingAtCurrentPeriodEnd = 
this.configurationDomainService
                 .isSavingsInterestPostingAtCurrentPeriodEnd();
         final Integer financialYearBeginningMonth = 
this.configurationDomainService.retrieveFinancialYearBeginningMonth();
@@ -148,6 +150,8 @@ public class SavingsAccountDomainServiceJpa implements 
SavingsAccountDomainServi
             final boolean isAccountTransfer, final boolean 
isRegularTransaction,
             final SavingsAccountTransactionType savingsAccountTransactionType) 
{
         AppUser user = getAppUserIfPresent();
+        account.validateForAccountBlock();
+        account.validateForCreditBlock();
         final boolean isSavingsInterestPostingAtCurrentPeriodEnd = 
this.configurationDomainService
                 .isSavingsInterestPostingAtCurrentPeriodEnd();
         final Integer financialYearBeginningMonth = 
this.configurationDomainService.retrieveFinancialYearBeginningMonth();

http://git-wip-us.apache.org/repos/asf/fineract/blob/fe3741c2/fineract-provider/src/main/java/org/apache/fineract/portfolio/savings/domain/SavingsAccountSubStatusEnum.java
----------------------------------------------------------------------
diff --git 
a/fineract-provider/src/main/java/org/apache/fineract/portfolio/savings/domain/SavingsAccountSubStatusEnum.java
 
b/fineract-provider/src/main/java/org/apache/fineract/portfolio/savings/domain/SavingsAccountSubStatusEnum.java
index aefe183..889a69a 100644
--- 
a/fineract-provider/src/main/java/org/apache/fineract/portfolio/savings/domain/SavingsAccountSubStatusEnum.java
+++ 
b/fineract-provider/src/main/java/org/apache/fineract/portfolio/savings/domain/SavingsAccountSubStatusEnum.java
@@ -26,7 +26,10 @@ public enum SavingsAccountSubStatusEnum {
     NONE(0, "SavingsAccountSubStatusEnum.none"), //
     INACTIVE(100, "SavingsAccountSubStatusEnum.inactive"), //
     DORMANT(200, "SavingsAccountSubStatusEnum.dormant"),
-    ESCHEAT(300,"SavingsAccountSubStatusEnum.escheat");
+    ESCHEAT(300,"SavingsAccountSubStatusEnum.escheat"),
+    BLOCK(400, "SavingsAccountSubStatusEnum.block"),
+    BLOCK_CREDIT(500, "SavingsAccountSubStatusEnum.blockCredit"),
+    BLOCK_DEBIT(600, "SavingsAccountSubStatusEnum.blockDebit");
 
     private final Integer value;
     private final String code;
@@ -45,6 +48,15 @@ public enum SavingsAccountSubStatusEnum {
                    case 300:
                        enumeration = SavingsAccountSubStatusEnum.ESCHEAT;
                    break;
+                   case 400:
+                       enumeration = SavingsAccountSubStatusEnum.BLOCK;
+                   break;
+                   case 500:
+                    enumeration = SavingsAccountSubStatusEnum.BLOCK_CREDIT;
+                break;
+                   case 600:
+                    enumeration = SavingsAccountSubStatusEnum.BLOCK_DEBIT;
+                break;
                }
        }
         return enumeration;
@@ -82,4 +94,16 @@ public enum SavingsAccountSubStatusEnum {
     public boolean isSubStatusEscheat() {
         return 
this.value.equals(SavingsAccountSubStatusEnum.ESCHEAT.getValue());
     }
+    
+    public boolean isSubStatusAccountBlocked() {
+        return this.value.equals(SavingsAccountSubStatusEnum.BLOCK.getValue());
+    }
+    
+    public boolean isSubStatusCreditBlocked() {
+        return 
this.value.equals(SavingsAccountSubStatusEnum.BLOCK_CREDIT.getValue());
+    }
+
+    public boolean isSubStatusDebitBlocked() {
+        return 
this.value.equals(SavingsAccountSubStatusEnum.BLOCK_DEBIT.getValue());
+    }
 }
\ No newline at end of file

Reply via email to