Merge remote-tracking branch 'vishwasbabu/mifosx-151'

This commit is contained in:
Keith Woodlock
2013-02-10 20:34:53 +00:00
20 changed files with 960 additions and 87 deletions
+772 -7
View File
@@ -293,6 +293,27 @@
<td></td>
<td></td>
</tr>
<tr>
<td></td>
<td>loans/{loanId}/guarantors</td>
<td><a href="#loans_guarantors_create">Create a Guarantor
</a></td>
<td><a href="#loans_guarantors_list">List Guarantors
</a></td>
<td></td>
<td></td>
</tr>
<tr>
<td></td>
<td>loans/{loanId}/guarantors/{guarantorId}</td>
<td></td>
<td><a href="#loans_guarantors_retrieve">Retrieve a Guarantor
</a></td>
<td><a href="#loans_guarantors_update">Update a Guarantor
</a></td>
<td><a href="#loans_guarantors_delete">Delete a Guarantor
</a></td>
</tr>
</table>
</div>
</div>
@@ -1076,6 +1097,113 @@
</div>
</div>
</div>
<div class="flybar-nav">
<h2 class="flybar-button">Accounting</h2>
<div id="toc-menu-group" class="flybar-menu">
<div class="tocMatrix">
<table class=matrixHeading>
<tr class="matrixHeadingBG">
<td colspan=2 valign="top"><div class="matrixHeadingVerbs">
<table>
<tr>
<td>RESOURCES</td>
</tr>
</table>
</div></td>
<td><table>
<tr>
<td><div class="matrixHeadingVerbs">POST</div></td>
</tr>
<tr>
<td><div class=matrixHeadingCommands>create/complex
update</div></td>
</tr>
</table></td>
<td><table>
<tr>
<td><div class="matrixHeadingVerbs">GET</div></td>
</tr>
<tr>
<td><div class=matrixHeadingCommands>read</div></td>
</tr>
</table></td>
<td><table>
<tr>
<td><div class="matrixHeadingVerbs">PUT</div></td>
</tr>
<tr>
<td><div class=matrixHeadingCommands>update</div></td>
</tr>
</table></td>
<td><table>
<tr>
<td><div class="matrixHeadingVerbs">DELETE</div></td>
</tr>
<tr>
<td><div class=matrixHeadingCommands>delete</div></td>
</tr>
</table></td>
</tr>
<tr class="alt">
<td><a href="#glaccounts">General Ledger Account</a></td>
<td>glaccounts</td>
<td><a href="#glaccounts_create">Create a New Ledger Account</a></td>
<td><a href="#glaccounts_list">List Ledger Accounts</a></td>
<td></td>
<td></td>
</tr>
<tr>
<td></td>
<td>glaccounts/{glaccountId}</td>
<td></td>
<td><a href="#glaccounts_retrieve">Retrieve a Ledger Account</a></td>
<td><a href="#glaccounts_update">Update a Ledger Account</a></td>
<td><a href="#glaccounts_delete">Delete a Ledger Account</a></td>
</tr>
<tr class="alt">
<td><a href="#glclosures">Accounting Closure</a></td>
<td>glclosures</td>
<td><a href="#glclosures_create">Create an Accounting Closure</a></td>
<td><a href="#glclosures_list">List Accounting Closures</a></td>
<td></td>
<td></td>
</tr>
<tr>
<td></td>
<td>glclosures/{glclosureId}</td>
<td></td>
<td><a href="#glclosures_retrieve">Retrieve an Accounting Closure</a></td>
<td><a href="#glclosures_update">Update an Accounting Closure</a></td>
<td><a href="#glclosures_delete">Delete an Accounting Closure</a></td>
</tr>
<tr class="alt">
<td><a href="#glclosures">Journal Entries</a></td>
<td>journalentries</td>
<td><a href="#journalentries_create">Create Journal Entries</a></td>
<td><a href="#journalentries_list">List Journal Entries</a></td>
<td></td>
<td></td>
</tr>
<tr>
<td></td>
<td>journalentries/{entryId}</td>
<td></td>
<td><a href="#journalentries_retrieve">Retrieve a Journal Entry</a></td>
<td></td>
<td></td>
</tr>
<tr>
<td></td>
<td>journalentries/{transactionId}/reversal</td>
<td><a href="#journalentries_reverse">Reverse Journal Entries</a></td>
<td></td>
<td></td>
<td></td>
</tr>
</table>
</div>
</div>
</div>
</div>
<div id="main-content-wrapper">
@@ -3976,7 +4104,7 @@ Request Body:
</tr>
</tr>
<tr class=alt>
<td>accountingType</td>
<td>accountingRule</td>
</tr>
<tr>
<td class=fielddesc><span>Example Values:</span>NONE(1),
@@ -4055,7 +4183,11 @@ GET https://DomainName/api/v1/loanproducts
"code": "interestCalculationPeriodType.same.as.repayment.period",
"value": "Same as repayment period"
},
"accountingType": 1
"accountingRule": {
"id": 1,
"code": "accountingRuleType.none",
"value": "NONE"
}
}
]
</code>
@@ -4123,7 +4255,7 @@ GET https://DomainName/api/v1/loanproducts/template
"code": "interestCalculationPeriodType.same.as.repayment.period",
"value": "Same as repayment period"
},
"accountingType": 1,
"accountingRule": 1,
"currencyOptions": [
{
"code": "USD",
@@ -4281,6 +4413,158 @@ GET https://DomainName/api/v1/loanproducts/template
}
}
],
"accountingOptions": {
"assetAccountOptions": [
{
"id": 1,
"name": "Fund Source For Loans",
"glCode": "100001",
"disabled": false,
"manualEntriesAllowed": true,
"type": {
"id": 1,
"code": "accountType.asset",
"value": "ASSET"
},
"usage": {
"id": 1,
"code": "accountUsage.detail",
"value": "DETAIL"
},
"description": "Desc"
},
{
"id": 2,
"name": "Interest Receivable",
"glCode": "100002",
"disabled": false,
"manualEntriesAllowed": true,
"type": {
"id": 1,
"code": "accountType.asset",
"value": "ASSET"
},
"usage": {
"id": 1,
"code": "accountUsage.detail",
"value": "DETAIL"
},
"description": "Desc"
},
{
"id": 3,
"name": "Fees Receivable",
"glCode": "100003",
"disabled": false,
"manualEntriesAllowed": true,
"type": {
"id": 1,
"code": "accountType.asset",
"value": "ASSET"
},
"usage": {
"id": 1,
"code": "accountUsage.detail",
"value": "DETAIL"
},
"description": "Desc"
},
{
"id": 4,
"name": "Penalties Receivable",
"glCode": "100004",
"disabled": false,
"manualEntriesAllowed": true,
"type": {
"id": 1,
"code": "accountType.asset",
"value": "ASSET"
},
"usage": {
"id": 1,
"code": "accountUsage.detail",
"value": "DETAIL"
},
"description": "better duddette"
}
],
"expenseAccountOptions": [
{
"id": 5,
"name": "Written Off Losses",
"glCode": "500005",
"disabled": false,
"manualEntriesAllowed": true,
"type": {
"id": 5,
"code": "accountType.expense",
"value": "EXPENSE"
},
"usage": {
"id": 1,
"code": "accountUsage.detail",
"value": "DETAIL"
},
"description": "Desc"
}
],
"incomeAccountOptions": [
{
"id": 6,
"name": "Income from Interest",
"glCode": "400001",
"disabled": false,
"manualEntriesAllowed": true,
"type": {
"id": 4,
"code": "accountType.income",
"value": "INCOME"
},
"usage": {
"id": 1,
"code": "accountUsage.detail",
"value": "DETAIL"
},
"description": "Desc"
},
{
"id": 7,
"name": "Income from Fees",
"glCode": "400002",
"disabled": false,
"manualEntriesAllowed": true,
"type": {
"id": 4,
"code": "accountType.income",
"value": "INCOME"
},
"usage": {
"id": 1,
"code": "accountUsage.detail",
"value": "DETAIL"
},
"description": "Desc"
},
{
"id": 8,
"name": "Income from Penalties",
"glCode": "400003",
"disabled": false,
"manualEntriesAllowed": true,
"type": {
"id": 4,
"code": "accountType.income",
"value": "INCOME"
},
"usage": {
"id": 1,
"code": "accountUsage.detail",
"value": "DETAIL"
},
"description": "Desc"
}
]
},
"accountingMappings": {}
}
</code>
@@ -4355,7 +4639,7 @@ GET https://DomainName/api/v1/loanproducts/{productId}
"code": "interestCalculationPeriodType.same.as.repayment.period",
"value": "Same as repayment period"
},
"accountingType": 1,
"accountingRule": 1,
"charges": []
}
</code>
@@ -4367,7 +4651,17 @@ GET https://DomainName/api/v1/loanproducts/{productId}
<div class="method-section">
<div class="method-description">
<h4>Create a Loan Product</h4>
<table class=matrixHeading>
<p>Depending of the Accounting Rule (accountingRule) selected,
additional fields with details with the appropriate Ledger Account
identifiers would need to be passed in.
</p>
</p>Refer <a href="https://mifosforge.jira.com/wiki/display/MIFOSX/A+Possible+accounting+Spec">
MifosX Accounting Specs Draft</a> for more details regarding the
significance of the selected accounting Rule
</p>
<table class=matrixHeading>
<tr class="matrixHeadingBG">
<td><div class="mifosXHeading2">Mandatory Fields</div></td>
</tr>
@@ -4376,7 +4670,24 @@ GET https://DomainName/api/v1/loanproducts/{productId}
inArrearsTolerance, repaymentFrequencyType, repaymentEvery,
numberOfRepayments, interestRatePerPeriod,
interestRateFrequencyType, amortizationType, interestType,
interestCalculationPeriodType, accountingType</td>
interestCalculationPeriodType, accountingRule</td>
</tr>
<tr class="matrixHeadingBG">
<td><div class="mifosXHeading2">Additional Mandatory Fields for Cash(2) based accounting</div></td>
</tr>
<tr class=alt>
<td>fundSourceAccountId, loanPortfolioAccountId, interestOnLoanAccountId,
incomeFromFeeAccountId, incomeFromPenaltyAccountId,
writeOffAccountId</td>
</tr>
<tr class="matrixHeadingBG">
<td><div class="mifosXHeading2">Additional Mandatory Fields for Accrual(3) based accounting</div></td>
</tr>
<tr class=alt>
<td>fundSourceAccountId, loanPortfolioAccountId, interestOnLoanAccountId,
incomeFromFeeAccountId, incomeFromPenaltyAccountId,
writeOffAccountId, receivableInterestAccountId, receivableFeeAccountId,
receivablePenaltyAccountId</td>
</tr>
</table>
</div>
@@ -4403,7 +4714,7 @@ Request Body:
"amortizationType": 1,
"interestType": 0,
"interestCalculationPeriodType": 1,
"accountingType": 1
"accountingRule": 1
}
</code>
<code class="method-response">
@@ -4411,6 +4722,76 @@ Request Body:
"resourceId": 1
}
</code>
<code class="method-request">
POST loanproducts
Content-Type: application/json
Request Body:
{
"name": "A new loan product for me",
"currencyCode": "USD",
"locale": "en_GB",
"digitsAfterDecimal": "2",
"principal": "100,000.00",
"numberOfRepayments": "12",
"repaymentEvery": "1",
"repaymentFrequencyType": 2,
"transactionProcessingStrategyId": 1,
"interestRatePerPeriod": "1.75",
"interestRateFrequencyType": 2,
"amortizationType": 1,
"interestType": 0,
"interestCalculationPeriodType": 1,
"accountingRule":"3",
"fundSourceAccountId":"15",
"loanPortfolioAccountId":"16",
"interestOnLoanAccountId":"14",
"incomeFromFeeAccountId":"13",
"incomeFromPenaltyAccountId":"12",
"writeOffAccountId":"11"
}
</code>
<code class="method-response">
{
"resourceId": 2
}
</code>
<code class="method-request">
POST loanproducts
Content-Type: application/json
Request Body:
{
"name": "A new loan product for me",
"currencyCode": "USD",
"locale": "en_GB",
"digitsAfterDecimal": "2",
"principal": "100,000.00",
"numberOfRepayments": "12",
"repaymentEvery": "1",
"repaymentFrequencyType": 2,
"transactionProcessingStrategyId": 1,
"interestRatePerPeriod": "1.75",
"interestRateFrequencyType": 2,
"amortizationType": 1,
"interestType": 0,
"interestCalculationPeriodType": 1,
"accountingRule":"3",
"fundSourceAccountId":"15",
"loanPortfolioAccountId":"16",
"receivableInterestAccountId":"10",
"receivableFeeAccountId":"9",
"receivablePenaltyAccountId":"8",
"interestOnLoanAccountId":"14",
"incomeFromFeeAccountId":"13",
"incomeFromPenaltyAccountId":"12",
"writeOffAccountId":"11"
}
</code>
<code class="method-response">
{
"resourceId": 3
}
</code>
</div>
</div>
@@ -6985,6 +7366,390 @@ GET https://DomainName/api/v1/permissions
</div>
</div>
<!-- start of accounting api docs -->
<a id="glaccounts" name="glaccounts" class="old-syle-anchor">&nbsp;</a>
<div class="method-section">
<div class="method-description">
<h3>General Ledger Account</h3>
<p>Ledger accounts represent an Individual account within an Organizations Chart
Of Accounts(COA) and are assigned a name and unique number by which they can
be identified. <br/>
All transactions relating to a company's assets, liabilities, owners' equity,
revenue and expenses are recorded against these accounts
</p>
<table class=matrixHeading>
<tr class="matrixHeadingBG">
<td><div class="mifosXHeading2">Field Descriptions</div></td>
</tr>
<tr class=alt>
<td>name</td>
</tr>
<tr>
<td class=fielddesc>The name of the account</td>
</tr>
<tr class=alt>
<td>glCode</td>
</tr>
<tr>
<td class=fielddesc>The Ledger code associated with the
Account<br>These codes are mandatory and should be unique within
an organization</td>
</tr>
<tr class=alt>
<td>disabled</td>
</tr>
<tr>
<td class=fielddesc>A boolean flag that indicates whether an account
is currently in use</td>
</tr>
<tr class=alt>
<td>type</td>
</tr>
<tr>
<td class=fielddesc>Classifies the account into one of the following Types
<br/><b>Asset accounts:</b> represent the different types of economic resources
owned or controlled by business, common examples of Asset accounts are cash,
cash in bank, building, inventory, prepaid rent, goodwill, accounts receivable<br/>
<b>Liability accounts:</b> represent the different types of economic obligations
by a business, such as accounts payable, bank loan, bonds payable<br/>
<b>Income accounts:</b> represent the company's gross earnings and common examples
include Interest Income, Sales and Service revenue<br/>
<b>Expense accounts:</b> represent the company's expenditures to enable itself to
operate. Common examples are electricity and water, rentals, depreciation,
doubtful accounts, insurance.<br/>
<b>Equity accounts:</b> represent the residual equity of a business (after
deducting from Assets all the liabilities) including Retained Earnings
and Appropriations <br/><br/>
The options are fully listed in <a href="#glaccounts_template">Retrieve
General Ledger Accounts Template</a>.
</td>
</tr>
<tr class=alt>
<td>usage</td>
</tr>
<tr>
<td class=fielddesc>Determines how the account shall be used<br>
"Header" accounts specify the title of a group of accounts. Header accounts are used
only to group detail accounts that have a similar purpose; that is, detail accounts
are assigned to specific header accounts
<br/>
"Detail" accounts may have transactions logged against them<br/><br/>
The options are fully listed in <a href="#glaccounts_template">Retrieve
General Ledger Accounts Template</a>.
</td>
</tr>
<tr class=alt>
<td>manualEntriesAllowed</td>
</tr>
<tr>
<td class=fielddesc>Specifies if manual adjustments can be made
against this account using the <a href="#journalentries_create">
Create Journal Entries API</a> </td>
</tr>
<tr class=alt>
<td>description</td>
</tr>
<tr>
<td class=fielddesc>Human understandable description for the Ledger Account
</td>
</tr>
</table>
</div>
</div>
<a id="glaccounts_list" name="glaccounts_list" class="old-syle-anchor">&nbsp;</a>
<div class="method-section">
<div class="method-description">
<h4>List General Ledger Accounts</h4>
<h5>Arguments</h5>
<dl class="argument-list">
<dt>type</dt>
<dd>
Integer <span>optional</span>
</dd>
<dt>manualAdjustmentsAllowed</dt>
<dd>
boolean <span>optional</span>
</dd>
<dt>usage</dt>
<dd>
Integer <span>optional</span>
</dd>
<dt>disabled</dt>
<dd>
boolean <span>optional</span>
</dd>
</dl>
<p>Example Requests:</p>
<div class=apiClick>glaccounts</div>
<br>
<br>
<div class=apiClick>glaccounts?type=1&manualAdjustmentsAllowed=true&usage=1&disabled=false</div>
</div>
<div class="method-example">
<code class="method-declaration">
GET https://DomainName/api/v1/glaccounts
</code>
<code class="method-response">
[
{
"id": 16,
"name": "Cash",
"glCode": "100001",
"disabled": false,
"manualEntriesAllowed": true,
"type": {
"id": 1,
"code": "accountType.asset",
"value": "ASSET"
},
"usage": {
"id": 1,
"code": "accountUsage.detail",
"value": "DETAIL"
},
"description": "Desc"
},
{
"id": 15,
"name": "Fund Source For Loan",
"glCode": "100002",
"disabled": false,
"manualEntriesAllowed": true,
"type": {
"id": 1,
"code": "accountType.asset",
"value": "ASSET"
},
"usage": {
"id": 1,
"code": "accountUsage.detail",
"value": "DETAIL"
},
"description": "Desc"
}
]
</code>
</div>
</div>
<a id="glaccounts_template" name="glaccounts_template"
class="old-syle-anchor">&nbsp;</a>
<div class="method-section">
<div class="method-description">
<h4>Retrieve GL Accounts 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>
<p>Example Request:</p>
<div class=apiClick>glaccounts/template</div>
</div>
<div class="method-example">
<code class="method-declaration">
GET https://DomainName/api/v1/glaccounts/template
</code>
<code class="method-response">
{
"disabled": false,
"manualEntriesAllowed": true,
"type": {
"id": 1,
"code": "accountType.asset",
"value": "ASSET"
},
"usage": {
"id": 1,
"code": "accountUsage.detail",
"value": "DETAIL"
},
"accountTypeOptions": [
{
"id": 1,
"code": "accountType.asset",
"value": "ASSET"
},
{
"id": 2,
"code": "accountType.liability",
"value": "LIABILITY"
},
{
"id": 3,
"code": "accountType.equity",
"value": "EQUITY"
},
{
"id": 4,
"code": "accountType.income",
"value": "INCOME"
},
{
"id": 5,
"code": "accountType.expense",
"value": "EXPENSE"
}
],
"usageOptions": [
{
"id": 1,
"code": "accountUsage.detail",
"value": "DETAIL"
},
{
"id": 2,
"code": "accountUsage.header",
"value": "HEADER"
}
]
}
</code>
</div>
</div>
<a id="glaccounts_retrieve" name="glaccounts_retrieve"
class="old-syle-anchor">&nbsp;</a>
<div class="method-section">
<div class="method-description">
<h4>Retrieve a General Ledger Account</h4>
<p>Example Requests:</p>
<div class=apiClick>glaccounts/1</div>
<br>
<br>
<div class=apiClick>glaccounts/1?template=true</div>
<br>
<br>
<div class=apiClick>glaccounts/1?fields=name,glCode</div>
</div>
<div class="method-example">
<code class="method-declaration">
GET https://DomainName/api/v1/glaccounts/{glaccountsId}
</code>
<code class="method-response">
{
"id": 1,
"name": "Cash",
"glCode": "100001",
"disabled": false,
"manualEntriesAllowed": true,
"type": {
"id": 1,
"code": "accountType.asset1",
"value": "ASSET"
},
"usage": {
"id": 1,
"code": "accountUsage.detail",
"value": "DETAIL"
},
"description": "Desc"
}
</code>
</div>
</div>
<a id="glaccounts_create" name="glaccounts_create" class="old-syle-anchor">&nbsp;</a>
<div class="method-section">
<div class="method-description">
<h4>Create a General Ledger Account</h4>
<p>
<b>Note:</b> You can optionally<br>
create a Hierarchical Chart of Account by using the "parentId"
property of an Account<br>
</p>
<table class=matrixHeading>
<tr class="matrixHeadingBG">
<td><div class="mifosXHeading2">Mandatory Fields</div></td>
</tr>
<tr class=alt>
<td>name, glCode, classification, usage and manualEntriesAllowed
</td>
</tr>
</table>
</div>
<div class="method-example">
<code class="method-declaration">
POST https://DomainName/api/v1/glaccounts_update
</code>
<code class="method-request">
POST glaccounts
Content-Type: application/json
Request Body:
{
"name": "Cash at Bangalore",
"glCode": "100017",
"manualEntriesAllowed": true,
"classification": 1,
"usage": 1,
"description": "Cash at Bangalore Branch"
}
</code>
<code class="method-response">
{
"resourceId": 22
}
</code>
</div>
</div>
<a id="glaccounts_update" name="glaccounts_update" class="old-syle-anchor">&nbsp;</a>
<div class="method-section">
<div class="method-description">
<h4>Update a General Ledger Account</h4>
</div>
<div class="method-example">
<code class="method-declaration">
PUT https://DomainName/api/v1/glaccounts/{glaccountId}
</code>
<code class="method-request">
PUT glaccounts/1
Content-Type: application/json
Request Body:
{
"name": "Cash at Tumkur"
}
</code>
<code class="method-response">
{
"resourceId": 1,
}
</code>
</div>
</div>
<a id="glaccounts_delete" name="glaccounts_delete" class="old-syle-anchor">&nbsp;</a>
<div class="method-section">
<div class="method-description">
<h4>Delete a General Ledger Account</h4>
<p>
<b>Note:</b> Only Ledger Accounts against which no transactions have been logged
(either manually or by the loan or Savings portfolio) can be deleted.
</p>
</div>
<div class="method-example">
<code class="method-declaration">
DELETE https://DomainName/api/v1/glaccounts/{glaccountId}
</code>
<code class="method-request">
DELETE glaccounts/1
Content-Type: application/json
No Request Body:
</code>
<code class="method-response">
{
"resourceId": 1
}
</code>
</div>
</div>
</div>
<!-- main-content-wrapper -->
@@ -70,7 +70,7 @@ public class GLAccountsApiResource {
@GET
@Consumes({ MediaType.APPLICATION_JSON })
@Produces({ MediaType.APPLICATION_JSON })
public String retrieveAllAccounts(@Context final UriInfo uriInfo, @QueryParam("classification") final Integer classification,
public String retrieveAllAccounts(@Context final UriInfo uriInfo, @QueryParam("type") final Integer classification,
@QueryParam("searchParam") final String searchParam, @QueryParam("usage") final Integer usage,
@QueryParam("manualAdjustmentsAllowed") final Boolean manualTransactionsAllowed, @QueryParam("disabled") final Boolean disabled) {
@@ -15,6 +15,7 @@ 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.mifosplatform.accounting.api.commands.GLJournalEntryCommand;
import org.mifosplatform.accounting.api.data.GLJournalEntryData;
import org.mifosplatform.accounting.api.data.JournalEntryIdentifier;
@@ -24,6 +25,7 @@ import org.mifosplatform.accounting.api.infrastructure.DateParam;
import org.mifosplatform.accounting.service.GLJournalEntryReadPlatformService;
import org.mifosplatform.accounting.service.GLJournalEntryWritePlatformService;
import org.mifosplatform.infrastructure.core.api.ApiParameterHelper;
import org.mifosplatform.infrastructure.core.exception.UnrecognizedQueryParamException;
import org.mifosplatform.infrastructure.security.service.PlatformSecurityContext;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Scope;
@@ -58,9 +60,9 @@ public class GLJournalEntriesApiResource {
@Consumes({ MediaType.APPLICATION_JSON })
@Produces({ MediaType.APPLICATION_JSON })
public String retrieveAllJournalEntries(@Context final UriInfo uriInfo, @QueryParam("officeId") final Long officeId,
@QueryParam("glAccountId") final Long glAccountId,
@QueryParam("portfolioGenerated") final Boolean portfolioGenerated, @QueryParam("fromDate") final DateParam fromDateParam,
@QueryParam("toDate") final DateParam toDateParam) {
@QueryParam("glAccountId") final Long glAccountId, @QueryParam("portfolioGenerated") final Boolean portfolioGenerated,
@QueryParam("fromDate") final DateParam fromDateParam, @QueryParam("toDate") final DateParam toDateParam,
@QueryParam("transactionId") String transactionId) {
// TODO: Vishwas Add pagination, approach at
// http://www.javaworld.com/community/node/8295 looks good
@@ -79,8 +81,13 @@ public class GLJournalEntriesApiResource {
if (toDateParam != null) {
toDate = toDateParam.getDate();
}
glJournalEntryDatas = this.glJournalEntryReadPlatformService.retrieveAllGLJournalEntries(officeId, glAccountId,
portfolioGenerated, fromDate, toDate);
if (StringUtils.isBlank(transactionId)) {
glJournalEntryDatas = this.glJournalEntryReadPlatformService.retrieveAllGLJournalEntries(officeId, glAccountId,
portfolioGenerated, fromDate, toDate);
} else {
glJournalEntryDatas = this.glJournalEntryReadPlatformService.retrieveRelatedJournalEntries(transactionId);
}
return this.apiJsonSerializerService.serializeGLJournalEntryDataToJson(prettyPrint, responseParameters, glJournalEntryDatas);
}
@@ -88,7 +95,7 @@ public class GLJournalEntriesApiResource {
@Path("{glJournalEntryId}")
@Consumes({ MediaType.APPLICATION_JSON })
@Produces({ MediaType.APPLICATION_JSON })
public String retreiveAccount(@PathParam("glJournalEntryId") final Long glJournalEntryId, @Context final UriInfo uriInfo) {
public String retreiveJournalEntryById(@PathParam("glJournalEntryId") final Long glJournalEntryId, @Context final UriInfo uriInfo) {
context.authenticatedUser().validateHasReadPermission(entityType);
@@ -111,13 +118,21 @@ public class GLJournalEntriesApiResource {
}
@POST
@Path("{transactionId}/reversal")
@Path("{transactionId}")
@Consumes({ MediaType.APPLICATION_JSON })
@Produces({ MediaType.APPLICATION_JSON })
public String createReversalJournalEntry(@PathParam("transactionId") final String transactionId) {
this.glJournalEntryWritePlatformService.revertJournalEntry(transactionId);
public String createReversalJournalEntry(@PathParam("transactionId") final String transactionId,
@QueryParam("command") final String commandParam) {
if (is(commandParam, "reverse")) {
this.glJournalEntryWritePlatformService.revertJournalEntry(transactionId);
} else {
throw new UnrecognizedQueryParamException("command", commandParam);
}
return this.apiJsonSerializerService.serializeJournalEntryIdentifier(new JournalEntryIdentifier(transactionId));
}
private boolean is(final String commandParam, final String commandValue) {
return StringUtils.isNotBlank(commandParam) && commandParam.trim().equalsIgnoreCase(commandValue);
}
}
@@ -0,0 +1,18 @@
package org.mifosplatform.accounting.exceptions;
import org.mifosplatform.infrastructure.core.exception.AbstractPlatformResourceNotFoundException;
/**
* A {@link RuntimeException} thrown when journal entry resources are not found.
*/
public class GLJournalEntryNotFoundException extends AbstractPlatformResourceNotFoundException {
public GLJournalEntryNotFoundException(final String transactionId) {
super("error.msg.journalEntries.transactionId.invalid", "Journal Entries with transaction Identifier " + transactionId
+ " does not exist or are not system generated/reversible ", transactionId);
}
public GLJournalEntryNotFoundException(final Long entryId) {
super("error.msg.journalEntries.id.invalid", "Journal Entry with entry Id " + entryId + " does not exist ", entryId);
}
}
@@ -30,7 +30,7 @@ public class GLAccountCommandValidator {
baseDataValidator.reset().parameter("parentId").value(command.getParentId()).ignoreIfNull().integerGreaterThanZero();
baseDataValidator.reset().parameter("classification").value(command.getClassification())
baseDataValidator.reset().parameter("classification").value(command.getClassification()).notNull()
.inMinMaxRange(GLAccountType.getMinValue(), GLAccountType.getMaxValue());
baseDataValidator.reset().parameter("usage").value(command.getUsage())
@@ -10,6 +10,8 @@ public interface GLJournalEntryReadPlatformService {
List<GLJournalEntryData> retrieveAllGLJournalEntries(Long officeId, Long glAccountId, Boolean portfolioGenerated, Date fromDate,
Date toDate);
List<GLJournalEntryData> retrieveRelatedJournalEntries(String transactionId);
GLJournalEntryData retrieveGLJournalEntryById(long glJournalEntryId);
}
@@ -45,7 +45,7 @@ public class GLAccountReadPlatformServiceImpl implements GLAccountReadPlatformSe
Long id = rs.getLong("id");
String name = rs.getString("name");
Long parentId = rs.getLong("parentId");
Long parentId = JdbcSupport.getLong(rs,"parentId");
String glCode = rs.getString("glCode");
boolean disabled = rs.getBoolean("disabled");
boolean manualEntriesAllowed = rs.getBoolean("manualEntriesAllowed");
@@ -73,7 +73,7 @@ public class GLClosureReadPlatformServiceImpl implements GLClosureReadPlatformSe
arrayPos = arrayPos + 1;
}
sql = sql + " order by glClosure.closing_date";
sql = sql + " order by glClosure.closing_date desc";
Object[] finalObjectArray = Arrays.copyOf(objectArray, arrayPos);
return this.jdbcTemplate.query(sql, rm, finalObjectArray);
@@ -134,7 +134,7 @@ public class GLJournalEntryReadPlatformServiceImpl implements GLJournalEntryRead
}
}
sql += " order by journalEntry.entry_date,journalEntry.transaction_id";
sql += " order by journalEntry.entry_date desc,journalEntry.transaction_id";
Object[] finalObjectArray = Arrays.copyOf(objectArray, arrayPos);
return this.jdbcTemplate.query(sql, rm, finalObjectArray);
@@ -147,12 +147,27 @@ public class GLJournalEntryReadPlatformServiceImpl implements GLJournalEntryRead
GLJournalEntryMapper rm = new GLJournalEntryMapper();
String sql = "select " + rm.schema() + " and journalEntry.id = ?";
GLJournalEntryData glAccountData = this.jdbcTemplate.queryForObject(sql, rm, new Object[] { glJournalEntryId });
GLJournalEntryData glJournalEntryData = this.jdbcTemplate.queryForObject(sql, rm, new Object[] { glJournalEntryId });
return glAccountData;
return glJournalEntryData;
} catch (EmptyResultDataAccessException e) {
throw new GLJournalEntriesNotFoundException(glJournalEntryId);
}
}
@Override
public List<GLJournalEntryData> retrieveRelatedJournalEntries(String transactionId) {
try {
GLJournalEntryMapper rm = new GLJournalEntryMapper();
String sql = "select " + rm.schema() + " and journalEntry.transaction_id = ?";
List<GLJournalEntryData> journalEntryDatas = this.jdbcTemplate.query(sql, rm, new Object[] { transactionId });
return journalEntryDatas;
} catch (EmptyResultDataAccessException e) {
throw new GLJournalEntriesNotFoundException(transactionId);
}
}
}
@@ -50,7 +50,7 @@ public class ProductToGLAccountMappingWritePlatformServiceImpl implements Produc
@Transactional
public void createLoanProductToGLAccountMapping(final Long loanProductId, final JsonCommand command) {
final JsonElement element = this.fromApiJsonHelper.parse(command.json());
final Integer accountingRuleTypeId = this.fromApiJsonHelper.extractIntegerNamed("accountingType", element, Locale.getDefault());
final Integer accountingRuleTypeId = this.fromApiJsonHelper.extractIntegerNamed("accountingRule", element, Locale.getDefault());
final AccountingRuleType accountingRuleType = AccountingRuleType.fromInt(accountingRuleTypeId);
switch (accountingRuleType) {
@@ -41,7 +41,7 @@ public class CommandWrapperBuilder {
this.json = withJson;
return this;
}
public CommandWrapperBuilder updateGlobalConfiguration() {
this.actionName = "UPDATE";
this.entityName = "CONFIGURATION";
@@ -127,7 +127,7 @@ public class CommandWrapperBuilder {
this.href = "/officetransactions/template";
return this;
}
public CommandWrapperBuilder deleteOfficeTransaction(final Long transactionId) {
this.actionName = "DELETE";
this.entityName = "OFFICETRANSACTION";
@@ -151,28 +151,31 @@ public class CommandWrapperBuilder {
this.href = "/staff/" + staffId;
return this;
}
public CommandWrapperBuilder createGuarantor() {
public CommandWrapperBuilder createGuarantor(final Long loanId) {
this.actionName = "CREATE";
this.entityName = "GUARANTOR";
this.entityId = null;
this.href = "/guarantors/template";
this.loanId = loanId;
this.href = "/loans/" + loanId + "/guarantors/template";
return this;
}
public CommandWrapperBuilder updateGuarantor(final Long guarantorId) {
public CommandWrapperBuilder updateGuarantor(final Long loanId, final Long guarantorId) {
this.actionName = "UPDATE";
this.entityName = "GUARANTOR";
this.entityId = guarantorId;
this.href = "/guarantors/" + guarantorId;
this.loanId = loanId;
this.href = "/loans/" + loanId + "/guarantors/" + guarantorId;
return this;
}
public CommandWrapperBuilder deleteGuarantor(final Long guarantorId) {
public CommandWrapperBuilder deleteGuarantor(final Long loanId, final Long guarantorId) {
this.actionName = "DELETE";
this.entityName = "GUARANTOR";
this.entityId = guarantorId;
this.href = "/guarantors/" + guarantorId;
this.loanId = loanId;
this.href = "/loans/" + loanId + "/guarantors/" + guarantorId;
return this;
}
@@ -549,7 +552,7 @@ public class CommandWrapperBuilder {
this.href = "/loans/" + loanId;
return this;
}
public CommandWrapperBuilder unassignLoanOfficer(final Long loanId) {
this.actionName = "REMOVELOANOFFICER";
this.entityName = "LOAN";
@@ -565,7 +568,7 @@ public class CommandWrapperBuilder {
this.href = "/loans/loanreassignment";
return this;
}
public CommandWrapperBuilder createCodeValue(final Long codeId) {
this.actionName = "CREATE";
this.entityName = "CODEVALUE";
@@ -573,7 +576,7 @@ public class CommandWrapperBuilder {
this.href = "/codes/" + codeId + "/codevalues/template";
return this;
}
public CommandWrapperBuilder updateCodeValue(Long codeId, final Long codeValueId) {
this.actionName = "UPDATE";
this.entityName = "CODEVALUE";
@@ -582,7 +585,7 @@ public class CommandWrapperBuilder {
this.href = "/codes/" + codeId + "/codevalues/" + codeValueId;
return this;
}
public CommandWrapperBuilder deleteCodeValue(Long codeId, final Long codeValueId) {
this.actionName = "DELETE";
this.entityName = "CODEVALUE";
@@ -34,12 +34,12 @@ import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Scope;
import org.springframework.stereotype.Component;
@Path("/guarantors")
@Path("/loans/{loanId}/guarantors")
@Component
@Scope("singleton")
public class GuarantorsApiResource {
private static final Set<String> RESPONSE_DATA_PARAMETERS = new HashSet<String>(Arrays.asList("externalGuarantor", "existingClientId",
private static final Set<String> RESPONSE_DATA_PARAMETERS = new HashSet<String>(Arrays.asList("guarantorTypeId", "entityId",
"firstname", "lastname", "addressLine1", "addressLine2", "city", "state", "zip", "country", "mobileNumber", "housePhoneNumber",
"comment", "dob"));
@@ -75,14 +75,28 @@ public class GuarantorsApiResource {
return this.apiJsonSerializerService.serialize(settings, guarantorData, RESPONSE_DATA_PARAMETERS);
}
@GET
@Consumes({ MediaType.APPLICATION_JSON })
@Produces({ MediaType.APPLICATION_JSON })
public String retrieveGuarantorDetails(@Context final UriInfo uriInfo, @PathParam("loanId") final Long loanId) {
context.authenticatedUser().validateHasReadPermission(resourceNameForPermission);
List<GuarantorData> guarantorDatas = guarantorReadPlatformService.retrieveGuarantorsForValidLoan(loanId);
final ApiRequestJsonSerializationSettings settings = apiRequestParameterHelper.process(uriInfo.getQueryParameters());
return this.apiJsonSerializerService.serialize(settings, guarantorDatas, RESPONSE_DATA_PARAMETERS);
}
@GET
@Path("{guarantorId}")
@Consumes({ MediaType.APPLICATION_JSON })
@Produces({ MediaType.APPLICATION_JSON })
public String retrieveGuarantorDetails(@Context final UriInfo uriInfo, @PathParam("guarantorId") final Long guarantorId) {
public String retrieveGuarantorDetails(@Context final UriInfo uriInfo, @PathParam("loanId") final Long loanId,
@PathParam("guarantorId") final Long guarantorId) {
context.authenticatedUser().validateHasReadPermission(resourceNameForPermission);
GuarantorData guarantorData = guarantorReadPlatformService.retrieveGuarantor(guarantorId);
GuarantorData guarantorData = guarantorReadPlatformService.retrieveGuarantor(loanId, guarantorId);
final ApiRequestJsonSerializationSettings settings = apiRequestParameterHelper.process(uriInfo.getQueryParameters());
if (settings.isTemplate()) {
@@ -96,9 +110,9 @@ public class GuarantorsApiResource {
@POST
@Consumes({ MediaType.APPLICATION_JSON })
@Produces({ MediaType.APPLICATION_JSON })
public String createGuarantor(final String apiRequestBodyAsJson) {
public String createGuarantor(@PathParam("loanId") final Long loanId, final String apiRequestBodyAsJson) {
final CommandWrapper commandRequest = new CommandWrapperBuilder().createGuarantor().withJson(apiRequestBodyAsJson).build();
final CommandWrapper commandRequest = new CommandWrapperBuilder().createGuarantor(loanId).withJson(apiRequestBodyAsJson).build();
final CommandProcessingResult result = this.commandsSourceWritePlatformService.logCommandSource(commandRequest);
@@ -109,8 +123,10 @@ public class GuarantorsApiResource {
@Path("{guarantorId}")
@Consumes({ MediaType.APPLICATION_JSON })
@Produces({ MediaType.APPLICATION_JSON })
public String updateGuarantor(@PathParam("guarantorId") final Long guarantorId, final String jsonRequestBody) {
final CommandWrapper commandRequest = new CommandWrapperBuilder().updateGuarantor(guarantorId).withJson(jsonRequestBody).build();
public String updateGuarantor(@PathParam("loanId") final Long loanId, @PathParam("guarantorId") final Long guarantorId,
final String jsonRequestBody) {
final CommandWrapper commandRequest = new CommandWrapperBuilder().updateGuarantor(loanId, guarantorId).withJson(jsonRequestBody)
.build();
final CommandProcessingResult result = this.commandsSourceWritePlatformService.logCommandSource(commandRequest);
@@ -121,8 +137,8 @@ public class GuarantorsApiResource {
@Path("{guarantorId}")
@Consumes({ MediaType.APPLICATION_JSON })
@Produces({ MediaType.APPLICATION_JSON })
public String deleteGuarantor(@PathParam("guarantorId") final Long guarantorId) {
final CommandWrapper commandRequest = new CommandWrapperBuilder().deleteGuarantor(guarantorId).build();
public String deleteGuarantor(@PathParam("loanId") final Long loanId, @PathParam("guarantorId") final Long guarantorId) {
final CommandWrapper commandRequest = new CommandWrapperBuilder().deleteGuarantor(loanId, guarantorId).build();
final CommandProcessingResult result = this.commandsSourceWritePlatformService.logCommandSource(commandRequest);
@@ -6,9 +6,24 @@ import org.mifosplatform.portfolio.loanaccount.guarantor.data.GuarantorData;
public interface GuarantorReadPlatformService {
/**
* Validates the passed in loanId before retrieving Loans for the same
*
* @param loanId
* @return
*/
List<GuarantorData> retrieveGuarantorsForValidLoan(Long loanId);
/**
* Methods Returns all Guarantors for a Given loan Id (if the loan Id is
* valid and Exists)
*
* @param loanId
* @return
*/
List<GuarantorData> retrieveGuarantorsForLoan(Long loanId);
GuarantorData retrieveGuarantor(Long guarantorId);
GuarantorData retrieveGuarantor(Long loanId, Long guarantorId);
GuarantorData retrieveNewGuarantorDetails();
@@ -13,6 +13,9 @@ import org.mifosplatform.organisation.staff.data.StaffData;
import org.mifosplatform.organisation.staff.service.StaffReadPlatformService;
import org.mifosplatform.portfolio.client.data.ClientData;
import org.mifosplatform.portfolio.client.service.ClientReadPlatformService;
import org.mifosplatform.portfolio.loanaccount.domain.Loan;
import org.mifosplatform.portfolio.loanaccount.domain.LoanRepository;
import org.mifosplatform.portfolio.loanaccount.exception.LoanNotFoundException;
import org.mifosplatform.portfolio.loanaccount.guarantor.data.GuarantorData;
import org.mifosplatform.portfolio.loanaccount.guarantor.domain.GuarantorType;
import org.springframework.beans.factory.annotation.Autowired;
@@ -26,13 +29,16 @@ public class GuarantorReadPlatformServiceImpl implements GuarantorReadPlatformSe
private final JdbcTemplate jdbcTemplate;
private final ClientReadPlatformService clientReadPlatformService;
private final StaffReadPlatformService staffReadPlatformService;
private final LoanRepository loanRepository;
@Autowired
public GuarantorReadPlatformServiceImpl(final TenantAwareRoutingDataSource dataSource,
final ClientReadPlatformService clientReadPlatformService, final StaffReadPlatformService staffReadPlatformService) {
final ClientReadPlatformService clientReadPlatformService, final StaffReadPlatformService staffReadPlatformService,
final LoanRepository loanRepository) {
this.jdbcTemplate = new JdbcTemplate(dataSource);
this.clientReadPlatformService = clientReadPlatformService;
this.staffReadPlatformService = staffReadPlatformService;
this.loanRepository = loanRepository;
}
private static final class GuarantorMapper implements RowMapper<GuarantorData> {
@@ -68,6 +74,13 @@ public class GuarantorReadPlatformServiceImpl implements GuarantorReadPlatformSe
}
}
@Override
public List<GuarantorData> retrieveGuarantorsForValidLoan(Long loanId) {
Loan loan = this.loanRepository.findOne(loanId);
if (loan == null) { throw new LoanNotFoundException(loanId); }
return retrieveGuarantorsForLoan(loanId);
}
@Override
public List<GuarantorData> retrieveGuarantorsForLoan(Long loanId) {
final GuarantorMapper rm = new GuarantorMapper();
@@ -84,11 +97,11 @@ public class GuarantorReadPlatformServiceImpl implements GuarantorReadPlatformSe
}
@Override
public GuarantorData retrieveGuarantor(Long guarantorId) {
public GuarantorData retrieveGuarantor(Long loanId, Long guarantorId) {
final GuarantorMapper rm = new GuarantorMapper();
String sql = "select " + rm.schema();
sql += " where loan_id = ?";
GuarantorData guarantorData = this.jdbcTemplate.queryForObject(sql, rm, new Object[] { guarantorId });
sql += " where g.loan_id = ? and g.id = ?";
GuarantorData guarantorData = this.jdbcTemplate.queryForObject(sql, rm, new Object[] { loanId, guarantorId });
return mergeDetailsForClientOrStaffGuarantor(guarantorData);
}
@@ -58,7 +58,7 @@ public class GuarantorWritePlatformServiceJpaRepositoryIImpl implements Guaranto
final GuarantorCommand guarantorCommand = this.fromApiJsonDeserializer.commandFromApiJson(command.json());
guarantorCommand.validateForCreate();
final Long loanId = command.longValueOfParameterNamed(GUARANTOR_JSON_INPUT_PARAMS.LOAN_ID.getValue());
final Long loanId = command.getLoanId();
Loan loan = retrieveLoanById(loanId);
Guarantor guarantor = null;
guarantor = Guarantor.fromJson(loan, command);
@@ -83,6 +83,7 @@ public class GuarantorWritePlatformServiceJpaRepositoryIImpl implements Guaranto
final GuarantorCommand guarantorCommand = this.fromApiJsonDeserializer.commandFromApiJson(command.json());
guarantorCommand.validateForUpdate();
// TODO: Vishwas need to fetch by both loan and Guarantor Id
final Guarantor guarantorForUpdate = this.guarantorRepository.findOne(guarantorId);
if (guarantorForUpdate == null) { throw new GuarantorNotFoundException(guarantorId); }
@@ -108,6 +109,7 @@ public class GuarantorWritePlatformServiceJpaRepositoryIImpl implements Guaranto
@Override
@Transactional
public CommandProcessingResult removeGuarantor(final Long guarantorId) {
// TODO: Vishwas need to fetch by both loan and Guarantor Id
final Guarantor guarantorForDelete = this.guarantorRepository.findOne(guarantorId);
if (guarantorForDelete == null) { throw new GuarantorNotFoundException(guarantorId); }
@@ -19,7 +19,6 @@ import javax.ws.rs.core.Context;
import javax.ws.rs.core.MediaType;
import javax.ws.rs.core.UriInfo;
import org.mifosplatform.accounting.AccountingConstants.LOAN_PRODUCT_ACCOUNTING_PARAMS;
import org.mifosplatform.accounting.api.data.GLAccountData;
import org.mifosplatform.accounting.domain.GLAccountType;
import org.mifosplatform.accounting.service.GLAccountReadPlatformService;
@@ -58,12 +57,7 @@ public class LoanProductsApiResource {
"interestRateFrequencyType", "amortizationType", "interestType", "interestCalculationPeriodType", "charges", "createdOn",
"lastModifedOn", "currencyOptions", "amortizationTypeOptions", "interestTypeOptions", "interestCalculationPeriodTypeOptions",
"repaymentFrequencyTypeOptions", "interestRateFrequencyTypeOptions", "fundOptions", "transactionProcessingStrategyOptions",
"chargeOptions", "assetAccountOptions", "incomeAccountOptions", "expenseAccountOptions", "accountingType",
LOAN_PRODUCT_ACCOUNTING_PARAMS.FEES_RECEIVABLE.getValue(), LOAN_PRODUCT_ACCOUNTING_PARAMS.FUND_SOURCE.getValue(),
LOAN_PRODUCT_ACCOUNTING_PARAMS.INCOME_FROM_FEES.getValue(), LOAN_PRODUCT_ACCOUNTING_PARAMS.INCOME_FROM_PENALTIES.getValue(),
LOAN_PRODUCT_ACCOUNTING_PARAMS.INTEREST_ON_LOANS.getValue(), LOAN_PRODUCT_ACCOUNTING_PARAMS.INTEREST_RECEIVABLE.getValue(),
LOAN_PRODUCT_ACCOUNTING_PARAMS.LOAN_PORTFOLIO.getValue(), LOAN_PRODUCT_ACCOUNTING_PARAMS.LOSSES_WRITTEN_OFF.getValue(),
LOAN_PRODUCT_ACCOUNTING_PARAMS.PENALTIES_RECEIVABLE.getValue()));
"chargeOptions", "accountingOptions", "accountingRule","accountingRuleOptions","accountingMappings","accountingMappingOptions"));
private final String resourceNameForPermissions = "LOANPRODUCT";
@@ -205,22 +199,29 @@ public class LoanProductsApiResource {
final Collection<TransactionProcessingStrategyData> transactionProcessingStrategyOptions = this.dropdownReadPlatformService
.retreiveTransactionProcessingStrategies();
Map<String, List<GLAccountData>> accountOptions= new HashMap<String, List<GLAccountData>>();
List<GLAccountData> assetAccountOptions = accountReadPlatformService.retrieveAllEnabledDetailGLAccounts(GLAccountType.ASSET);
if (assetAccountOptions.isEmpty()) {
assetAccountOptions = null;
}
accountOptions.put("assetAccountOptions", assetAccountOptions);
List<GLAccountData> incomeAccountOptions = accountReadPlatformService.retrieveAllEnabledDetailGLAccounts(GLAccountType.INCOME);
if (incomeAccountOptions.isEmpty()) {
incomeAccountOptions = null;
}
accountOptions.put("incomeAccountOptions", incomeAccountOptions);
List<GLAccountData> expenseAccountOptions = accountReadPlatformService.retrieveAllEnabledDetailGLAccounts(GLAccountType.EXPENSE);
if (expenseAccountOptions.isEmpty()) {
expenseAccountOptions = null;
}
accountOptions.put("expenseAccountOptions", expenseAccountOptions);
List<EnumOptionData> accountingRuleTypeOptions = dropdownReadPlatformService.retrieveAccountingRuleTypeOptions();
return new LoanProductData(productData, chargeOptions, currencyOptions, amortizationTypeOptions, interestTypeOptions,
interestCalculationPeriodTypeOptions, loanTermFrequencyTypeOptions, repaymentFrequencyTypeOptions,
interestRateFrequencyTypeOptions, fundOptions, transactionProcessingStrategyOptions, assetAccountOptions,
incomeAccountOptions, expenseAccountOptions, accountingMappings);
interestRateFrequencyTypeOptions, fundOptions, transactionProcessingStrategyOptions, accountOptions, accountingRuleTypeOptions,accountingMappings);
}
}
@@ -44,8 +44,8 @@ public class LoanProductData {
private final EnumOptionData interestType;
private final EnumOptionData interestCalculationPeriodType;
private final BigDecimal inArrearsTolerance;
private final EnumOptionData accountingType;
private final EnumOptionData accountingRule;
private final Collection<ChargeData> charges;
@@ -62,9 +62,8 @@ public class LoanProductData {
private final Collection<ChargeData> chargeOptions;
// accounting related template fields
private final List<GLAccountData> assetAccountOptions;
private final List<GLAccountData> incomeAccountOptions;
private final List<GLAccountData> expenseAccountOptions;
private final List<EnumOptionData> accountingRuleOptions;
private final Map<String, List<GLAccountData>> accountingMappingOptions;
// accounting related mapping fields
@SuppressWarnings("unused")
@@ -140,7 +139,7 @@ public class LoanProductData {
productData.amortizationTypeOptions, productData.interestTypeOptions, productData.interestCalculationPeriodTypeOptions,
productData.loanTermFrequencyTypeOptions, productData.repaymentFrequencyTypeOptions,
productData.interestRateFrequencyTypeOptions, productData.fundOptions, productData.transactionProcessingStrategyOptions,
productData.assetAccountOptions, productData.incomeAccountOptions, productData.expenseAccountOptions, accountingMappings);
productData.accountingMappingOptions, productData.accountingRuleOptions, accountingMappings);
}
public LoanProductData(final Long id, final String name, final String description, final CurrencyData currency,
@@ -173,7 +172,7 @@ public class LoanProductData {
this.transactionProcessingStrategyId = transactionProcessingStrategyId;
this.transactionProcessingStrategyName = transactionProcessingStrategyName;
this.charges = charges;
this.accountingType = accountingType;
this.accountingRule = accountingType;
this.chargeOptions = null;
this.currencyOptions = null;
@@ -186,9 +185,8 @@ public class LoanProductData {
this.repaymentFrequencyTypeOptions = null;
this.interestRateFrequencyTypeOptions = null;
this.assetAccountOptions = null;
this.incomeAccountOptions = null;
this.expenseAccountOptions = null;
this.accountingMappingOptions = null;
this.accountingRuleOptions = null;
this.accountingMappings = null;
}
@@ -198,8 +196,8 @@ public class LoanProductData {
final List<EnumOptionData> loanTermFrequencyTypeOptions, final List<EnumOptionData> repaymentFrequencyTypeOptions,
final List<EnumOptionData> interestRateFrequencyTypeOptions, final Collection<FundData> fundOptions,
final Collection<TransactionProcessingStrategyData> transactionProcessingStrategyOptions,
final List<GLAccountData> assetAccountOptions, final List<GLAccountData> incomeAccountOptions,
final List<GLAccountData> expenseAccountOptions, final Map<String, Object> accountingMappings) {
final Map<String, List<GLAccountData>> accountingMappingOptions, final List<EnumOptionData> accountingRuleOptions,
final Map<String, Object> accountingMappings) {
this.id = productData.id;
this.name = productData.name;
this.description = productData.description;
@@ -221,7 +219,7 @@ public class LoanProductData {
this.transactionProcessingStrategyId = productData.transactionProcessingStrategyId;
this.transactionProcessingStrategyName = productData.transactionProcessingStrategyName;
this.charges = nullIfEmpty(productData.charges());
this.accountingType = productData.accountingType;
this.accountingRule = productData.accountingRule;
this.chargeOptions = chargeOptions;
this.currencyOptions = currencyOptions;
@@ -239,9 +237,8 @@ public class LoanProductData {
this.repaymentFrequencyTypeOptions = repaymentFrequencyTypeOptions;
this.interestRateFrequencyTypeOptions = interestRateFrequencyTypeOptions;
this.assetAccountOptions = assetAccountOptions;
this.incomeAccountOptions = incomeAccountOptions;
this.expenseAccountOptions = expenseAccountOptions;
this.accountingMappingOptions = accountingMappingOptions;
this.accountingRuleOptions = accountingRuleOptions;
this.accountingMappings = accountingMappings;
}
@@ -262,11 +259,11 @@ public class LoanProductData {
}
public EnumOptionData accountingRuleType() {
return this.accountingType;
return this.accountingRule;
}
public boolean hasAccountingEnabled() {
return this.accountingType.getId() > 1;
return this.accountingRule.getId() > 1;
}
public Long getId() {
@@ -33,7 +33,7 @@ public final class LoanProductCommandFromApiJsonDeserializer {
private final Set<String> supportedParameters = new HashSet<String>(Arrays.asList("name", "description", "fundId",
"transactionProcessingStrategyId", "currencyCode", "digitsAfterDecimal", "principal", "inArrearsTolerance",
"interestRatePerPeriod", "repaymentEvery", "numberOfRepayments", "repaymentFrequencyType", "interestRateFrequencyType",
"amortizationType", "interestType", "interestCalculationPeriodType", "charges", "locale", "accountingType",
"amortizationType", "interestType", "interestCalculationPeriodType", "charges", "locale", "accountingRule",
LOAN_PRODUCT_ACCOUNTING_PARAMS.FEES_RECEIVABLE.getValue(), LOAN_PRODUCT_ACCOUNTING_PARAMS.FUND_SOURCE.getValue(),
LOAN_PRODUCT_ACCOUNTING_PARAMS.INCOME_FROM_FEES.getValue(), LOAN_PRODUCT_ACCOUNTING_PARAMS.INCOME_FROM_PENALTIES.getValue(),
LOAN_PRODUCT_ACCOUNTING_PARAMS.INTEREST_ON_LOANS.getValue(), LOAN_PRODUCT_ACCOUNTING_PARAMS.INTEREST_RECEIVABLE.getValue(),
@@ -114,8 +114,8 @@ public final class LoanProductCommandFromApiJsonDeserializer {
.inMinMaxRange(0, 1);
// accounting related data validation
final Integer accountingRuleType = fromApiJsonHelper.extractIntegerNamed("accountingType", element, Locale.getDefault());
baseDataValidator.reset().parameter("accountingType").value(accountingRuleType).notNull().inMinMaxRange(1, 3);
final Integer accountingRuleType = fromApiJsonHelper.extractIntegerNamed("accountingRule", element, Locale.getDefault());
baseDataValidator.reset().parameter("accountingRule").value(accountingRuleType).notNull().inMinMaxRange(1, 3);
if (isCashBasedAccounting(accountingRuleType) || isAccrualBasedAccounting(accountingRuleType)) {
@@ -266,8 +266,8 @@ public final class LoanProductCommandFromApiJsonDeserializer {
.inMinMaxRange(0, 1);
}
final Integer accountingRuleType = fromApiJsonHelper.extractIntegerNamed("accountingType", element, Locale.getDefault());
baseDataValidator.reset().parameter("accountingType").value(accountingRuleType).ignoreIfNull().inMinMaxRange(1, 3);
final Integer accountingRuleType = fromApiJsonHelper.extractIntegerNamed("accountingRule", element, Locale.getDefault());
baseDataValidator.reset().parameter("accountingRule").value(accountingRuleType).ignoreIfNull().inMinMaxRange(1, 3);
final Long fundAccountId = fromApiJsonHelper.extractLongNamed(LOAN_PRODUCT_ACCOUNTING_PARAMS.FUND_SOURCE.getValue(), element);
baseDataValidator.reset().parameter(LOAN_PRODUCT_ACCOUNTING_PARAMS.FUND_SOURCE.getValue()).value(fundAccountId).ignoreIfNull()
@@ -21,4 +21,6 @@ public interface LoanDropdownReadPlatformService {
List<EnumOptionData> retrieveInterestRateFrequencyTypeOptions();
Collection<TransactionProcessingStrategyData> retreiveTransactionProcessingStrategies();
List<EnumOptionData> retrieveAccountingRuleTypeOptions();
}
@@ -6,6 +6,7 @@ import static org.mifosplatform.portfolio.loanproduct.service.LoanEnumerations.i
import static org.mifosplatform.portfolio.loanproduct.service.LoanEnumerations.interestType;
import static org.mifosplatform.portfolio.loanproduct.service.LoanEnumerations.loanTermFrequencyType;
import static org.mifosplatform.portfolio.loanproduct.service.LoanEnumerations.repaymentFrequencyType;
import static org.mifosplatform.portfolio.loanproduct.service.LoanEnumerations.accountingRuleType;
import java.util.ArrayList;
import java.util.Arrays;
@@ -15,6 +16,7 @@ import java.util.List;
import org.mifosplatform.infrastructure.core.data.EnumOptionData;
import org.mifosplatform.portfolio.loanaccount.domain.LoanTransactionProcessingStrategyRepository;
import org.mifosplatform.portfolio.loanproduct.data.TransactionProcessingStrategyData;
import org.mifosplatform.portfolio.loanproduct.domain.AccountingRuleType;
import org.mifosplatform.portfolio.loanproduct.domain.AmortizationMethod;
import org.mifosplatform.portfolio.loanproduct.domain.InterestCalculationPeriodMethod;
import org.mifosplatform.portfolio.loanproduct.domain.InterestMethod;
@@ -103,4 +105,11 @@ public class LoanDropdownReadPlatformServiceImpl implements LoanDropdownReadPlat
return strategyOptions;
}
@Override
public List<EnumOptionData> retrieveAccountingRuleTypeOptions() {
List<EnumOptionData> accountingRuleTypeOptions = Arrays.asList(accountingRuleType(AccountingRuleType.NONE),
accountingRuleType(AccountingRuleType.CASH_BASED),accountingRuleType(AccountingRuleType.ACCRUAL_BASED));
return accountingRuleTypeOptions;
}
}