You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@fineract.apache.org by na...@apache.org on 2016/03/22 08:26:37 UTC

incubator-fineract git commit: Self Service - Loan Application

Repository: incubator-fineract
Updated Branches:
  refs/heads/develop 04fe104dd -> 2ddea0aae


Self Service - Loan Application


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

Branch: refs/heads/develop
Commit: 2ddea0aaee8385591343026cef2f276765f72a79
Parents: 04fe104
Author: Adi Narayana Raju <ad...@confluxtechnologies.com>
Authored: Mon Mar 21 17:32:19 2016 +0530
Committer: Adi Narayana Raju <ad...@confluxtechnologies.com>
Committed: Mon Mar 21 17:32:19 2016 +0530

----------------------------------------------------------------------
 api-docs/apiLive.htm                            | 744 ++++++++++++++++++-
 .../loanaccount/api/SelfLoansApiResource.java   | 101 ++-
 .../data/SelfLoansDataValidator.java            |  75 +-
 .../useradministration/domain/AppUser.java      |   2 +-
 4 files changed, 914 insertions(+), 8 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/incubator-fineract/blob/2ddea0aa/api-docs/apiLive.htm
----------------------------------------------------------------------
diff --git a/api-docs/apiLive.htm b/api-docs/apiLive.htm
index 4edd5e7..789582d 100644
--- a/api-docs/apiLive.htm
+++ b/api-docs/apiLive.htm
@@ -3159,10 +3159,42 @@
 								<td></td>
 							</tr>
 							<tr>
-								<td><a href="#selfloan">Loans</a></td>
+								<td><a href="#selfloantemplate">Loans</a></td>
+								<td>self/loans/template?templateType=individual</td>
+								<td></td>
+								<td><a href="#selfloantemplate">Loan Application Template</a></td>
+								<td></td>
+								<td></td>
+							</tr>
+							<tr>
+								<td></td>
+								<td>self/loans?command=calculateLoanSchedule</td>
+								<td><a href="#selfloancalc">Calculate Loan Repayment Schedule</a></td>
+								<td></td>
+								<td></td>
+								<td></td>
+							</tr>
+							<tr>
+								<td></td>
+								<td>self/loans</td>
+								<td><a href="#selfloanapply">Submit new Loan Application</a></td>
+								<td></td>
+								<td></td>
+								<td></td>
+							</tr>
+							<tr>
+								<td></td>
 								<td>self/loans/{loanId}</td>
 								<td></td>
 								<td><a href="#selfloan">Retrieve a Loan</a></td>
+								<td><a href="#selfloanupdate">Update a Loan Application</a></td>
+								<td></td>
+							</tr>
+							<tr>
+								<td></td>
+								<td>self/loans/{loanId}?command=withdrawnByApplicant</td>
+								<td><a href="#selfloanwithdraw">Withdraw Loan Application</a></td>
+								<td></td>
 								<td></td>
 								<td></td>
 							</tr>
@@ -39210,10 +39242,10 @@ No Request Body
 				</div>
 				<div class="method-example">
 					<code class="method-declaration">
-POST https://DomainName/api/v1/userdetails?access_token={access_token}
+POST https://DomainName/api/v1/self/userdetails?access_token={access_token}
 					</code>
 					<code class="method-request">
-POST userdetails?access_token=bWlmb3M6cGFzc3dvcmQ=
+POST self/userdetails?access_token=bWlmb3M6cGFzc3dvcmQ=
 Content-Type: application/json
 No Request Body
 					</code>
@@ -39989,6 +40021,610 @@ GET https://DomainName/api/v1/self/clients/{clientId}/transaction/{transactionId
 				</div>
 			</div>
 
