fineract-commits mailing list archives

Site index · List index
Message view « Date » · « Thread »
Top « Date » · « Thread »
From nazeer1100...@apache.org
Subject [2/3] fineract git commit: block account/amount/credit/debit
Date Wed, 28 Jun 2017 10:15:39 GMT
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 <shruthi@confluxtechnologies.com>
Authored: Wed Jun 21 13:21:36 2017 +0530
Committer: ShruthiRajaram <shruthi@confluxtechnologies.com>
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


Mime
View raw message