+			<a id="selfloantemplate" name="selfloantemplate" class="old-syle-anchor">&nbsp;</a>
+			<div class="method-section">
+				<div class="method-description">
+					<h4>Retrieve Loan Details Template</h4>
+					<p>This is a convenience resource. It can be useful when
+						building maintenance user interface screens for client
+						applications. The template data returned consists of any or all
+						of:
+					<ul>
+						<li class=normalli>Field Defaults</li>
+						<li class=normalli>Allowed Value Lists</li>
+					</ul>
+					</p>
+					<h5>Arguments</h5>
+					<dl class="argument-list">
+						<dt>templateType</dt>
+						<dd>
+							String <span>mandatory</span>, only allowed value is <span>individual</span>
+						</dd>
+						<dd>
+							<br>templateType value decides the required template data for creating a new loan application.
+
+						</dd>
+						<dd>
+							<br><b>'individual':</b> Loan template data for creating individual loans.
+						</dd>
+						<dt>clientId</dt>
+						<dd>
+							Integer <span>mandatory</span>
+						</dd>
+					</dl>
+					<h5>Optional Arguments</h5>
+					<dl class="argument-list">
+						<dt>productId</dt>
+						<dd>
+							Integer <span>optional</span>
+						</dd>
+						<dd>If entered, productId, productName and selectedProduct
+							fields are returned.</dd>
+
+					</dl>
+					<p>Example Requests:</p>
+					<div class=apiClick>self/loans/template?templateType=individual&clientId=1</div>
+					<br>
+					<br>
+					<div class=apiClick>self/loans/template?templateType=individual&clientId=1&productId=1</div>
+				</div>
+				<div class="method-example">
+					<code class="method-declaration">
+GET https://DomainName/api/v1/self/loans/template?templateType=individual&clientId=1
+					</code>
+					<code class="method-response">
+{
+  "clientId": 1,
+  "clientName": "Kampala first Client",
+  "clientOfficeId": 2,
+  "timeline": {
+    "expectedDisbursementDate": [
+      2013,
+      3,
+      8
+    ]
+  },
+  "productOptions": [
+    {
+      "id": 1,
+      "name": "Kampala Product (with cash accounting)"
+    }
+  ]
+}
+					</code>
+					<code class="method-declaration">
+GET https://DomainName/api/v1/self/loans/template?templateType=individual&clientId=1&productId=1
+					</code>
+					<code class="method-response">
+{
+  "clientId": 1,
+  "clientName": "Kampala first Client",
+  "clientOfficeId": 2,
+  "loanProductId": 1,
+  "loanProductName": "Kampala Product (with cash accounting)",
+  "loanProductDescription": "Typical Kampala loan product with cash accounting enabled for testing.",
+  "currency": {
+    "code": "UGX",
+    "name": "Uganda Shilling",
+    "decimalPlaces": 2,
+    "displaySymbol": "USh",
+    "nameCode": "currency.UGX",
+    "displayLabel": "Uganda Shilling (USh)"
+  },
+  "principal": 1000000,
+  "termFrequency": 12,
+  "termPeriodFrequencyType": {
+    "id": 2,
+    "code": "repaymentFrequency.periodFrequencyType.months",
+    "value": "Months"
+  },
+  "numberOfRepayments": 12,
+  "repaymentEvery": 1,
+  "repaymentFrequencyType": {
+    "id": 2,
+    "code": "repaymentFrequency.periodFrequencyType.months",
+    "value": "Months"
+  },
+  "interestRatePerPeriod": 24,
+  "interestRateFrequencyType": {
+    "id": 3,
+    "code": "interestRateFrequency.periodFrequencyType.years",
+    "value": "Per year"
+  },
+  "annualInterestRate": 24,
+  "amortizationType": {
+    "id": 1,
+    "code": "amortizationType.equal.installments",
+    "value": "Equal installments"
+  },
+  "interestType": {
+    "id": 1,
+    "code": "interestType.flat",
+    "value": "Flat"
+  },
+  "interestCalculationPeriodType": {
+    "id": 1,
+    "code": "interestCalculationPeriodType.same.as.repayment.period",
+    "value": "Same as repayment period"
+  },
+  "transactionProcessingStrategyId": 2,
+  "timeline": {
+    "expectedDisbursementDate": [
+      2013,
+      3,
+      8
+    ]
+  },
+  "daysInMonthType": {
+    "id": 30,
+    "code": "DaysInMonthType.days360",
+    "value": "30 Days"
+  },
+  "daysInYearType": {
+	"id": 360,
+	"code": "DaysInYearType.days360",
+	"value": "360 Days"
+  },
+  "isInterestRecalculationEnabled": true,
+  "interestRecalculationData": {
+    "interestRecalculationCompoundingType": {
+      "id": 2,
+      "code": "interestRecalculationCompoundingMethod.fee",
+      "value": "Fee"
+    },
+	"recalculationCompoundingFrequencyType": {
+		    "id":1,
+			"code":"interestRecalculationFrequencyType.same.as.repayment.period",
+			"value":"Same as repayment period"
+	},
+    "rescheduleStrategyType": {
+      "id": 2,
+      "code": "loanRescheduleStrategyMethod.reduce.number.of.installments",
+      "value": "Reduce number of installments"
+    },
+	"recalculationRestFrequencyType": {
+		    "id":1,
+			"code":"interestRecalculationFrequencyType.same.as.repayment.period",
+			"value":"Same as repayment period"
+	}
+  }
+  "charges": [],
+  "productOptions": [
+    {
+      "id": 1,
+      "name": "Kampala Product (with cash accounting)"
+    }
+  ],
+  "loanOfficerOptions": [
+    {
+      "id": 2,
+      "firstname": "Kampala",
+      "lastname": "LoanOfficer",
+      "displayName": "LoanOfficer, Kampala",
+      "officeId": 2,
+      "officeName": "Uganda (Kampala)",
+      "isLoanOfficer": true
+    }
+  ],
+  "loanPurposeOptions": [
+    {
+      "id": 20,
+      "name": "option.Agriculture",
+      "position": 1
+    },
+    {
+      "id": 21,
+      "name": "option.Manufacturing",
+      "position": 20
+    },
+    {
+      "id": 22,
+      "name": "option.HousingImprovement",
+      "position": 21
+    }
+  ],
+  "termFrequencyTypeOptions": [
+    {
+      "id": 0,
+      "code": "loanTermFrequency.periodFrequencyType.days",
+      "value": "Days"
+    },
+    {
+      "id": 1,
+      "code": "loanTermFrequency.periodFrequencyType.weeks",
+      "value": "Weeks"
+    },
+    {
+      "id": 2,
+      "code": "loanTermFrequency.periodFrequencyType.months",
+      "value": "Months"
+    },
+    {
+      "id": 3,
+      "code": "loanTermFrequency.periodFrequencyType.years",
+      "value": "Years"
+    }
+  ],
+  "repaymentFrequencyTypeOptions": [
+    {
+      "id": 0,
+      "code": "repaymentFrequency.periodFrequencyType.days",
+      "value": "Days"
+    },
+    {
+      "id": 1,
+      "code": "repaymentFrequency.periodFrequencyType.weeks",
+      "value": "Weeks"
+    },
+    {
+      "id": 2,
+      "code": "repaymentFrequency.periodFrequencyType.months",
+      "value": "Months"
+    }
+  ],
+  "interestRateFrequencyTypeOptions": [
+    {
+      "id": 2,
+      "code": "interestRateFrequency.periodFrequencyType.months",
+      "value": "Per month"
+    },
+    {
+      "id": 3,
+      "code": "interestRateFrequency.periodFrequencyType.years",
+      "value": "Per year"
+    }
+  ],
+  "amortizationTypeOptions": [
+    {
+      "id": 1,
+      "code": "amortizationType.equal.installments",
+      "value": "Equal installments"
+    },
+    {
+      "id": 0,
+      "code": "amortizationType.equal.principal",
+      "value": "Equal principle payments"
+    }
+  ],
+  "interestTypeOptions": [
+    {
+      "id": 1,
+      "code": "interestType.flat",
+      "value": "Flat"
+    },
+    {
+      "id": 0,
+      "code": "interestType.declining.balance",
+      "value": "Declining Balance"
+    }
+  ],
+  "interestCalculationPeriodTypeOptions": [
+    {
+      "id": 0,
+      "code": "interestCalculationPeriodType.daily",
+      "value": "Daily"
+    },
+    {
+      "id": 1,
+      "code": "interestCalculationPeriodType.same.as.repayment.period",
+      "value": "Same as repayment period"
+    }
+  ],
+  "transactionProcessingStrategyOptions": [
+    {
+      "id": 2,
+      "code": "heavensfamily-strategy",
+      "name": "Heavensfamily"
+    }
+  ],
+  "chargeOptions": [
+    {
+      "id": 1,
+      "name": "Bank Fee (per installment)",
+      "active": true,
+      "penalty": false,
+      "currency": {
+        "code": "UGX",
+        "name": "Uganda Shilling",
+        "decimalPlaces": 2,
+        "displaySymbol": "USh",
+        "nameCode": "currency.UGX",
+        "displayLabel": "Uganda Shilling (USh)"
+      },
+      "amount": 1500,
+      "chargeTimeType": {
+        "id": 2,
+        "code": "chargeTimeType.specifiedDueDate",
+        "value": "Specified due date"
+      },
+      "chargeAppliesTo": {
+        "id": 1,
+        "code": "chargeAppliesTo.loan",
+        "value": "Loan"
+      },
+      "chargeCalculationType": {
+        "id": 1,
+        "code": "chargeCalculationType.flat",
+        "value": "Flat"
+      }
+    }
+  ],
+  "loanCollateralOptions": [
+    {
+      "id": 17,
+      "name": "option.House",
+      "position": 1
+    },
+    {
+      "id": 18,
+      "name": "option.Television",
+      "position": 17
+    },
+    {
+      "id": 19,
+      "name": "option.Gold",
+      "position": 18
+    }
+  ],
+  "accountLinkingOptions":[
+  	{
+  		"id":1,
+  		"accountNo":"000000001",
+  		"clientId":1,
+  		"clientName":"pramod nuthakki",
+  		"productId":1,
+  		"productName":"pramod sav",
+  		"fieldOfficerId":0,
+  		"currency":{"code":"USD","name":"US Dollar","decimalPlaces":2,"displaySymbol":"$","nameCode":"currency.USD","displayLabel":"US Dollar ($)"}
+  	}
+  ]
+}
+					</code>
+				</div>
+			</div>
+
+			<a id="selfloancalc" name="selfloancalc" class="old-syle-anchor">&nbsp;</a>
+			<div class="method-section">
+				<div class="method-description">
+					<h4>Calculate Loan Repayment Schedule</h4>
+					<table class=matrixHeading>
+						<tr class="matrixHeadingBG">
+							<td><div class="fineractHeading2">Mandatory Fields</div></td>
+						</tr>
+						<tr class=alt>
+							<td>productId, principal, loanTermFrequency,
+								loanTermFrequencyType, numberOfRepayments, repaymentEvery,
+								repaymentFrequencyType, interestRatePerPeriod,
+								amortizationType, interestType,
+								interestCalculationPeriodType, expectedDisbursementDate,
+								transactionProcessingStrategyId</td>
+						</tr>
+					</table>
+				</div>
+				<div class="method-example">
+					<code class="method-declaration">
+POST https://DomainName/api/v1/self/loans?command=calculateLoanSchedule
+					</code>
+					<code class="method-request">
+POST self/loans?command=calculateLoanSchedule
+Content-Type: application/json
+Request Body:
+{
+    "dateFormat": "dd MMMM yyyy",
+    "locale": "en_GB",
+    "productId": 1,
+    "principal": "100,000.00",
+    "loanTermFrequency": 12,
+    "loanTermFrequencyType": 2,
+    "numberOfRepayments": 12,
+    "repaymentEvery": 1,
+    "repaymentFrequencyType": 2,
+    "interestRatePerPeriod": 2,
+    "amortizationType": 1,
+    "interestType": 0,
+    "interestCalculationPeriodType": 1,
+    "expectedDisbursementDate": "20 September 2011",
+    "transactionProcessingStrategyId": 2
+}
+					</code>
+					<code class="method-response">
+{
+  "currency": {
+    "code": "UGX",
+    "name": "Uganda Shilling",
+    "decimalPlaces": 2,
+    "displaySymbol": "USh",
+    "nameCode": "currency.UGX",
+    "displayLabel": "Uganda Shilling (USh)"
+  },
+  "loanTermInDays": 366,
+  "totalPrincipalDisbursed": 100000,
+  "totalPrincipalExpected": 100000,
+  "totalPrincipalPaid": 0,
+  "totalInterestCharged": 13471.52,
+  "totalFeeChargesCharged": 0,
+  "totalPenaltyChargesCharged": 0,
+  "totalWaived": 0,
+  "totalWrittenOff": 0,
+  "totalRepaymentExpected": 113471.52,
+  "totalRepayment": 0,
+  "totalOutstanding": 0,
+  "periods": [
+    {
+      "period": 0,
+      "dueDate": [
+        2011,
+        9,
+        20
+      ],
+      "principalDisbursed": 100000,
+      "principalLoanBalanceOutstanding": 100000,
+      "feeChargesDue": 0,
+      "feeChargesOutstanding": 0,
+      "totalOriginalDueForPeriod": 0,
+      "totalDueForPeriod": 0,
+      "totalOutstandingForPeriod": 0,
+      "totalOverdue": 0,
+      "totalActualCostOfLoanForPeriod": 0
+    },
+    {
+      "period": 1,
+      "fromDate": [
+        2011,
+        9,
+        20
+      ],
+      "dueDate": [
+        2011,
+        10,
+        20
+      ],
+      "daysInPeriod": 30,
+      "principalOriginalDue": 7455.96,
+      "principalDue": 7455.96,
+      "principalOutstanding": 7455.96,
+      "principalLoanBalanceOutstanding": 92544.04,
+      "interestOriginalDue": 2000,
+      "interestDue": 2000,
+      "interestOutstanding": 2000,
+      "feeChargesDue": 0,
+      "penaltyChargesDue": 0,
+      "totalOriginalDueForPeriod": 9455.96,
+      "totalDueForPeriod": 9455.96,
+      "totalPaidForPeriod": 0,
+      "totalOutstandingForPeriod": 9455.96,
+      "totalOverdue": 9455.96,
+      "totalActualCostOfLoanForPeriod": 2000
+    },
+    ...
+    ...
+    {
+      "period": 12,
+      "fromDate": [
+        2012,
+        8,
+        20
+      ],
+      "dueDate": [
+        2012,
+        9,
+        20
+      ],
+      "daysInPeriod": 31,
+      "principalOriginalDue": 9270.56,
+      "principalDue": 9270.56,
+      "principalOutstanding": 9270.56,
+      "principalLoanBalanceOutstanding": 0,
+      "interestOriginalDue": 185.4,
+      "interestDue": 185.4,
+      "interestOutstanding": 185.4,
+      "feeChargesDue": 0,
+      "penaltyChargesDue": 0,
+      "totalOriginalDueForPeriod": 9455.96,
+      "totalDueForPeriod": 9455.96,
+      "totalPaidForPeriod": 0,
+      "totalOutstandingForPeriod": 9455.96,
+      "totalOverdue": 9455.96,
+      "totalActualCostOfLoanForPeriod": 185.4
+    }
+  ]
+}
+					</code>
+				</div>
+			</div>
+			
+			
+			<a id="selfloanapply" name="selfloanapply" class="old-syle-anchor">&nbsp;</a>
+			<div class="method-section">
+				<div class="method-description">
+					<h4>Submit a new Loan Application</h4>
+					<p>Only individual loanType can be used by Self Service User </p>
+					<table class=matrixHeading>
+						<tr class="matrixHeadingBG">
+							<td><div class="fineractHeading2">Mandatory Fields</div></td>
+						</tr>
+						<tr class=alt>
+							<td>clientId, productId, principal, loanTermFrequency,
+								loanTermFrequencyType, loanType, numberOfRepayments, repaymentEvery,
+								repaymentFrequencyType, interestRatePerPeriod,
+								amortizationType, interestType,
+								interestCalculationPeriodType, transactionProcessingStrategyId,
+								expectedDisbursementDate, submittedOnDate, loanType</td>
+						</tr>
+					</table>
+					<br/>
+					<table class=matrixHeading>
+						<tr class="matrixHeadingBG">
+							<td><div class="fineractHeading2">Additional Mandatory Fields if interest recalculation is enabled for product and Rest frequency  not same as repayment period</div></td>
+						</tr>
+						<tr class=alt>
+							<td>recalculationRestFrequencyDate</td>
+						</tr>
+					</table>
+					<table class=matrixHeading>
+						<tr class="matrixHeadingBG">
+							<td><div class="fineractHeading2">Additional Mandatory Fields if interest recalculation with interest/fee compounding is enabled for product and compounding frequency not same as repayment period</div></td>
+						</tr>
+						<tr class=alt>
+							<td>recalculationCompoundingFrequencyDate</td>
+						</tr>
+					</table>
+					<br/>
+					<table class=matrixHeading>
+						<tr class="matrixHeadingBG">
+							<td><div class="fineractHeading2">Optional Fields</div></td>
+						</tr>
+						<tr class=alt>
+							<td>graceOnPrincipalPayment, graceOnInterestPayment, graceOnInterestCharged, linkAccountId, allowPartialPeriodInterestCalcualtion,
+								 fixedEmiAmount, maxOutstandingLoanBalance, disbursementData, graceOnArrearsAgeing, createStandingInstructionAtDisbursement (requires linkedAccountId if set to true)
+							</td>
+						</tr>
+					</table>
+				</div>
+				<div class="method-example">
+					<code class="method-declaration">
+POST https://DomainName/api/v1/self/loans
+					</code>
+					<code class="method-request">
+POST self/loans
+Content-Type: application/json
+Request Body:
+{
+    "dateFormat": "dd MMMM yyyy",
+    "locale": "en_GB",
+    "clientId": 1,
+    "productId": 1,
+    "principal": "10,000.00",
+    "loanTermFrequency": 12,
+    "loanTermFrequencyType": 2,
+    "loanType": "individual",
+    "numberOfRepayments": 10,
+    "repaymentEvery": 1,
+    "repaymentFrequencyType": 2,
+    "interestRatePerPeriod": 10,
+    "amortizationType": 1,
+    "interestType": 0,
+    "interestCalculationPeriodType": 1,
+    "transactionProcessingStrategyId": 1,
+    "expectedDisbursementDate": "10 Jun 2013",
+    "submittedOnDate": "10 Jun 2013",
+    "linkAccountId" : "1",
+    "fixedEmiAmount":1100,
+    "maxOutstandingLoanBalance":"35000",
+    "disbursementData":[{"expectedDisbursementDate":"01 November 2013",
+    					"principal":22000,"approvedPrincipal":22000}]
+}
+					</code>
+					<code class="method-response">
+{
+    "officeId": 1,
+    "clientId": 1,
+    "loanId": 1,
+    "resourceId": 1
+}
+					</code>
+				</div>
+			</div>
 			<a id="selfloan" name="selfloan" class="old-syle-anchor">&nbsp;</a>
 			<div class="method-section">
 				<div class="method-description">
@@ -40265,6 +40901,108 @@ GET https://DomainName/api/v1/self/loans/{loanId}
 				</div>
 			</div>
 
+			<a id="selfloanupdate" name="selfloanupdate" class="old-syle-anchor">&nbsp;</a>
+			<div class="method-section">
+				<div class="method-description">
+					<h2>Update a Loan Application</h2>
+					<p>Loan application can only be modified when in 'Submitted and pending approval' state. Once the application is approved, the details cannot be changed using this method.</p>
+				</div>
+				<div class="method-example">
+					<code class="method-declaration">PUT https://Domain Name/api/v1/self/loans/{loanId}</code>
+					<code class="method-request">PUT self/loans/1
+Content-Type: application/json
+No Request Body:
+{
+  "locale": "en",
+  "dateFormat": "dd MMMM yyyy",
+  "productId": 1,
+  "principal": "5000",
+  "loanTermFrequency": 10,
+  "loanTermFrequencyType": 0,
+  "numberOfRepayments": 10,
+  "repaymentEvery": 1,
+  "repaymentFrequencyType": 0,
+  "interestRatePerPeriod": 2,
+  "interestType": 0,
+  "interestCalculationPeriodType": 0,
+  "amortizationType": 1,
+  "expectedDisbursementDate": "04 March 2014",
+  "transactionProcessingStrategyId": 1
+}
+					</code>
+					<code class="method-response">
+{
+  "officeId": 2,
+  "clientId": 1,
+  "loanId": 1,
+  "resourceId": 1,
+  "changes": {
+    "principal": 5000,
+    "locale": "en"
+  }
+}
+					</code>
+				</div>
+			</div>
+
+			<a id="selfloanwithdraw" name="selfloanwithdraw" class="old-syle-anchor">&nbsp;</a>
+			<div class="method-section">
+				<div class="method-description">
+					<h4>Applicant Withdraws from Loan Application</h4>
+					<table class=matrixHeading>
+						<tr class="matrixHeadingBG">
+							<td><div class="fineractHeading2">Mandatory Fields</div></td>
+						</tr>
+						<tr class=alt>
+							<td>withdrawnOnDate</td>
+						</tr>
+					</table>
+				</div>
+				<div class="method-example">
+					<code class="method-declaration">
+POST https://DomainName/api/v1/self/loans/{loanId}?command=withdrawnByApplicant
+					</code>
+					<code class="method-request">
+POST self/loans/1?command=withdrawnByApplicant
+Content-Type: application/json
+Request Body:
+{
+    "locale": "en",
+    "dateFormat": "dd MMMM yyyy",
+    "withdrawnOnDate": "20 September 2011",
+    "note": "Reason loan applicant withdrew from application."
+}
+</code>
+					<code class="method-response">
+{
+  "officeId": 1,
+  "clientId": 1,
+  "loanId": 2,
+  "resourceId": 2,
+  "changes": {
+    "status": {
+      "id": 400,
+      "code": "loanStatusType.withdrawn.by.client",
+      "value": "Withdrawn by applicant",
+      "pendingApproval": false,
+      "waitingForDisbursal": false,
+      "active": false,
+      "closedObligationsMet": false,
+      "closedWrittenOff": false,
+      "closedRescheduled": false,
+      "closed": false,
+      "overpaid": false
+    },
+    "locale": "en",
+    "dateFormat": "dd MMMM yyyy",
+    "withdrawnOnDate": "20 September 2011",
+    "closedOnDate": "20 September 2011"
+  }
+}
+					</code>
+				</div>
+			</div>
+
             <a id="selfloantransaction" name="selfloantransaction" class="old-syle-anchor">&nbsp;</a>
 			<div class="method-section">
 				<div class="method-description">

http://git-wip-us.apache.org/repos/asf/incubator-fineract/blob/2ddea0aa/fineract-provider/src/main/java/org/apache/fineract/portfolio/self/loanaccount/api/SelfLoansApiResource.java
----------------------------------------------------------------------
diff --git a/fineract-provider/src/main/java/org/apache/fineract/portfolio/self/loanaccount/api/SelfLoansApiResource.java b/fineract-provider/src/main/java/org/apache/fineract/portfolio/self/loanaccount/api/SelfLoansApiResource.java
index d317b5b..7281752 100644
--- a/fineract-provider/src/main/java/org/apache/fineract/portfolio/self/loanaccount/api/SelfLoansApiResource.java
+++ b/fineract-provider/src/main/java/org/apache/fineract/portfolio/self/loanaccount/api/SelfLoansApiResource.java
@@ -18,20 +18,31 @@
  */
 package org.apache.fineract.portfolio.self.loanaccount.api;
 
+import java.util.HashMap;
+
 import javax.ws.rs.Consumes;
 import javax.ws.rs.GET;
+import javax.ws.rs.POST;
+import javax.ws.rs.PUT;
 import javax.ws.rs.Path;
 import javax.ws.rs.PathParam;
 import javax.ws.rs.Produces;
+import javax.ws.rs.QueryParam;
 import javax.ws.rs.core.Context;
 import javax.ws.rs.core.MediaType;
 import javax.ws.rs.core.UriInfo;
 
+import org.apache.commons.lang.StringUtils;
+import org.apache.fineract.infrastructure.core.exception.UnrecognizedQueryParamException;
 import org.apache.fineract.infrastructure.security.service.PlatformSecurityContext;
+import org.apache.fineract.portfolio.client.exception.ClientNotFoundException;
 import org.apache.fineract.portfolio.loanaccount.api.LoanChargesApiResource;
 import org.apache.fineract.portfolio.loanaccount.api.LoanTransactionsApiResource;
 import org.apache.fineract.portfolio.loanaccount.api.LoansApiResource;
 import org.apache.fineract.portfolio.loanaccount.exception.LoanNotFoundException;
+import org.apache.fineract.portfolio.loanaccount.exception.LoanTemplateTypeRequiredException;
+import org.apache.fineract.portfolio.loanaccount.exception.NotSupportedLoanTemplateTypeException;
+import org.apache.fineract.portfolio.self.client.service.AppuserClientMapperReadService;
 import org.apache.fineract.portfolio.self.loanaccount.data.SelfLoansDataValidator;
 import org.apache.fineract.portfolio.self.loanaccount.service.AppuserLoansMapperReadService;
 import org.apache.fineract.useradministration.domain.AppUser;
@@ -49,6 +60,7 @@ public class SelfLoansApiResource {
 	private final LoanTransactionsApiResource loanTransactionsApiResource;
 	private final LoanChargesApiResource loanChargesApiResource;
 	private final AppuserLoansMapperReadService appuserLoansMapperReadService;
+	private final AppuserClientMapperReadService appUserClientMapperReadService;
 	private final SelfLoansDataValidator dataValidator;
 
 	@Autowired
@@ -57,12 +69,14 @@ public class SelfLoansApiResource {
 			final LoanTransactionsApiResource loanTransactionsApiResource,
 			final LoanChargesApiResource loanChargesApiResource,
 			final AppuserLoansMapperReadService appuserLoansMapperReadService,
+			final AppuserClientMapperReadService appUserClientMapperReadService,
 			final SelfLoansDataValidator dataValidator) {
 		this.context = context;
 		this.loansApiResource = loansApiResource;
 		this.loanTransactionsApiResource = loanTransactionsApiResource;
 		this.loanChargesApiResource = loanChargesApiResource;
 		this.appuserLoansMapperReadService = appuserLoansMapperReadService;
+		this.appUserClientMapperReadService = appUserClientMapperReadService;
 		this.dataValidator = dataValidator;
 	}
 
@@ -125,7 +139,79 @@ public class SelfLoansApiResource {
 		return this.retrieveLoanCharge(loanId, loanChargeId, uriInfo);
 	}
 
-	private void validateAppuserLoanMapping(final Long loanId) {
+    @GET
+    @Path("template")
+    @Consumes({ MediaType.APPLICATION_JSON })
+    @Produces({ MediaType.APPLICATION_JSON })
+    public String template(@QueryParam("clientId") final Long clientId, 
+    		@QueryParam("productId") final Long productId,
+    		@QueryParam("templateType") final String templateType,
+    		@Context final UriInfo uriInfo) {
+    	
+    	if(clientId != null){
+        	validateAppuserClientsMapping(clientId);
+    	}
+    	
+        if (templateType == null) {
+            final String errorMsg = "Loan template type must be provided";
+            throw new LoanTemplateTypeRequiredException(errorMsg);
+        } else if (!(templateType.equalsIgnoreCase("individual") 
+        		|| templateType.equalsIgnoreCase("collateral"))){
+            final String errorMsg = "Loan template type '" + templateType + "' is not supported";
+            throw new NotSupportedLoanTemplateTypeException(errorMsg, templateType);
+        }
+    	final Long groupId = null;
+    	final boolean staffInSelectedOfficeOnly = false;
+    	final boolean onlyActive = true;
+    	return this.loansApiResource.template(clientId, groupId, productId, 
+    			templateType, staffInSelectedOfficeOnly, onlyActive, uriInfo);
+
+    }
+    
+    @POST
+    @Consumes({ MediaType.APPLICATION_JSON })
+    @Produces({ MediaType.APPLICATION_JSON })
+    public String calculateLoanScheduleOrSubmitLoanApplication(@QueryParam("command") final String commandParam,
+            @Context final UriInfo uriInfo, final String apiRequestBodyAsJson) {
+    	
+    	HashMap<String, Object> attr = this.dataValidator.validateLoanApplication(apiRequestBodyAsJson);
+        final Long clientId = (Long) attr.get("clientId");
+        validateAppuserClientsMapping(clientId);
+
+    	return this.loansApiResource.calculateLoanScheduleOrSubmitLoanApplication(commandParam, 
+    			uriInfo, apiRequestBodyAsJson);
+    }
+    
+    @PUT
+    @Path("{loanId}")
+    @Consumes({ MediaType.APPLICATION_JSON })
+    @Produces({ MediaType.APPLICATION_JSON })
+    public String modifyLoanApplication(@PathParam("loanId") final Long loanId, final String apiRequestBodyAsJson) {
+
+    	HashMap<String, Object> attr = this.dataValidator.validateModifyLoanApplication(apiRequestBodyAsJson);
+        validateAppuserLoanMapping(loanId);
+        final Long clientId = (Long) attr.get("clientId");
+        if(clientId != null){
+            validateAppuserClientsMapping(clientId);
+        }
+
+    	return this.loansApiResource.modifyLoanApplication(loanId, apiRequestBodyAsJson);
+    }
+    
+    @POST
+    @Path("{loanId}")
+    @Consumes({ MediaType.APPLICATION_JSON })
+    @Produces({ MediaType.APPLICATION_JSON })
+    public String stateTransitions(@PathParam("loanId") final Long loanId, @QueryParam("command") final String commandParam,
+            final String apiRequestBodyAsJson) {
+    	if (!is(commandParam, "withdrawnByApplicant")) {
+    		throw new UnrecognizedQueryParamException("command", commandParam);
+    	}
+    	validateAppuserLoanMapping(loanId);
+    	return this.loansApiResource.stateTransitions(loanId, commandParam, apiRequestBodyAsJson);
+    }
+    
+    private void validateAppuserLoanMapping(final Long loanId) {
 		AppUser user = this.context.authenticatedUser();
 		final boolean isLoanMappedToUser = this.appuserLoansMapperReadService
 				.isLoanMappedToUser(loanId, user.getId());
@@ -133,5 +219,18 @@ public class SelfLoansApiResource {
 			throw new LoanNotFoundException(loanId);
 		}
 	}
+    
+	private void validateAppuserClientsMapping(final Long clientId) {
+		AppUser user = this.context.authenticatedUser();
+		final boolean mappedClientId = this.appUserClientMapperReadService
+				.isClientMappedToUser(clientId, user.getId());
+		if (!mappedClientId) {
+			throw new ClientNotFoundException(clientId);
+		}
+	}
+
+    private boolean is(final String commandParam, final String commandValue) {
+        return StringUtils.isNotBlank(commandParam) && commandParam.trim().equalsIgnoreCase(commandValue);
+    }
 
 }
\ No newline at end of file

http://git-wip-us.apache.org/repos/asf/incubator-fineract/blob/2ddea0aa/fineract-provider/src/main/java/org/apache/fineract/portfolio/self/loanaccount/data/SelfLoansDataValidator.java
----------------------------------------------------------------------
diff --git a/fineract-provider/src/main/java/org/apache/fineract/portfolio/self/loanaccount/data/SelfLoansDataValidator.java b/fineract-provider/src/main/java/org/apache/fineract/portfolio/self/loanaccount/data/SelfLoansDataValidator.java
index 7560fba..ef93de0 100644
--- a/fineract-provider/src/main/java/org/apache/fineract/portfolio/self/loanaccount/data/SelfLoansDataValidator.java
+++ b/fineract-provider/src/main/java/org/apache/fineract/portfolio/self/loanaccount/data/SelfLoansDataValidator.java
@@ -20,16 +20,26 @@ package org.apache.fineract.portfolio.self.loanaccount.data;
 
 import java.util.ArrayList;
 import java.util.Arrays;
+import java.util.HashMap;
 import java.util.HashSet;
 import java.util.List;
 import java.util.Set;
 
 import javax.ws.rs.core.UriInfo;
 
+import org.apache.commons.lang.StringUtils;
 import org.apache.fineract.infrastructure.core.api.ApiParameterHelper;
+import org.apache.fineract.infrastructure.core.data.ApiParameterError;
+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.exception.UnsupportedParameterException;
+import org.apache.fineract.infrastructure.core.serialization.FromJsonHelper;
+import org.springframework.beans.factory.annotation.Autowired;
 import org.springframework.stereotype.Component;
 
+import com.google.gson.JsonElement;
+
 @Component
 public class SelfLoansDataValidator {
 	private static final Set<String> allowedAssociationParameters = new HashSet<>(
@@ -37,12 +47,16 @@ public class SelfLoansDataValidator {
 					"originalSchedule", "transactions", "charges",
 					"guarantors", "collateral", "linkedAccount",
 					"multiDisburseDetails"));
-
+	private final FromJsonHelper fromApiJsonHelper;
+	
+	@Autowired
+	public SelfLoansDataValidator(final FromJsonHelper fromApiJsonHelper){
+		this.fromApiJsonHelper = fromApiJsonHelper;
+	}
+	
 	public void validateRetrieveLoan(final UriInfo uriInfo) {
 		List<String> unsupportedParams = new ArrayList<>();
 
-		validateTemplate(uriInfo, unsupportedParams);
-
 		Set<String> associationParameters = ApiParameterHelper
 				.extractAssociationsForResponseIfProvided(uriInfo
 						.getQueryParameters());
@@ -68,6 +82,60 @@ public class SelfLoansDataValidator {
 		throwExceptionIfReqd(unsupportedParams);
 
 	}
+	
+	public HashMap<String, Object> validateLoanApplication(final String json){
+        if (StringUtils.isBlank(json)) { throw new InvalidJsonException(); }
+
+        final List<ApiParameterError> dataValidationErrors = new ArrayList<>();
+        final DataValidatorBuilder baseDataValidator = new DataValidatorBuilder(dataValidationErrors).resource("loan");
+
+        final JsonElement element = this.fromApiJsonHelper.parse(json);
+
+        final String loanTypeParameterName = "loanType";
+        final String loanTypeStr = this.fromApiJsonHelper.extractStringNamed(loanTypeParameterName, element);
+        baseDataValidator.reset().parameter(loanTypeParameterName).value(loanTypeStr).notNull().equals("individual");
+
+        final String clientIdParameterName = "clientId";
+        final String clientId = this.fromApiJsonHelper.extractStringNamed(clientIdParameterName, element);
+        baseDataValidator.reset().parameter(clientIdParameterName).value(clientId).notNull().longGreaterThanZero();
+
+        if (!dataValidationErrors.isEmpty()) { throw new PlatformApiDataValidationException(dataValidationErrors); }
+        
+        HashMap<String, Object> retAttr = new HashMap<>();
+        retAttr.put("clientId", Long.parseLong(clientId));
+        
+        return retAttr;
+
+	}
+
+	public HashMap<String, Object> validateModifyLoanApplication(final String json) {
+        final List<ApiParameterError> dataValidationErrors = new ArrayList<>();
+        final DataValidatorBuilder baseDataValidator = new DataValidatorBuilder(dataValidationErrors).resource("loan");
+
+        final JsonElement element = this.fromApiJsonHelper.parse(json);
+
+        final String loanTypeParameterName = "loanType";
+        if(this.fromApiJsonHelper.parameterExists(loanTypeParameterName, element)){
+            final String loanTypeStr = this.fromApiJsonHelper.extractStringNamed(loanTypeParameterName, element);
+            baseDataValidator.reset().parameter(loanTypeParameterName).value(loanTypeStr).notNull().equals("individual");
+        }
+
+        final String clientIdParameterName = "clientId";
+        String clientId = null;
+        if(this.fromApiJsonHelper.parameterExists(clientIdParameterName, element)){
+            clientId = this.fromApiJsonHelper.extractStringNamed(clientIdParameterName, element);
+            baseDataValidator.reset().parameter(clientIdParameterName).value(clientId).notNull().longGreaterThanZero();
+        }
+
+        if (!dataValidationErrors.isEmpty()) { throw new PlatformApiDataValidationException(dataValidationErrors); }
+        
+        HashMap<String, Object> retAttr = new HashMap<>();
+        if(clientId != null){
+            retAttr.put("clientId", Long.parseLong(clientId));
+        }
+        
+        return retAttr;
+	}
 
 	private void throwExceptionIfReqd(List<String> unsupportedParams) {
 		if (unsupportedParams.size() > 0) {
@@ -84,4 +152,5 @@ public class SelfLoansDataValidator {
 		}
 	}
 
+
 }

http://git-wip-us.apache.org/repos/asf/incubator-fineract/blob/2ddea0aa/fineract-provider/src/main/java/org/apache/fineract/useradministration/domain/AppUser.java
----------------------------------------------------------------------
diff --git a/fineract-provider/src/main/java/org/apache/fineract/useradministration/domain/AppUser.java b/fineract-provider/src/main/java/org/apache/fineract/useradministration/domain/AppUser.java
index b68f794..7bf9558 100644
--- a/fineract-provider/src/main/java/org/apache/fineract/useradministration/domain/AppUser.java
+++ b/fineract-provider/src/main/java/org/apache/fineract/useradministration/domain/AppUser.java
@@ -325,7 +325,7 @@ public class AppUser extends AbstractPersistable<Long> implements PlatformUser {
         }else if(!this.isSelfServiceUser && actualChanges.containsKey(AppUserConstants.IS_SELF_SERVICE_USER)){
         	actualChanges.put(AppUserConstants.CLIENTS, new ArrayList<>());
         	if(this.appUserClientMappings != null){
-        		this.appUserClientMappings = null;
+        		this.appUserClientMappings.clear();
         	}
         }