MIFOSX-247: add basic lifecycle state to savings account and support some constrains around deposits and withdrawals.
This commit is contained in:
+61
-14
@@ -7118,6 +7118,12 @@ Content-Type: application/json
|
|||||||
<tr class=alt><td>externalId</td></tr>
|
<tr class=alt><td>externalId</td></tr>
|
||||||
<tr><td class=fielddesc>A place to put an external reference for this savings account e.g. The ID another system uses. If provided, it must be unique.</td></tr>
|
<tr><td class=fielddesc>A place to put an external reference for this savings account e.g. The ID another system uses. If provided, it must be unique.</td></tr>
|
||||||
|
|
||||||
|
<tr class=alt><td>active</td></tr>
|
||||||
|
<tr><td class=fielddesc>Indicates whether this savings account should go into active state or not automatically</td></tr>
|
||||||
|
|
||||||
|
<tr class=alt><td>activationDate</td></tr>
|
||||||
|
<tr><td class=fielddesc>If <b>active</b> is true the <i>activationDate</i> must be provided. If the savings account has an entry for <i>minRequiredOpeningBalance</i> then a deposit for that amount with <i>activationDate</i> as the date is automatically entered.</td></tr>
|
||||||
|
|
||||||
<tr class=alt><td>interestRate</td></tr>
|
<tr class=alt><td>interestRate</td></tr>
|
||||||
<tr><td class=fielddesc>The default interest rate set when creating savings accounts of this type of product. e.g. <b>5</b>% Per year</td></tr>
|
<tr><td class=fielddesc>The default interest rate set when creating savings accounts of this type of product. e.g. <b>5</b>% Per year</td></tr>
|
||||||
|
|
||||||
@@ -7257,7 +7263,7 @@ Content-Type: application/json
|
|||||||
<br/>
|
<br/>
|
||||||
<table class=matrixHeading>
|
<table class=matrixHeading>
|
||||||
<tr class="matrixHeadingBG"><td><div class="mifosXHeading2">Mandatory Fields</div></td></tr>
|
<tr class="matrixHeadingBG"><td><div class="mifosXHeading2">Mandatory Fields</div></td></tr>
|
||||||
<tr class=alt><td>clientId or groupId, productId, accountNo, externalId</td></tr>
|
<tr class=alt><td>clientId or groupId, productId, accountNo, externalId, active, (activationDate if active is true)</td></tr>
|
||||||
</table>
|
</table>
|
||||||
<br/>
|
<br/>
|
||||||
<table class=matrixHeading>
|
<table class=matrixHeading>
|
||||||
@@ -7273,27 +7279,29 @@ Content-Type: application/json
|
|||||||
<div class="method-example">
|
<div class="method-example">
|
||||||
<p>Minimal request: accountNo auto generated, remaining details inherited from savings product.</p>
|
<p>Minimal request: accountNo auto generated, remaining details inherited from savings product.</p>
|
||||||
<code class="method-declaration">POST https://Domain Name/api/v1/savingsaccounts</code>
|
<code class="method-declaration">POST https://Domain Name/api/v1/savingsaccounts</code>
|
||||||
<code class="method-request">POST savingaccount
|
<code class="method-request">POST savingsaccount
|
||||||
Content-Type: application/json
|
|
||||||
Request Body:
|
|
||||||
{
|
|
||||||
"clientId": 1,
|
|
||||||
"productId": 1
|
|
||||||
}
|
|
||||||
</code>
|
|
||||||
<p>Minimal request: accountNo provided (must be unique), remaining details inherited from savings product.</p>
|
|
||||||
<code class="method-request">POST savingaccount
|
|
||||||
Content-Type: application/json
|
Content-Type: application/json
|
||||||
Request Body:
|
Request Body:
|
||||||
{
|
{
|
||||||
"clientId": 1,
|
"clientId": 1,
|
||||||
"productId": 1,
|
"productId": 1,
|
||||||
|
"active": false
|
||||||
|
}
|
||||||
|
</code>
|
||||||
|
<p>Minimal request: accountNo provided (must be unique), remaining details inherited from savings product.</p>
|
||||||
|
<code class="method-request">POST savingsaccount
|
||||||
|
Content-Type: application/json
|
||||||
|
Request Body:
|
||||||
|
{
|
||||||
|
"clientId": 1,
|
||||||
|
"productId": 1,
|
||||||
|
"active": false,
|
||||||
"accountNo": "SA000023",
|
"accountNo": "SA000023",
|
||||||
"externalId": "SYS-23"
|
"externalId": "SYS-23"
|
||||||
}
|
}
|
||||||
</code>
|
</code>
|
||||||
<p>Full request: accountNo provided (must be unique), remaining details override details from savings product (except currency).</p>
|
<p>Full request: accountNo provided (must be unique), remaining details override details from savings product (except currency).</p>
|
||||||
<code class="method-request">POST savingaccount
|
<code class="method-request">POST savingsaccount
|
||||||
Content-Type: application/json
|
Content-Type: application/json
|
||||||
Request Body:
|
Request Body:
|
||||||
{
|
{
|
||||||
@@ -7301,7 +7309,10 @@ Request Body:
|
|||||||
"productId": 1,
|
"productId": 1,
|
||||||
"accountNo": "SA000023",
|
"accountNo": "SA000023",
|
||||||
"externalId": "SYS-23",
|
"externalId": "SYS-23",
|
||||||
|
"active": true,
|
||||||
"locale": "en",
|
"locale": "en",
|
||||||
|
"dateFormat": "dd MMMM yyyy",
|
||||||
|
"activationDate": "01 March 2011",
|
||||||
"interestRate": "5.65",
|
"interestRate": "5.65",
|
||||||
"interestRatePeriodFrequencyType": 2,
|
"interestRatePeriodFrequencyType": 2,
|
||||||
"minRequiredOpeningBalance": "1,000",
|
"minRequiredOpeningBalance": "1,000",
|
||||||
@@ -7313,6 +7324,35 @@ Request Body:
|
|||||||
{
|
{
|
||||||
"officeId": 1,
|
"officeId": 1,
|
||||||
"clientId": 1,
|
"clientId": 1,
|
||||||
|
"savingsId": 1,
|
||||||
|
"resourceId": 1
|
||||||
|
}
|
||||||
|
</code>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<a id="savingsaccounts_activate" name="savingsaccounts_activate" class="old-syle-anchor"> </a>
|
||||||
|
<div class="method-section">
|
||||||
|
<div class="method-description">
|
||||||
|
<h2>Activate a Savings Account</h2>
|
||||||
|
<p>Activates a savings account.</p>
|
||||||
|
</div>
|
||||||
|
<div class="method-example">
|
||||||
|
<code class="method-declaration">POST https://Domain Name/api/v1/savingsaccounts/{savingsId}?command=activate</code>
|
||||||
|
<code class="method-request">POST savingsaccount/1?command=activate
|
||||||
|
Content-Type: application/json
|
||||||
|
Request Body:
|
||||||
|
{
|
||||||
|
"locale": "en",
|
||||||
|
"dateFormat": "dd MMMM yyyy",
|
||||||
|
"activationDate": "01 March 2011"
|
||||||
|
}
|
||||||
|
</code>
|
||||||
|
<code class="method-response">
|
||||||
|
{
|
||||||
|
"officeId": 1,
|
||||||
|
"clientId": 1,
|
||||||
|
"savingsId": 1,
|
||||||
"resourceId": 1
|
"resourceId": 1
|
||||||
}
|
}
|
||||||
</code>
|
</code>
|
||||||
@@ -11436,6 +11476,14 @@ Content-Type: application/json
|
|||||||
<td><a href="#savingsaccounts_delete">Delete a Savings Account</a></td>
|
<td><a href="#savingsaccounts_delete">Delete a Savings Account</a></td>
|
||||||
</tr>
|
</tr>
|
||||||
<tr class="alt">
|
<tr class="alt">
|
||||||
|
<td></td>
|
||||||
|
<td>savingsaccounts/{accountId}?command=activate</td>
|
||||||
|
<td><a href="#savingsaccounts_activate">Activate a Savings Account</a></td>
|
||||||
|
<td></td>
|
||||||
|
<td></td>
|
||||||
|
<td></td>
|
||||||
|
</tr>
|
||||||
|
<tr>
|
||||||
<td><a href="#savingsaccounts_transactions">Savings Transactions</a></td>
|
<td><a href="#savingsaccounts_transactions">Savings Transactions</a></td>
|
||||||
<td>savingsaccounts/{accountId}/transactions?command=deposit</td>
|
<td>savingsaccounts/{accountId}/transactions?command=deposit</td>
|
||||||
<td><a href="#savingsaccounts_deposit">Make a Deposit</a></td>
|
<td><a href="#savingsaccounts_deposit">Make a Deposit</a></td>
|
||||||
@@ -11443,7 +11491,7 @@ Content-Type: application/json
|
|||||||
<td></td>
|
<td></td>
|
||||||
<td></td>
|
<td></td>
|
||||||
</tr>
|
</tr>
|
||||||
<tr>
|
<tr class="alt">
|
||||||
<td></td>
|
<td></td>
|
||||||
<td>savingsaccounts/{accountId}/transactions?command=withdrawal</td>
|
<td>savingsaccounts/{accountId}/transactions?command=withdrawal</td>
|
||||||
<td><a href="#savingsaccounts_withdrawal">Make a Withdrawal</a></td>
|
<td><a href="#savingsaccounts_withdrawal">Make a Withdrawal</a></td>
|
||||||
@@ -11467,7 +11515,6 @@ Content-Type: application/json
|
|||||||
<td><a href="#offices_update">Update an Office</a></td>
|
<td><a href="#offices_update">Update an Office</a></td>
|
||||||
<td></td>
|
<td></td>
|
||||||
</tr>
|
</tr>
|
||||||
|
|
||||||
<tr class="alt">
|
<tr class="alt">
|
||||||
<td><a href="#configs">CURRENCY</a></td>
|
<td><a href="#configs">CURRENCY</a></td>
|
||||||
<td>currencies</td>
|
<td>currencies</td>
|
||||||
|
|||||||
@@ -729,6 +729,7 @@ CREATE TABLE `m_savings_product` (
|
|||||||
UNIQUE KEY `sp_unq_name` (`name`)
|
UNIQUE KEY `sp_unq_name` (`name`)
|
||||||
) ENGINE=InnoDB DEFAULT CHARSET=utf8;
|
) ENGINE=InnoDB DEFAULT CHARSET=utf8;
|
||||||
|
|
||||||
|
|
||||||
CREATE TABLE `m_savings_account` (
|
CREATE TABLE `m_savings_account` (
|
||||||
`id` bigint(20) NOT NULL AUTO_INCREMENT,
|
`id` bigint(20) NOT NULL AUTO_INCREMENT,
|
||||||
`account_no` varchar(20) NOT NULL,
|
`account_no` varchar(20) NOT NULL,
|
||||||
@@ -736,6 +737,8 @@ CREATE TABLE `m_savings_account` (
|
|||||||
`client_id` bigint(20) DEFAULT NULL,
|
`client_id` bigint(20) DEFAULT NULL,
|
||||||
`group_id` bigint(20) DEFAULT NULL,
|
`group_id` bigint(20) DEFAULT NULL,
|
||||||
`product_id` bigint(20) DEFAULT NULL,
|
`product_id` bigint(20) DEFAULT NULL,
|
||||||
|
`status_enum` SMALLINT(5) NOT NULL DEFAULT 300,
|
||||||
|
`activation_date` DATE DEFAULT NULL,
|
||||||
`currency_code` varchar(3) NOT NULL,
|
`currency_code` varchar(3) NOT NULL,
|
||||||
`currency_digits` smallint(5) NOT NULL,
|
`currency_digits` smallint(5) NOT NULL,
|
||||||
`nominal_interest_rate_per_period` decimal(19,6) NOT NULL,
|
`nominal_interest_rate_per_period` decimal(19,6) NOT NULL,
|
||||||
@@ -744,6 +747,7 @@ CREATE TABLE `m_savings_account` (
|
|||||||
`min_required_opening_balance` decimal(19,6) DEFAULT NULL,
|
`min_required_opening_balance` decimal(19,6) DEFAULT NULL,
|
||||||
`lockin_period_frequency` decimal(19,6) DEFAULT NULL,
|
`lockin_period_frequency` decimal(19,6) DEFAULT NULL,
|
||||||
`lockin_period_frequency_enum` smallint(5) DEFAULT NULL,
|
`lockin_period_frequency_enum` smallint(5) DEFAULT NULL,
|
||||||
|
`lockedin_until_date_derived` DATE DEFAULT NULL,
|
||||||
`total_deposits_derived` decimal(19,6) DEFAULT NULL,
|
`total_deposits_derived` decimal(19,6) DEFAULT NULL,
|
||||||
`total_withdrawals_derived` decimal(19,6) DEFAULT NULL,
|
`total_withdrawals_derived` decimal(19,6) DEFAULT NULL,
|
||||||
`total_interest_posted_derived` decimal(19,6) DEFAULT NULL,
|
`total_interest_posted_derived` decimal(19,6) DEFAULT NULL,
|
||||||
|
|||||||
@@ -17,19 +17,36 @@ INSERT INTO `r_enum_value`
|
|||||||
VALUES
|
VALUES
|
||||||
('amortization_method_enum',0,'Equal principle payments','Equal principle payments'),
|
('amortization_method_enum',0,'Equal principle payments','Equal principle payments'),
|
||||||
('amortization_method_enum',1,'Equal installments','Equal installments'),
|
('amortization_method_enum',1,'Equal installments','Equal installments'),
|
||||||
('interest_calculated_in_period_enum',0,'Daily','Daily'),('interest_calculated_in_period_enum',1,'Same as repayment period','Same as repayment period'),
|
('interest_calculated_in_period_enum',0,'Daily','Daily'),
|
||||||
('interest_method_enum',0,'Declining Balance','Declining Balance'),('interest_method_enum',1,'Flat','Flat'),
|
('interest_calculated_in_period_enum',1,'Same as repayment period','Same as repayment period'),
|
||||||
('interest_period_frequency_enum',2,'Per month','Per month'),('interest_period_frequency_enum',3,'Per year','Per year'),
|
('interest_method_enum',0,'Declining Balance','Declining Balance'),
|
||||||
('loan_status_id',100,'Submitted and awaiting approval','Submitted and awaiting approval'),('loan_status_id',200,'Approved','Approved'),
|
('interest_method_enum',1,'Flat','Flat'),
|
||||||
('loan_status_id',300,'Active','Active'),('loan_status_id',400,'Withdrawn by client','Withdrawn by client'),('loan_status_id',500,'Rejected','Rejected'),
|
('interest_period_frequency_enum',2,'Per month','Per month'),
|
||||||
('loan_status_id',600,'Closed','Closed'),('loan_status_id',601,'Written-Off','Written-Off'),('loan_status_id',602,'Rescheduled','Rescheduled'),('loan_status_id',700,'Overpaid','Overpaid'),
|
('interest_period_frequency_enum',3,'Per year','Per year'),
|
||||||
('loan_transaction_strategy_id',1,'mifos-standard-strategy','Mifos style'),('loan_transaction_strategy_id',2,'heavensfamily-strategy','Heavensfamily'),
|
('loan_status_id',100,'Submitted and awaiting approval','Submitted and awaiting approval'),
|
||||||
('loan_transaction_strategy_id',3,'creocore-strategy','Creocore'),('loan_transaction_strategy_id',4,'rbi-india-strategy','RBI (India)'),
|
('loan_status_id',200,'Approved','Approved'),
|
||||||
('processing_result_enum',0,'invalid','Invalid'),('processing_result_enum',1,'processed','Processed'),
|
('loan_status_id',300,'Active','Active'),
|
||||||
('processing_result_enum',2,'awaiting.approval','Awaiting Approval'),('processing_result_enum',3,'rejected','Rejected'),
|
('loan_status_id',400,'Withdrawn by client','Withdrawn by client'),
|
||||||
('repayment_period_frequency_enum',0,'Days','Days'),('repayment_period_frequency_enum',1,'Weeks','Weeks'),
|
('loan_status_id',500,'Rejected','Rejected'),
|
||||||
('repayment_period_frequency_enum',2,'Months','Months'),('term_period_frequency_enum',0,'Days','Days'),
|
('loan_status_id',600,'Closed','Closed'),
|
||||||
('term_period_frequency_enum',1,'Weeks','Weeks'),('term_period_frequency_enum',2,'Months','Months'),('term_period_frequency_enum',3,'Years','Years');
|
('loan_status_id',601,'Written-Off','Written-Off'),
|
||||||
|
('loan_status_id',602,'Rescheduled','Rescheduled'),
|
||||||
|
('loan_status_id',700,'Overpaid','Overpaid'),
|
||||||
|
('loan_transaction_strategy_id',1,'mifos-standard-strategy','Mifos style'),
|
||||||
|
('loan_transaction_strategy_id',2,'heavensfamily-strategy','Heavensfamily'),
|
||||||
|
('loan_transaction_strategy_id',3,'creocore-strategy','Creocore'),
|
||||||
|
('loan_transaction_strategy_id',4,'rbi-india-strategy','RBI (India)'),
|
||||||
|
('processing_result_enum',0,'invalid','Invalid'),
|
||||||
|
('processing_result_enum',1,'processed','Processed'),
|
||||||
|
('processing_result_enum',2,'awaiting.approval','Awaiting Approval'),
|
||||||
|
('processing_result_enum',3,'rejected','Rejected'),
|
||||||
|
('repayment_period_frequency_enum',0,'Days','Days'),
|
||||||
|
('repayment_period_frequency_enum',1,'Weeks','Weeks'),
|
||||||
|
('repayment_period_frequency_enum',2,'Months','Months'),
|
||||||
|
('term_period_frequency_enum',0,'Days','Days'),
|
||||||
|
('term_period_frequency_enum',1,'Weeks','Weeks'),
|
||||||
|
('term_period_frequency_enum',2,'Months','Months'),
|
||||||
|
('term_period_frequency_enum',3,'Years','Years');
|
||||||
|
|
||||||
INSERT INTO `r_enum_value` (`enum_name`, `enum_id`, `enum_message_property`, `enum_value`)
|
INSERT INTO `r_enum_value` (`enum_name`, `enum_id`, `enum_message_property`, `enum_value`)
|
||||||
VALUES ('transaction_type_enum', '1', 'Disbursement', 'Disbursement');
|
VALUES ('transaction_type_enum', '1', 'Disbursement', 'Disbursement');
|
||||||
@@ -64,7 +81,6 @@ VALUES ('transaction_type_enum', '10', 'Apply Charges', 'Apply Charges');
|
|||||||
INSERT INTO `r_enum_value` (`enum_name`, `enum_id`, `enum_message_property`, `enum_value`)
|
INSERT INTO `r_enum_value` (`enum_name`, `enum_id`, `enum_message_property`, `enum_value`)
|
||||||
VALUES ('transaction_type_enum', '11', 'Apply Interest', 'Apply Interest');
|
VALUES ('transaction_type_enum', '11', 'Apply Interest', 'Apply Interest');
|
||||||
|
|
||||||
|
|
||||||
INSERT INTO `m_currency`
|
INSERT INTO `m_currency`
|
||||||
(`id`,`code`,`decimal_places`,`display_symbol`,`name`, `internationalized_name_code`)
|
(`id`,`code`,`decimal_places`,`display_symbol`,`name`, `internationalized_name_code`)
|
||||||
VALUES
|
VALUES
|
||||||
|
|||||||
@@ -263,7 +263,9 @@ INSERT INTO `m_permission`
|
|||||||
('transaction_savings', 'DEPOSIT_SAVINGSACCOUNT', 'SAVINGSACCOUNT', 'DEPOSIT', '1'),
|
('transaction_savings', 'DEPOSIT_SAVINGSACCOUNT', 'SAVINGSACCOUNT', 'DEPOSIT', '1'),
|
||||||
('transaction_savings', 'DEPOSIT_SAVINGSACCOUNT_CHECKER', 'SAVINGSACCOUNT', 'DEPOSIT', '0'),
|
('transaction_savings', 'DEPOSIT_SAVINGSACCOUNT_CHECKER', 'SAVINGSACCOUNT', 'DEPOSIT', '0'),
|
||||||
('transaction_savings', 'WITHDRAWAL_SAVINGSACCOUNT', 'SAVINGSACCOUNT', 'WITHDRAWAL', '1'),
|
('transaction_savings', 'WITHDRAWAL_SAVINGSACCOUNT', 'SAVINGSACCOUNT', 'WITHDRAWAL', '1'),
|
||||||
('transaction_savings', 'WITHDRAWAL_SAVINGSACCOUNT_CHECKER', 'SAVINGSACCOUNT', 'WITHDRAWAL', '0');
|
('transaction_savings', 'WITHDRAWAL_SAVINGSACCOUNT_CHECKER', 'SAVINGSACCOUNT', 'WITHDRAWAL', '0'),
|
||||||
|
('transaction_savings', 'ACTIVATE_SAVINGSACCOUNT', 'SAVINGSACCOUNT', 'ACTIVATE', '1'),
|
||||||
|
('transaction_savings', 'ACTIVATE_SAVINGSACCOUNT_CHECKER', 'SAVINGSACCOUNT', 'ACTIVATE', '0');
|
||||||
|
|
||||||
-- == accounting related permissions
|
-- == accounting related permissions
|
||||||
INSERT INTO `m_permission` (`grouping`, `code`, `entity_name`, `action_name`, `can_maker_checker`) VALUES
|
INSERT INTO `m_permission` (`grouping`, `code`, `entity_name`, `action_name`, `can_maker_checker`) VALUES
|
||||||
|
|||||||
@@ -0,0 +1,16 @@
|
|||||||
|
ALTER TABLE `m_savings_account`
|
||||||
|
ADD COLUMN `status_enum` SMALLINT(5) NOT NULL DEFAULT 300 AFTER `product_id` ;
|
||||||
|
|
||||||
|
ALTER TABLE `m_savings_account`
|
||||||
|
ADD COLUMN `activation_date` DATE DEFAULT NULL AFTER `status_enum`;
|
||||||
|
|
||||||
|
ALTER TABLE `m_savings_account`
|
||||||
|
ADD COLUMN `lockedin_until_date_derived` DATE DEFAULT NULL AFTER `lockin_period_frequency_enum`;
|
||||||
|
|
||||||
|
ALTER TABLE `m_portfolio_command_source`
|
||||||
|
ADD COLUMN `savings_id` BIGINT(20) NULL DEFAULT NULL AFTER `loan_id` ;
|
||||||
|
|
||||||
|
INSERT INTO `m_permission` (`grouping`, `code`, `entity_name`, `action_name`, `can_maker_checker`)
|
||||||
|
VALUES
|
||||||
|
('transaction_savings', 'ACTIVATE_SAVINGSACCOUNT', 'SAVINGSACCOUNT', 'ACTIVATE', '1'),
|
||||||
|
('transaction_savings', 'ACTIVATE_SAVINGSACCOUNT_CHECKER', 'SAVINGSACCOUNT', 'ACTIVATE', '0');
|
||||||
@@ -1,4 +1,17 @@
|
|||||||
|
|
||||||
|
import static com.jayway.restassured.RestAssured.given;
|
||||||
|
import static com.jayway.restassured.RestAssured.post;
|
||||||
|
import static com.jayway.restassured.path.json.JsonPath.from;
|
||||||
|
import static junit.framework.Assert.assertEquals;
|
||||||
|
|
||||||
|
import java.util.ArrayList;
|
||||||
|
import java.util.Arrays;
|
||||||
|
import java.util.HashMap;
|
||||||
|
import java.util.Random;
|
||||||
|
|
||||||
|
import org.junit.Before;
|
||||||
|
import org.junit.Test;
|
||||||
|
|
||||||
import com.google.gson.Gson;
|
import com.google.gson.Gson;
|
||||||
import com.jayway.restassured.builder.RequestSpecBuilder;
|
import com.jayway.restassured.builder.RequestSpecBuilder;
|
||||||
import com.jayway.restassured.builder.ResponseSpecBuilder;
|
import com.jayway.restassured.builder.ResponseSpecBuilder;
|
||||||
@@ -6,22 +19,11 @@ import com.jayway.restassured.http.ContentType;
|
|||||||
import com.jayway.restassured.path.json.JsonPath;
|
import com.jayway.restassured.path.json.JsonPath;
|
||||||
import com.jayway.restassured.specification.RequestSpecification;
|
import com.jayway.restassured.specification.RequestSpecification;
|
||||||
import com.jayway.restassured.specification.ResponseSpecification;
|
import com.jayway.restassured.specification.ResponseSpecification;
|
||||||
import org.junit.Before;
|
|
||||||
import org.junit.Test;
|
|
||||||
|
|
||||||
import java.util.ArrayList;
|
|
||||||
import java.util.Arrays;
|
|
||||||
import java.util.HashMap;
|
|
||||||
import java.util.Random;
|
|
||||||
|
|
||||||
import static com.jayway.restassured.RestAssured.given;
|
|
||||||
import static com.jayway.restassured.RestAssured.post;
|
|
||||||
import static com.jayway.restassured.path.json.JsonPath.from;
|
|
||||||
import static junit.framework.Assert.assertEquals;
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Client Loan Integration Test for checking Loan Application Repayment Schedule.
|
* Client Loan Integration Test for checking Loan Application Repayment Schedule.
|
||||||
*/
|
*/
|
||||||
|
@SuppressWarnings({ "rawtypes", "unchecked" })
|
||||||
public class ClientLoanIntegrationTest {
|
public class ClientLoanIntegrationTest {
|
||||||
String basicAuthKey;
|
String basicAuthKey;
|
||||||
ResponseSpecification responseSpec;
|
ResponseSpecification responseSpec;
|
||||||
@@ -70,7 +72,7 @@ public class ClientLoanIntegrationTest {
|
|||||||
return from(json).get("clientId");
|
return from(json).get("clientId");
|
||||||
}
|
}
|
||||||
|
|
||||||
private void checkClientCreatedOnServer(Integer generatedClientID) {
|
private void checkClientCreatedOnServer(final Integer generatedClientID) {
|
||||||
System.out.println("------------------------------CHECK CLIENT DETAILS------------------------------------\n");
|
System.out.println("------------------------------CHECK CLIENT DETAILS------------------------------------\n");
|
||||||
given().spec(requestSpec)
|
given().spec(requestSpec)
|
||||||
.expect().spec(responseSpec)
|
.expect().spec(responseSpec)
|
||||||
@@ -86,14 +88,14 @@ public class ClientLoanIntegrationTest {
|
|||||||
return from(json).get("resourceId");
|
return from(json).get("resourceId");
|
||||||
}
|
}
|
||||||
|
|
||||||
private void applyForLoanApplication(Integer clientID, Integer loanProductID) {
|
private void applyForLoanApplication(final Integer clientID, final Integer loanProductID) {
|
||||||
System.out.println("--------------------------------APPLYING FOR LOAN APPLICATION--------------------------------");
|
System.out.println("--------------------------------APPLYING FOR LOAN APPLICATION--------------------------------");
|
||||||
given().spec(requestSpec).body(getLoanApplicationBodyAsJSON(clientID.toString(), loanProductID.toString()))
|
given().spec(requestSpec).body(getLoanApplicationBodyAsJSON(clientID.toString(), loanProductID.toString()))
|
||||||
.expect().spec(responseSpec)
|
.expect().spec(responseSpec)
|
||||||
.when().post("/mifosng-provider/api/v1/loans?tenantIdentifier=default");
|
.when().post("/mifosng-provider/api/v1/loans?tenantIdentifier=default");
|
||||||
}
|
}
|
||||||
|
|
||||||
private ArrayList getLoanRepaymentSchedule(Integer productID)
|
private ArrayList getLoanRepaymentSchedule(final Integer productID)
|
||||||
{
|
{
|
||||||
System.out.println("---------------------------GETTING LOAN REPAYMENT SCHEDULE--------------------------------");
|
System.out.println("---------------------------GETTING LOAN REPAYMENT SCHEDULE--------------------------------");
|
||||||
String json = given().spec(requestSpec).body(getLoanCalculationBodyAsJSON(productID.toString()))
|
String json = given().spec(requestSpec).body(getLoanCalculationBodyAsJSON(productID.toString()))
|
||||||
@@ -102,7 +104,7 @@ public class ClientLoanIntegrationTest {
|
|||||||
return from(json).get("periods");
|
return from(json).get("periods");
|
||||||
}
|
}
|
||||||
|
|
||||||
private void verifyLoanRepaymentSchedule(ArrayList<HashMap> loanSchedule) {
|
private void verifyLoanRepaymentSchedule(final ArrayList<HashMap> loanSchedule) {
|
||||||
System.out.println("--------------------VERIFYING THE PRINCIPAL DUES,INTEREST DUE AND DUE DATE--------------------------");
|
System.out.println("--------------------VERIFYING THE PRINCIPAL DUES,INTEREST DUE AND DUE DATE--------------------------");
|
||||||
|
|
||||||
assertEquals("Checking for Due Date for 1st Month",new ArrayList<Integer>(Arrays.asList(2011, 10, 20)),loanSchedule.get(1).get("dueDate"));
|
assertEquals("Checking for Due Date for 1st Month",new ArrayList<Integer>(Arrays.asList(2011, 10, 20)),loanSchedule.get(1).get("dueDate"));
|
||||||
@@ -156,7 +158,7 @@ public class ClientLoanIntegrationTest {
|
|||||||
return new Gson().toJson(map);
|
return new Gson().toJson(map);
|
||||||
}
|
}
|
||||||
|
|
||||||
private String getLoanApplicationBodyAsJSON(String clientID,String productID){
|
private String getLoanApplicationBodyAsJSON(final String clientID,final String productID){
|
||||||
HashMap<String, String> map = new HashMap<String, String>();
|
HashMap<String, String> map = new HashMap<String, String>();
|
||||||
map.put("dateFormat", "dd MMMM yyyy");
|
map.put("dateFormat", "dd MMMM yyyy");
|
||||||
map.put("locale", "en_GB");
|
map.put("locale", "en_GB");
|
||||||
@@ -179,7 +181,7 @@ public class ClientLoanIntegrationTest {
|
|||||||
return new Gson().toJson(map);
|
return new Gson().toJson(map);
|
||||||
}
|
}
|
||||||
|
|
||||||
private String getLoanCalculationBodyAsJSON(String productID){
|
private String getLoanCalculationBodyAsJSON(final String productID){
|
||||||
HashMap<String, String> map = new HashMap<String, String>();
|
HashMap<String, String> map = new HashMap<String, String>();
|
||||||
map.put("dateFormat", "dd MMMM yyyy");
|
map.put("dateFormat", "dd MMMM yyyy");
|
||||||
map.put("locale", "en_GB");
|
map.put("locale", "en_GB");
|
||||||
@@ -200,15 +202,15 @@ public class ClientLoanIntegrationTest {
|
|||||||
return new Gson().toJson(map);
|
return new Gson().toJson(map);
|
||||||
}
|
}
|
||||||
|
|
||||||
public String randomIDGenerator(String prefix, int lenOfRandomSuffix) {
|
public String randomIDGenerator(final String prefix, final int lenOfRandomSuffix) {
|
||||||
return randomStringGenerator(prefix,lenOfRandomSuffix, "ABCDEFGHIJKLMNOPQRSTUVWXYZ");
|
return randomStringGenerator(prefix,lenOfRandomSuffix, "ABCDEFGHIJKLMNOPQRSTUVWXYZ");
|
||||||
}
|
}
|
||||||
|
|
||||||
public String randomNameGenerator(String prefix, int lenOfRandomSuffix) {
|
public String randomNameGenerator(final String prefix, final int lenOfRandomSuffix) {
|
||||||
return randomStringGenerator(prefix,lenOfRandomSuffix, "0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ");
|
return randomStringGenerator(prefix,lenOfRandomSuffix, "0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ");
|
||||||
}
|
}
|
||||||
|
|
||||||
private String randomStringGenerator(String prefix,int len, String sourceSetString) {
|
private String randomStringGenerator(final String prefix,final int len, final String sourceSetString) {
|
||||||
int lengthOfSource = sourceSetString.length();
|
int lengthOfSource = sourceSetString.length();
|
||||||
Random rnd = new Random();
|
Random rnd = new Random();
|
||||||
StringBuilder sb = new StringBuilder(len);
|
StringBuilder sb = new StringBuilder(len);
|
||||||
|
|||||||
@@ -47,6 +47,10 @@ public class CommandSource extends AbstractPersistable<Long> {
|
|||||||
@Column(name = "loan_id")
|
@Column(name = "loan_id")
|
||||||
private Long loanId;
|
private Long loanId;
|
||||||
|
|
||||||
|
@SuppressWarnings("unused")
|
||||||
|
@Column(name = "savings_id")
|
||||||
|
private Long savingsId;
|
||||||
|
|
||||||
@Column(name = "api_get_url", length = 100)
|
@Column(name = "api_get_url", length = 100)
|
||||||
private String resourceGetUrl;
|
private String resourceGetUrl;
|
||||||
|
|
||||||
@@ -165,11 +169,12 @@ public class CommandSource extends AbstractPersistable<Long> {
|
|||||||
this.processingResult = CommandProcessingResultType.AWAITING_APPROVAL.getValue();
|
this.processingResult = CommandProcessingResultType.AWAITING_APPROVAL.getValue();
|
||||||
}
|
}
|
||||||
|
|
||||||
public void updateForAudit(final Long officeId, final Long groupId, final Long clientId, final Long loanId) {
|
public void updateForAudit(final Long officeId, final Long groupId, final Long clientId, final Long loanId, final Long savignsId) {
|
||||||
this.officeId = officeId;
|
this.officeId = officeId;
|
||||||
this.groupId = groupId;
|
this.groupId = groupId;
|
||||||
this.clientId = clientId;
|
this.clientId = clientId;
|
||||||
this.loanId = loanId;
|
this.loanId = loanId;
|
||||||
|
this.savingsId = savignsId;
|
||||||
}
|
}
|
||||||
|
|
||||||
public String getResourceGetUrl() {
|
public String getResourceGetUrl() {
|
||||||
|
|||||||
+12
-10
@@ -31,12 +31,12 @@ public class CommandWrapper {
|
|||||||
}
|
}
|
||||||
|
|
||||||
public static CommandWrapper fromExistingCommand(final Long commandId, final String actionName, final String entityName,
|
public static CommandWrapper fromExistingCommand(final Long commandId, final String actionName, final String entityName,
|
||||||
final Long resourceId, final Long subresourceId, final String resourceGetUrl) {
|
final Long resourceId, final Long subresourceId, final String resourceGetUrl) {
|
||||||
return new CommandWrapper(commandId, actionName, entityName, resourceId, subresourceId, resourceGetUrl);
|
return new CommandWrapper(commandId, actionName, entityName, resourceId, subresourceId, resourceGetUrl);
|
||||||
}
|
}
|
||||||
|
|
||||||
private CommandWrapper(final Long commandId, final String actionName, final String entityName, final Long resourceId, final Long subresourceId,
|
private CommandWrapper(final Long commandId, final String actionName, final String entityName, final Long resourceId,
|
||||||
final String resourceGetUrl) {
|
final Long subresourceId, final String resourceGetUrl) {
|
||||||
this.commandId = commandId;
|
this.commandId = commandId;
|
||||||
this.officeId = null;
|
this.officeId = null;
|
||||||
this.groupId = null;
|
this.groupId = null;
|
||||||
@@ -58,9 +58,8 @@ public class CommandWrapper {
|
|||||||
}
|
}
|
||||||
|
|
||||||
public CommandWrapper(final Long officeId, final Long groupId, final Long clientId, final Long loanId, final Long savingsId,
|
public CommandWrapper(final Long officeId, final Long groupId, final Long clientId, final Long loanId, final Long savingsId,
|
||||||
final String actionName, final String entityName, final Long entityId, final Long subentityId,
|
final String actionName, final String entityName, final Long entityId, final Long subentityId, final Long codeId,
|
||||||
final Long codeId, final String supportedEntityType, final Long supportedEntityId, final String href, final String json,
|
final String supportedEntityType, final Long supportedEntityId, final String href, final String json, final String transactionId) {
|
||||||
final String transactionId) {
|
|
||||||
this.commandId = null;
|
this.commandId = null;
|
||||||
this.officeId = officeId;
|
this.officeId = officeId;
|
||||||
this.groupId = groupId;
|
this.groupId = groupId;
|
||||||
@@ -359,7 +358,7 @@ public class CommandWrapper {
|
|||||||
}
|
}
|
||||||
|
|
||||||
public boolean isDeleteOneToOne() {
|
public boolean isDeleteOneToOne() {
|
||||||
/* also covers case of deleting all of a one to many*/
|
/* also covers case of deleting all of a one to many */
|
||||||
return isDatatableResource() && isDeleteOperation() && this.subentityId == null;
|
return isDatatableResource() && isDeleteOperation() && this.subentityId == null;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -431,6 +430,10 @@ public class CommandWrapper {
|
|||||||
return this.entityName.equalsIgnoreCase("SAVINGSACCOUNT");
|
return this.entityName.equalsIgnoreCase("SAVINGSACCOUNT");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public boolean isSavingsAccountActivation() {
|
||||||
|
return this.actionName.equalsIgnoreCase("ACTIVATE") && this.entityName.equalsIgnoreCase("SAVINGSACCOUNT");
|
||||||
|
}
|
||||||
|
|
||||||
public boolean isSavingsAccountDeposit() {
|
public boolean isSavingsAccountDeposit() {
|
||||||
return this.actionName.equalsIgnoreCase("DEPOSIT") && this.entityName.equalsIgnoreCase("SAVINGSACCOUNT");
|
return this.actionName.equalsIgnoreCase("DEPOSIT") && this.entityName.equalsIgnoreCase("SAVINGSACCOUNT");
|
||||||
}
|
}
|
||||||
@@ -446,8 +449,8 @@ public class CommandWrapper {
|
|||||||
public boolean isNoteResource() {
|
public boolean isNoteResource() {
|
||||||
boolean isnoteResource = false;
|
boolean isnoteResource = false;
|
||||||
if (this.entityName.equalsIgnoreCase("CLIENTNOTE") || this.entityName.equalsIgnoreCase("LOANNOTE")
|
if (this.entityName.equalsIgnoreCase("CLIENTNOTE") || this.entityName.equalsIgnoreCase("LOANNOTE")
|
||||||
|| this.entityName.equalsIgnoreCase("LOANTRANSACTIONNOTE") || this.entityName.equalsIgnoreCase("DEPOSITNOTE")
|
|| this.entityName.equalsIgnoreCase("LOANTRANSACTIONNOTE") || this.entityName.equalsIgnoreCase("SAVINGNOTE")
|
||||||
|| this.entityName.equalsIgnoreCase("SAVINGNOTE") || this.entityName.equalsIgnoreCase("GROUPNOTE")) {
|
|| this.entityName.equalsIgnoreCase("GROUPNOTE")) {
|
||||||
isnoteResource = true;
|
isnoteResource = true;
|
||||||
}
|
}
|
||||||
return isnoteResource;
|
return isnoteResource;
|
||||||
@@ -456,5 +459,4 @@ public class CommandWrapper {
|
|||||||
public boolean isGroupResource() {
|
public boolean isGroupResource() {
|
||||||
return this.entityName.equalsIgnoreCase("GROUP");
|
return this.entityName.equalsIgnoreCase("GROUP");
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
+11
-2
@@ -686,10 +686,19 @@ public class CommandWrapperBuilder {
|
|||||||
return this;
|
return this;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public CommandWrapperBuilder savingsAccountActivation(final Long accountId) {
|
||||||
|
this.actionName = "ACTIVATE";
|
||||||
|
this.entityName = "SAVINGSACCOUNT";
|
||||||
|
this.savingsId = accountId;
|
||||||
|
this.entityId = null;
|
||||||
|
this.href = "/savingsaccounts/" + accountId + "?command=activate";
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
|
||||||
public CommandWrapperBuilder savingsAccountDeposit(final Long accountId) {
|
public CommandWrapperBuilder savingsAccountDeposit(final Long accountId) {
|
||||||
this.actionName = "DEPOSIT";
|
this.actionName = "DEPOSIT";
|
||||||
this.entityName = "SAVINGSACCOUNT";
|
this.entityName = "SAVINGSACCOUNT";
|
||||||
this.loanId = accountId;
|
this.savingsId = accountId;
|
||||||
this.entityId = null;
|
this.entityId = null;
|
||||||
this.href = "/savingsaccounts/" + accountId + "/transactions";
|
this.href = "/savingsaccounts/" + accountId + "/transactions";
|
||||||
return this;
|
return this;
|
||||||
@@ -698,7 +707,7 @@ public class CommandWrapperBuilder {
|
|||||||
public CommandWrapperBuilder savingsAccountWithdrawal(final Long accountId) {
|
public CommandWrapperBuilder savingsAccountWithdrawal(final Long accountId) {
|
||||||
this.actionName = "WITHDRAWAL";
|
this.actionName = "WITHDRAWAL";
|
||||||
this.entityName = "SAVINGSACCOUNT";
|
this.entityName = "SAVINGSACCOUNT";
|
||||||
this.loanId = accountId;
|
this.savingsId = accountId;
|
||||||
this.entityId = null;
|
this.entityId = null;
|
||||||
this.href = "/savingsaccounts/" + accountId + "/transactions";
|
this.href = "/savingsaccounts/" + accountId + "/transactions";
|
||||||
return this;
|
return this;
|
||||||
|
|||||||
+4
-1
@@ -69,7 +69,8 @@ public class SynchronousCommandProcessingService implements CommandProcessingSer
|
|||||||
commandSourceResult = CommandSource.fullEntryFrom(wrapper, command, maker);
|
commandSourceResult = CommandSource.fullEntryFrom(wrapper, command, maker);
|
||||||
}
|
}
|
||||||
commandSourceResult.updateResourceId(result.resourceId());
|
commandSourceResult.updateResourceId(result.resourceId());
|
||||||
commandSourceResult.updateForAudit(result.getOfficeId(), result.getGroupId(), result.getClientId(), result.getLoanId());
|
commandSourceResult.updateForAudit(result.getOfficeId(), result.getGroupId(), result.getClientId(), result.getLoanId(),
|
||||||
|
result.getSavingsId());
|
||||||
|
|
||||||
String changesOnlyJson = null;
|
String changesOnlyJson = null;
|
||||||
if (result.hasChanges()) {
|
if (result.hasChanges()) {
|
||||||
@@ -360,6 +361,8 @@ public class SynchronousCommandProcessingService implements CommandProcessingSer
|
|||||||
handler = applicationContext.getBean("depositSavingsAccountCommandHandler", NewCommandSourceHandler.class);
|
handler = applicationContext.getBean("depositSavingsAccountCommandHandler", NewCommandSourceHandler.class);
|
||||||
} else if (wrapper.isSavingsAccountWithdrawal()) {
|
} else if (wrapper.isSavingsAccountWithdrawal()) {
|
||||||
handler = applicationContext.getBean("withdrawSavingsAccountCommandHandler", NewCommandSourceHandler.class);
|
handler = applicationContext.getBean("withdrawSavingsAccountCommandHandler", NewCommandSourceHandler.class);
|
||||||
|
} else if (wrapper.isSavingsAccountActivation()) {
|
||||||
|
handler = applicationContext.getBean("activateSavingsAccountCommandHandler", NewCommandSourceHandler.class);
|
||||||
} else {
|
} else {
|
||||||
throw new UnsupportedCommandException(wrapper.commandName());
|
throw new UnsupportedCommandException(wrapper.commandName());
|
||||||
}
|
}
|
||||||
|
|||||||
+5
@@ -8,6 +8,7 @@ package org.mifosplatform.infrastructure.core.api;
|
|||||||
import java.math.BigDecimal;
|
import java.math.BigDecimal;
|
||||||
import java.util.Arrays;
|
import java.util.Arrays;
|
||||||
import java.util.Date;
|
import java.util.Date;
|
||||||
|
import java.util.Locale;
|
||||||
|
|
||||||
import org.apache.commons.lang.ObjectUtils;
|
import org.apache.commons.lang.ObjectUtils;
|
||||||
import org.apache.commons.lang.StringUtils;
|
import org.apache.commons.lang.StringUtils;
|
||||||
@@ -377,4 +378,8 @@ public final class JsonCommand {
|
|||||||
final PlatformUser dummyPlatformUser = new BasicPasswordEncodablePlatformUser(saltValue, "", passwordPlainText);
|
final PlatformUser dummyPlatformUser = new BasicPasswordEncodablePlatformUser(saltValue, "", passwordPlainText);
|
||||||
return platformPasswordEncoder.encode(dummyPlatformUser);
|
return platformPasswordEncoder.encode(dummyPlatformUser);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public Locale extractLocale() {
|
||||||
|
return this.fromApiJsonHelper.extractLocaleParameter(this.parsedCommand.getAsJsonObject());
|
||||||
|
}
|
||||||
}
|
}
|
||||||
-22
@@ -22,12 +22,6 @@ public class ApiGlobalErrorResponse {
|
|||||||
*/
|
*/
|
||||||
private String developerMessage;
|
private String developerMessage;
|
||||||
|
|
||||||
/**
|
|
||||||
* A link to a URL which provides more information on the details of this
|
|
||||||
* type of error.
|
|
||||||
*/
|
|
||||||
private String developerDocLink;
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* The HTTP status code of the response.
|
* The HTTP status code of the response.
|
||||||
*/
|
*/
|
||||||
@@ -57,7 +51,6 @@ public class ApiGlobalErrorResponse {
|
|||||||
ApiGlobalErrorResponse globalErrorResponse = new ApiGlobalErrorResponse();
|
ApiGlobalErrorResponse globalErrorResponse = new ApiGlobalErrorResponse();
|
||||||
globalErrorResponse.setHttpStatusCode("401");
|
globalErrorResponse.setHttpStatusCode("401");
|
||||||
globalErrorResponse.setDeveloperMessage("Invalid authentication details were passed in api request.");
|
globalErrorResponse.setDeveloperMessage("Invalid authentication details were passed in api request.");
|
||||||
globalErrorResponse.setDeveloperDocLink("https://github.com/keithwoodlock/mifosx/wiki/HTTP-API-Error-codes");
|
|
||||||
globalErrorResponse.setUserMessageGlobalisationCode("error.msg.not.authenticated");
|
globalErrorResponse.setUserMessageGlobalisationCode("error.msg.not.authenticated");
|
||||||
globalErrorResponse.setDefaultUserMessage("Unauthenticated. Please login.");
|
globalErrorResponse.setDefaultUserMessage("Unauthenticated. Please login.");
|
||||||
|
|
||||||
@@ -69,7 +62,6 @@ public class ApiGlobalErrorResponse {
|
|||||||
ApiGlobalErrorResponse globalErrorResponse = new ApiGlobalErrorResponse();
|
ApiGlobalErrorResponse globalErrorResponse = new ApiGlobalErrorResponse();
|
||||||
globalErrorResponse.setHttpStatusCode("401");
|
globalErrorResponse.setHttpStatusCode("401");
|
||||||
globalErrorResponse.setDeveloperMessage("Invalid tenant details were passed in api request.");
|
globalErrorResponse.setDeveloperMessage("Invalid tenant details were passed in api request.");
|
||||||
globalErrorResponse.setDeveloperDocLink("https://github.com/keithwoodlock/mifosx/wiki/HTTP-API-Error-codes");
|
|
||||||
globalErrorResponse.setUserMessageGlobalisationCode("error.msg.invalid.tenant.identifier");
|
globalErrorResponse.setUserMessageGlobalisationCode("error.msg.invalid.tenant.identifier");
|
||||||
globalErrorResponse.setDefaultUserMessage("Invalide tenant identifier provided with request.");
|
globalErrorResponse.setDefaultUserMessage("Invalide tenant identifier provided with request.");
|
||||||
|
|
||||||
@@ -81,7 +73,6 @@ public class ApiGlobalErrorResponse {
|
|||||||
globalErrorResponse.setHttpStatusCode("403");
|
globalErrorResponse.setHttpStatusCode("403");
|
||||||
globalErrorResponse
|
globalErrorResponse
|
||||||
.setDeveloperMessage("The user associated with credentials passed on this request does not have sufficient privileges to perform this action.");
|
.setDeveloperMessage("The user associated with credentials passed on this request does not have sufficient privileges to perform this action.");
|
||||||
globalErrorResponse.setDeveloperDocLink("https://github.com/keithwoodlock/mifosx/wiki/HTTP-API-Error-codes");
|
|
||||||
globalErrorResponse.setUserMessageGlobalisationCode("error.msg.not.authorized");
|
globalErrorResponse.setUserMessageGlobalisationCode("error.msg.not.authorized");
|
||||||
globalErrorResponse.setDefaultUserMessage("Insufficient privileges to perform this action.");
|
globalErrorResponse.setDefaultUserMessage("Insufficient privileges to perform this action.");
|
||||||
|
|
||||||
@@ -97,7 +88,6 @@ public class ApiGlobalErrorResponse {
|
|||||||
ApiGlobalErrorResponse globalErrorResponse = new ApiGlobalErrorResponse();
|
ApiGlobalErrorResponse globalErrorResponse = new ApiGlobalErrorResponse();
|
||||||
globalErrorResponse.setHttpStatusCode("403");
|
globalErrorResponse.setHttpStatusCode("403");
|
||||||
globalErrorResponse.setDeveloperMessage("Request was understood but caused a domain rule violation.");
|
globalErrorResponse.setDeveloperMessage("Request was understood but caused a domain rule violation.");
|
||||||
globalErrorResponse.setDeveloperDocLink("https://github.com/keithwoodlock/mifosx/wiki/HTTP-API-Error-codes");
|
|
||||||
globalErrorResponse.setUserMessageGlobalisationCode("validation.msg.domain.rule.violation");
|
globalErrorResponse.setUserMessageGlobalisationCode("validation.msg.domain.rule.violation");
|
||||||
globalErrorResponse.setDefaultUserMessage("Errors contain reason for domain rule violation.");
|
globalErrorResponse.setDefaultUserMessage("Errors contain reason for domain rule violation.");
|
||||||
|
|
||||||
@@ -114,7 +104,6 @@ public class ApiGlobalErrorResponse {
|
|||||||
ApiGlobalErrorResponse globalErrorResponse = new ApiGlobalErrorResponse();
|
ApiGlobalErrorResponse globalErrorResponse = new ApiGlobalErrorResponse();
|
||||||
globalErrorResponse.setHttpStatusCode("404");
|
globalErrorResponse.setHttpStatusCode("404");
|
||||||
globalErrorResponse.setDeveloperMessage("The requested resource is not available.");
|
globalErrorResponse.setDeveloperMessage("The requested resource is not available.");
|
||||||
globalErrorResponse.setDeveloperDocLink("https://github.com/keithwoodlock/mifosx/wiki/HTTP-API-Error-codes");
|
|
||||||
globalErrorResponse.setUserMessageGlobalisationCode("error.msg.resource.not.found");
|
globalErrorResponse.setUserMessageGlobalisationCode("error.msg.resource.not.found");
|
||||||
globalErrorResponse.setDefaultUserMessage("The requested resource is not available.");
|
globalErrorResponse.setDefaultUserMessage("The requested resource is not available.");
|
||||||
|
|
||||||
@@ -131,7 +120,6 @@ public class ApiGlobalErrorResponse {
|
|||||||
ApiGlobalErrorResponse globalErrorResponse = new ApiGlobalErrorResponse();
|
ApiGlobalErrorResponse globalErrorResponse = new ApiGlobalErrorResponse();
|
||||||
globalErrorResponse.setHttpStatusCode("403");
|
globalErrorResponse.setHttpStatusCode("403");
|
||||||
globalErrorResponse.setDeveloperMessage("The request caused a data integrity issue to be fired by the database.");
|
globalErrorResponse.setDeveloperMessage("The request caused a data integrity issue to be fired by the database.");
|
||||||
globalErrorResponse.setDeveloperDocLink("https://github.com/keithwoodlock/mifosx/wiki/HTTP-API-Error-codes");
|
|
||||||
globalErrorResponse.setUserMessageGlobalisationCode(globalisationMessageCode);
|
globalErrorResponse.setUserMessageGlobalisationCode(globalisationMessageCode);
|
||||||
globalErrorResponse.setDefaultUserMessage(defaultUserMessage);
|
globalErrorResponse.setDefaultUserMessage(defaultUserMessage);
|
||||||
|
|
||||||
@@ -149,7 +137,6 @@ public class ApiGlobalErrorResponse {
|
|||||||
globalErrorResponse.setHttpStatusCode("400");
|
globalErrorResponse.setHttpStatusCode("400");
|
||||||
globalErrorResponse
|
globalErrorResponse
|
||||||
.setDeveloperMessage("The request was invalid. This typically will happen due to validation errors which are provided.");
|
.setDeveloperMessage("The request was invalid. This typically will happen due to validation errors which are provided.");
|
||||||
globalErrorResponse.setDeveloperDocLink("https://github.com/keithwoodlock/mifosx/wiki/HTTP-API-Error-codes");
|
|
||||||
globalErrorResponse.setUserMessageGlobalisationCode(globalisationMessageCode);
|
globalErrorResponse.setUserMessageGlobalisationCode(globalisationMessageCode);
|
||||||
globalErrorResponse.setDefaultUserMessage(defaultUserMessage);
|
globalErrorResponse.setDefaultUserMessage(defaultUserMessage);
|
||||||
|
|
||||||
@@ -164,7 +151,6 @@ public class ApiGlobalErrorResponse {
|
|||||||
ApiGlobalErrorResponse globalErrorResponse = new ApiGlobalErrorResponse();
|
ApiGlobalErrorResponse globalErrorResponse = new ApiGlobalErrorResponse();
|
||||||
globalErrorResponse.setHttpStatusCode("500");
|
globalErrorResponse.setHttpStatusCode("500");
|
||||||
globalErrorResponse.setDeveloperMessage("An unexpected error occured on the platform server.");
|
globalErrorResponse.setDeveloperMessage("An unexpected error occured on the platform server.");
|
||||||
globalErrorResponse.setDeveloperDocLink("https://github.com/keithwoodlock/mifosx/wiki/HTTP-API-Error-codes");
|
|
||||||
globalErrorResponse.setUserMessageGlobalisationCode("error.msg.platform.server.side.error");
|
globalErrorResponse.setUserMessageGlobalisationCode("error.msg.platform.server.side.error");
|
||||||
globalErrorResponse.setDefaultUserMessage("An unexpected error occured on the platform server.");
|
globalErrorResponse.setDefaultUserMessage("An unexpected error occured on the platform server.");
|
||||||
|
|
||||||
@@ -224,12 +210,4 @@ public class ApiGlobalErrorResponse {
|
|||||||
public void setUserMessageGlobalisationCode(final String userMessageGlobalisationCode) {
|
public void setUserMessageGlobalisationCode(final String userMessageGlobalisationCode) {
|
||||||
this.userMessageGlobalisationCode = userMessageGlobalisationCode;
|
this.userMessageGlobalisationCode = userMessageGlobalisationCode;
|
||||||
}
|
}
|
||||||
|
|
||||||
public String getDeveloperDocLink() {
|
|
||||||
return developerDocLink;
|
|
||||||
}
|
|
||||||
|
|
||||||
public void setDeveloperDocLink(final String developerDocLink) {
|
|
||||||
this.developerDocLink = developerDocLink;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
+10
-1
@@ -9,14 +9,23 @@ import java.util.List;
|
|||||||
|
|
||||||
import org.mifosplatform.infrastructure.core.data.ApiParameterError;
|
import org.mifosplatform.infrastructure.core.data.ApiParameterError;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Exception thrown when problem with an API request to the platform.
|
||||||
|
*/
|
||||||
public class PlatformApiDataValidationException extends RuntimeException {
|
public class PlatformApiDataValidationException extends RuntimeException {
|
||||||
|
|
||||||
private final String globalisationMessageCode;
|
private final String globalisationMessageCode;
|
||||||
private final String defaultUserMessage;
|
private final String defaultUserMessage;
|
||||||
private final List<ApiParameterError> errors;
|
private final List<ApiParameterError> errors;
|
||||||
|
|
||||||
|
public PlatformApiDataValidationException(final List<ApiParameterError> errors) {
|
||||||
|
this.globalisationMessageCode = "validation.msg.validation.errors.exist";
|
||||||
|
this.defaultUserMessage = "Validation errors exist.";
|
||||||
|
this.errors = errors;
|
||||||
|
}
|
||||||
|
|
||||||
public PlatformApiDataValidationException(final String globalisationMessageCode, final String defaultUserMessage,
|
public PlatformApiDataValidationException(final String globalisationMessageCode, final String defaultUserMessage,
|
||||||
List<ApiParameterError> errors) {
|
final List<ApiParameterError> errors) {
|
||||||
this.globalisationMessageCode = globalisationMessageCode;
|
this.globalisationMessageCode = globalisationMessageCode;
|
||||||
this.defaultUserMessage = defaultUserMessage;
|
this.defaultUserMessage = defaultUserMessage;
|
||||||
this.errors = errors;
|
this.errors = errors;
|
||||||
|
|||||||
+3
-3
@@ -29,11 +29,11 @@ import org.springframework.stereotype.Component;
|
|||||||
public class PlatformApiDataValidationExceptionMapper implements ExceptionMapper<PlatformApiDataValidationException> {
|
public class PlatformApiDataValidationExceptionMapper implements ExceptionMapper<PlatformApiDataValidationException> {
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public Response toResponse(PlatformApiDataValidationException exception) {
|
public Response toResponse(final PlatformApiDataValidationException exception) {
|
||||||
|
|
||||||
ApiGlobalErrorResponse dataIntegrityError = ApiGlobalErrorResponse.badClientRequest(exception.getGlobalisationMessageCode(),
|
final ApiGlobalErrorResponse dataValidationErrorResponse = ApiGlobalErrorResponse.badClientRequest(exception.getGlobalisationMessageCode(),
|
||||||
exception.getDefaultUserMessage(), exception.getErrors());
|
exception.getDefaultUserMessage(), exception.getErrors());
|
||||||
|
|
||||||
return Response.status(Status.BAD_REQUEST).entity(dataIntegrityError).type(MediaType.APPLICATION_JSON).build();
|
return Response.status(Status.BAD_REQUEST).entity(dataValidationErrorResponse).type(MediaType.APPLICATION_JSON).build();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
+4
-5
@@ -10,10 +10,9 @@ import org.mifosplatform.infrastructure.core.exception.AbstractPlatformDomainRul
|
|||||||
/**
|
/**
|
||||||
* Exception thrown when an attempt is made update the parent of a root office.
|
* Exception thrown when an attempt is made update the parent of a root office.
|
||||||
*/
|
*/
|
||||||
public class CannotUpdateOfficeWithParentOfficeSameAsSelf extends
|
public class CannotUpdateOfficeWithParentOfficeSameAsSelf extends AbstractPlatformDomainRuleException {
|
||||||
AbstractPlatformDomainRuleException {
|
|
||||||
|
|
||||||
public CannotUpdateOfficeWithParentOfficeSameAsSelf(final Long officeId, final Long parentId) {
|
public CannotUpdateOfficeWithParentOfficeSameAsSelf(final Long officeId, final Long parentId) {
|
||||||
super("error.msg.office.parentId.same.as.id", "Cannot update office with parent same as self.", officeId, parentId);
|
super("error.msg.office.parentId.same.as.id", "Cannot update office with parent same as self.", officeId, parentId);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
+4
-5
@@ -10,10 +10,9 @@ import org.mifosplatform.infrastructure.core.exception.AbstractPlatformDomainRul
|
|||||||
/**
|
/**
|
||||||
* Exception thrown when an attempt is made update the parent of a root office.
|
* Exception thrown when an attempt is made update the parent of a root office.
|
||||||
*/
|
*/
|
||||||
public class RootOfficeParentCannotBeUpdated extends
|
public class RootOfficeParentCannotBeUpdated extends AbstractPlatformDomainRuleException {
|
||||||
AbstractPlatformDomainRuleException {
|
|
||||||
|
|
||||||
public RootOfficeParentCannotBeUpdated() {
|
public RootOfficeParentCannotBeUpdated() {
|
||||||
super("error.msg.office.cannot.update.parent.office.of.root.office", "The root office must not be set with a parent office.");
|
super("error.msg.office.cannot.update.parent.office.of.root.office", "The root office must not be set with a parent office.");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
+15
-17
@@ -29,24 +29,22 @@ public enum PeriodFrequencyType {
|
|||||||
}
|
}
|
||||||
|
|
||||||
public static PeriodFrequencyType fromInt(final Integer frequency) {
|
public static PeriodFrequencyType fromInt(final Integer frequency) {
|
||||||
|
|
||||||
PeriodFrequencyType repaymentFrequencyType = PeriodFrequencyType.INVALID;
|
PeriodFrequencyType repaymentFrequencyType = PeriodFrequencyType.INVALID;
|
||||||
switch (frequency) {
|
if (frequency != null) {
|
||||||
case 0:
|
switch (frequency) {
|
||||||
repaymentFrequencyType = PeriodFrequencyType.DAYS;
|
case 0:
|
||||||
break;
|
repaymentFrequencyType = PeriodFrequencyType.DAYS;
|
||||||
case 1:
|
break;
|
||||||
repaymentFrequencyType = PeriodFrequencyType.WEEKS;
|
case 1:
|
||||||
break;
|
repaymentFrequencyType = PeriodFrequencyType.WEEKS;
|
||||||
case 2:
|
break;
|
||||||
repaymentFrequencyType = PeriodFrequencyType.MONTHS;
|
case 2:
|
||||||
break;
|
repaymentFrequencyType = PeriodFrequencyType.MONTHS;
|
||||||
case 3:
|
break;
|
||||||
repaymentFrequencyType = PeriodFrequencyType.YEARS;
|
case 3:
|
||||||
break;
|
repaymentFrequencyType = PeriodFrequencyType.YEARS;
|
||||||
default:
|
break;
|
||||||
repaymentFrequencyType = PeriodFrequencyType.INVALID;
|
}
|
||||||
break;
|
|
||||||
}
|
}
|
||||||
return repaymentFrequencyType;
|
return repaymentFrequencyType;
|
||||||
}
|
}
|
||||||
|
|||||||
+4
-1
@@ -96,7 +96,10 @@ public class SavingsAccountTransactionsApiResource {
|
|||||||
result = this.commandsSourceWritePlatformService.logCommandSource(commandRequest);
|
result = this.commandsSourceWritePlatformService.logCommandSource(commandRequest);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (result == null) { throw new UnrecognizedQueryParamException("command", commandParam); }
|
if (result == null) {
|
||||||
|
// FIXME - KW - handle blank command param use case
|
||||||
|
throw new UnrecognizedQueryParamException("command", commandParam);
|
||||||
|
}
|
||||||
|
|
||||||
return this.toApiJsonSerializer.serialize(result);
|
return this.toApiJsonSerializer.serialize(result);
|
||||||
}
|
}
|
||||||
|
|||||||
+29
@@ -23,6 +23,7 @@ import javax.ws.rs.core.Context;
|
|||||||
import javax.ws.rs.core.MediaType;
|
import javax.ws.rs.core.MediaType;
|
||||||
import javax.ws.rs.core.UriInfo;
|
import javax.ws.rs.core.UriInfo;
|
||||||
|
|
||||||
|
import org.apache.commons.lang.StringUtils;
|
||||||
import org.mifosplatform.commands.domain.CommandWrapper;
|
import org.mifosplatform.commands.domain.CommandWrapper;
|
||||||
import org.mifosplatform.commands.service.CommandWrapperBuilder;
|
import org.mifosplatform.commands.service.CommandWrapperBuilder;
|
||||||
import org.mifosplatform.commands.service.PortfolioCommandSourceWritePlatformService;
|
import org.mifosplatform.commands.service.PortfolioCommandSourceWritePlatformService;
|
||||||
@@ -30,6 +31,7 @@ import org.mifosplatform.infrastructure.core.api.ApiParameterHelper;
|
|||||||
import org.mifosplatform.infrastructure.core.api.ApiRequestParameterHelper;
|
import org.mifosplatform.infrastructure.core.api.ApiRequestParameterHelper;
|
||||||
import org.mifosplatform.infrastructure.core.data.CommandProcessingResult;
|
import org.mifosplatform.infrastructure.core.data.CommandProcessingResult;
|
||||||
import org.mifosplatform.infrastructure.core.data.EnumOptionData;
|
import org.mifosplatform.infrastructure.core.data.EnumOptionData;
|
||||||
|
import org.mifosplatform.infrastructure.core.exception.UnrecognizedQueryParamException;
|
||||||
import org.mifosplatform.infrastructure.core.serialization.ApiRequestJsonSerializationSettings;
|
import org.mifosplatform.infrastructure.core.serialization.ApiRequestJsonSerializationSettings;
|
||||||
import org.mifosplatform.infrastructure.core.serialization.DefaultToApiJsonSerializer;
|
import org.mifosplatform.infrastructure.core.serialization.DefaultToApiJsonSerializer;
|
||||||
import org.mifosplatform.infrastructure.security.service.PlatformSecurityContext;
|
import org.mifosplatform.infrastructure.security.service.PlatformSecurityContext;
|
||||||
@@ -183,6 +185,33 @@ public class SavingsAccountsApiResource {
|
|||||||
return this.toApiJsonSerializer.serialize(result);
|
return this.toApiJsonSerializer.serialize(result);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@POST
|
||||||
|
@Path("{accountId}")
|
||||||
|
@Consumes({ MediaType.APPLICATION_JSON })
|
||||||
|
@Produces({ MediaType.APPLICATION_JSON })
|
||||||
|
public String activate(@PathParam("accountId") final Long accountId, @QueryParam("command") final String commandParam,
|
||||||
|
final String apiRequestBodyAsJson) {
|
||||||
|
|
||||||
|
final CommandWrapperBuilder builder = new CommandWrapperBuilder().withJson(apiRequestBodyAsJson);
|
||||||
|
|
||||||
|
CommandProcessingResult result = null;
|
||||||
|
if (is(commandParam, "activate")) {
|
||||||
|
final CommandWrapper commandRequest = builder.savingsAccountActivation(accountId).build();
|
||||||
|
result = this.commandsSourceWritePlatformService.logCommandSource(commandRequest);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (result == null) {
|
||||||
|
// FIXME - KW - handle blank command param use case
|
||||||
|
throw new UnrecognizedQueryParamException("command", commandParam);
|
||||||
|
}
|
||||||
|
|
||||||
|
return this.toApiJsonSerializer.serialize(result);
|
||||||
|
}
|
||||||
|
|
||||||
|
private boolean is(final String commandParam, final String commandValue) {
|
||||||
|
return StringUtils.isNotBlank(commandParam) && commandParam.trim().equalsIgnoreCase(commandValue);
|
||||||
|
}
|
||||||
|
|
||||||
@DELETE
|
@DELETE
|
||||||
@Path("{accountId}")
|
@Path("{accountId}")
|
||||||
@Consumes({ MediaType.APPLICATION_JSON })
|
@Consumes({ MediaType.APPLICATION_JSON })
|
||||||
|
|||||||
+14
-7
@@ -21,9 +21,12 @@ public class SavingsApiConstants {
|
|||||||
public static final String idParamName = "id";
|
public static final String idParamName = "id";
|
||||||
public static final String accountNoParamName = "accountNo";
|
public static final String accountNoParamName = "accountNo";
|
||||||
public static final String externalIdParamName = "externalId";
|
public static final String externalIdParamName = "externalId";
|
||||||
|
public static final String statusParamName = "status";
|
||||||
public static final String clientIdParamName = "clientId";
|
public static final String clientIdParamName = "clientId";
|
||||||
public static final String groupIdParamName = "groupId";
|
public static final String groupIdParamName = "groupId";
|
||||||
public static final String productIdParamName = "productId";
|
public static final String productIdParamName = "productId";
|
||||||
|
public static final String activeParamName = "active";
|
||||||
|
public static final String activationDateParamName = "activationDate";
|
||||||
public static final String nameParamName = "name";
|
public static final String nameParamName = "name";
|
||||||
public static final String descriptionParamName = "description";
|
public static final String descriptionParamName = "description";
|
||||||
public static final String currencyCodeParamName = "currencyCode";
|
public static final String currencyCodeParamName = "currencyCode";
|
||||||
@@ -55,9 +58,9 @@ public class SavingsApiConstants {
|
|||||||
"lockinPeriodFrequencyTypeOptions"));
|
"lockinPeriodFrequencyTypeOptions"));
|
||||||
|
|
||||||
public static final Set<String> SAVINGS_ACCOUNT_REQUEST_DATA_PARAMETERS = new HashSet<String>(Arrays.asList(localeParamName,
|
public static final Set<String> SAVINGS_ACCOUNT_REQUEST_DATA_PARAMETERS = new HashSet<String>(Arrays.asList(localeParamName,
|
||||||
accountNoParamName, externalIdParamName, clientIdParamName, groupIdParamName, productIdParamName, interestRateParamName,
|
dateFormatParamName, accountNoParamName, externalIdParamName, clientIdParamName, groupIdParamName, productIdParamName,
|
||||||
interestRatePeriodFrequencyTypeParamName, minRequiredOpeningBalanceParamName, lockinPeriodFrequencyParamName,
|
activeParamName, activationDateParamName, interestRateParamName, interestRatePeriodFrequencyTypeParamName,
|
||||||
lockinPeriodFrequencyTypeParamName));
|
minRequiredOpeningBalanceParamName, lockinPeriodFrequencyParamName, lockinPeriodFrequencyTypeParamName));
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* These parameters will match the class level parameters of
|
* These parameters will match the class level parameters of
|
||||||
@@ -65,14 +68,18 @@ public class SavingsApiConstants {
|
|||||||
* parameters to match those of request parameters.
|
* parameters to match those of request parameters.
|
||||||
*/
|
*/
|
||||||
public static final Set<String> SAVINGS_ACCOUNT_RESPONSE_DATA_PARAMETERS = new HashSet<String>(Arrays.asList(idParamName,
|
public static final Set<String> SAVINGS_ACCOUNT_RESPONSE_DATA_PARAMETERS = new HashSet<String>(Arrays.asList(idParamName,
|
||||||
accountNoParamName, externalIdParamName, clientIdParamName, "clientName", groupIdParamName, "groupName", "savingsProductId",
|
accountNoParamName, externalIdParamName, statusParamName, activationDateParamName, clientIdParamName, "clientName",
|
||||||
"savingsProductName", "currency", interestRateParamName, interestRatePeriodFrequencyTypeParamName, "annualInterestRate",
|
groupIdParamName, "groupName", "savingsProductId", "savingsProductName", "currency", interestRateParamName,
|
||||||
minRequiredOpeningBalanceParamName, lockinPeriodFrequencyParamName, lockinPeriodFrequencyTypeParamName, "summary",
|
interestRatePeriodFrequencyTypeParamName, "annualInterestRate", minRequiredOpeningBalanceParamName,
|
||||||
"transactions", "productOptions", "interestRatePeriodFrequencyTypeOptions", "lockinPeriodFrequencyTypeOptions"));
|
lockinPeriodFrequencyParamName, lockinPeriodFrequencyTypeParamName, "summary", "transactions", "productOptions",
|
||||||
|
"interestRatePeriodFrequencyTypeOptions", "lockinPeriodFrequencyTypeOptions"));
|
||||||
|
|
||||||
public static final Set<String> SAVINGS_ACCOUNT_TRANSACTION_REQUEST_DATA_PARAMETERS = new HashSet<String>(Arrays.asList(
|
public static final Set<String> SAVINGS_ACCOUNT_TRANSACTION_REQUEST_DATA_PARAMETERS = new HashSet<String>(Arrays.asList(
|
||||||
localeParamName, dateFormatParamName, transactionDateParamName, transactionAmountParamName));
|
localeParamName, dateFormatParamName, transactionDateParamName, transactionAmountParamName));
|
||||||
|
|
||||||
public static final Set<String> SAVINGS_TRANSACTION_RESPONSE_DATA_PARAMETERS = new HashSet<String>(Arrays.asList(idParamName,
|
public static final Set<String> SAVINGS_TRANSACTION_RESPONSE_DATA_PARAMETERS = new HashSet<String>(Arrays.asList(idParamName,
|
||||||
"accountId", accountNoParamName, "currency", "amount"));
|
"accountId", accountNoParamName, "currency", "amount"));
|
||||||
|
|
||||||
|
public static final Set<String> SAVINGS_ACCOUNT_ACTIVATION_REQUEST_DATA_PARAMETERS = new HashSet<String>(Arrays.asList(localeParamName,
|
||||||
|
dateFormatParamName, activationDateParamName));
|
||||||
}
|
}
|
||||||
+30
-20
@@ -8,6 +8,7 @@ package org.mifosplatform.portfolio.savings.data;
|
|||||||
import java.math.BigDecimal;
|
import java.math.BigDecimal;
|
||||||
import java.util.Collection;
|
import java.util.Collection;
|
||||||
|
|
||||||
|
import org.joda.time.LocalDate;
|
||||||
import org.mifosplatform.infrastructure.core.data.EnumOptionData;
|
import org.mifosplatform.infrastructure.core.data.EnumOptionData;
|
||||||
import org.mifosplatform.organisation.monetary.data.CurrencyData;
|
import org.mifosplatform.organisation.monetary.data.CurrencyData;
|
||||||
|
|
||||||
@@ -20,6 +21,8 @@ public class SavingsAccountData {
|
|||||||
private final Long id;
|
private final Long id;
|
||||||
private final String accountNo;
|
private final String accountNo;
|
||||||
private final String externalId;
|
private final String externalId;
|
||||||
|
private final SavingsAccountStatusEnumData status;
|
||||||
|
private final LocalDate activationDate;
|
||||||
private final Long groupId;
|
private final Long groupId;
|
||||||
private final String groupName;
|
private final String groupName;
|
||||||
private final Long clientId;
|
private final Long clientId;
|
||||||
@@ -43,10 +46,11 @@ public class SavingsAccountData {
|
|||||||
private final Collection<EnumOptionData> interestRatePeriodFrequencyTypeOptions;
|
private final Collection<EnumOptionData> interestRatePeriodFrequencyTypeOptions;
|
||||||
private final Collection<EnumOptionData> lockinPeriodFrequencyTypeOptions;
|
private final Collection<EnumOptionData> lockinPeriodFrequencyTypeOptions;
|
||||||
|
|
||||||
public static SavingsAccountData instance(final Long id, final String accountNo, final String externalId, final Long groupId,
|
public static SavingsAccountData instance(final Long id, final String accountNo, final String externalId,
|
||||||
final String groupName, final Long clientId, final String clientName, final Long productId, final String productName,
|
final SavingsAccountStatusEnumData status, final LocalDate activationDate, final Long groupId, final String groupName,
|
||||||
final CurrencyData currency, final BigDecimal interestRate, final EnumOptionData interestRatePeriodFrequencyType,
|
final Long clientId, final String clientName, final Long productId, final String productName, final CurrencyData currency,
|
||||||
final BigDecimal annualInterestRate, final BigDecimal minRequiredOpeningBalance, final Integer lockinPeriodFrequency,
|
final BigDecimal interestRate, final EnumOptionData interestRatePeriodFrequencyType, final BigDecimal annualInterestRate,
|
||||||
|
final BigDecimal minRequiredOpeningBalance, final Integer lockinPeriodFrequency,
|
||||||
final EnumOptionData lockinPeriodFrequencyType, final SavingsAccountSummaryData summary) {
|
final EnumOptionData lockinPeriodFrequencyType, final SavingsAccountSummaryData summary) {
|
||||||
|
|
||||||
final Collection<SavingsProductData> productOptions = null;
|
final Collection<SavingsProductData> productOptions = null;
|
||||||
@@ -54,21 +58,22 @@ public class SavingsAccountData {
|
|||||||
final Collection<EnumOptionData> lockinPeriodFrequencyTypeOptions = null;
|
final Collection<EnumOptionData> lockinPeriodFrequencyTypeOptions = null;
|
||||||
final Collection<SavingsAccountTransactionData> transactions = null;
|
final Collection<SavingsAccountTransactionData> transactions = null;
|
||||||
|
|
||||||
return new SavingsAccountData(id, accountNo, externalId, groupId, groupName, clientId, clientName, productId, productName,
|
return new SavingsAccountData(id, accountNo, externalId, status, activationDate, groupId, groupName, clientId, clientName,
|
||||||
currency, interestRate, interestRatePeriodFrequencyType, annualInterestRate, minRequiredOpeningBalance,
|
productId, productName, currency, interestRate, interestRatePeriodFrequencyType, annualInterestRate,
|
||||||
lockinPeriodFrequency, lockinPeriodFrequencyType, summary, productOptions, interestRatePeriodFrequencyTypeOptions,
|
minRequiredOpeningBalance, lockinPeriodFrequency, lockinPeriodFrequencyType, summary, productOptions,
|
||||||
lockinPeriodFrequencyTypeOptions, transactions);
|
interestRatePeriodFrequencyTypeOptions, lockinPeriodFrequencyTypeOptions, transactions);
|
||||||
}
|
}
|
||||||
|
|
||||||
public static SavingsAccountData withTemplateOptions(final SavingsAccountData account,
|
public static SavingsAccountData withTemplateOptions(final SavingsAccountData account,
|
||||||
final Collection<SavingsProductData> productOptions, final Collection<EnumOptionData> interestRatePeriodFrequencyTypeOptions,
|
final Collection<SavingsProductData> productOptions, final Collection<EnumOptionData> interestRatePeriodFrequencyTypeOptions,
|
||||||
final Collection<EnumOptionData> lockinPeriodFrequencyTypeOptions, final Collection<SavingsAccountTransactionData> transactions) {
|
final Collection<EnumOptionData> lockinPeriodFrequencyTypeOptions, final Collection<SavingsAccountTransactionData> transactions) {
|
||||||
|
|
||||||
return new SavingsAccountData(account.id, account.accountNo, account.externalId, account.groupId, account.groupName,
|
return new SavingsAccountData(account.id, account.accountNo, account.externalId, account.status, account.activationDate,
|
||||||
account.clientId, account.clientName, account.savingsProductId, account.savingsProductName, account.currency,
|
account.groupId, account.groupName, account.clientId, account.clientName, account.savingsProductId,
|
||||||
account.interestRate, account.interestRatePeriodFrequencyType, account.annualInterestRate,
|
account.savingsProductName, account.currency, account.interestRate, account.interestRatePeriodFrequencyType,
|
||||||
account.minRequiredOpeningBalance, account.lockinPeriodFrequency, account.lockinPeriodFrequencyType, account.summary,
|
account.annualInterestRate, account.minRequiredOpeningBalance, account.lockinPeriodFrequency,
|
||||||
productOptions, interestRatePeriodFrequencyTypeOptions, lockinPeriodFrequencyTypeOptions, transactions);
|
account.lockinPeriodFrequencyType, account.summary, productOptions, interestRatePeriodFrequencyTypeOptions,
|
||||||
|
lockinPeriodFrequencyTypeOptions, transactions);
|
||||||
}
|
}
|
||||||
|
|
||||||
public static SavingsAccountData withClientTemplate(final Long clientId, final String clientName, final Long groupId,
|
public static SavingsAccountData withClientTemplate(final Long clientId, final String clientName, final Long groupId,
|
||||||
@@ -77,6 +82,8 @@ public class SavingsAccountData {
|
|||||||
final Long id = null;
|
final Long id = null;
|
||||||
final String accountNo = null;
|
final String accountNo = null;
|
||||||
final String externalId = null;
|
final String externalId = null;
|
||||||
|
final SavingsAccountStatusEnumData status = null;
|
||||||
|
final LocalDate activationDate = null;
|
||||||
final Long productId = null;
|
final Long productId = null;
|
||||||
final String productName = null;
|
final String productName = null;
|
||||||
final CurrencyData currency = null;
|
final CurrencyData currency = null;
|
||||||
@@ -93,15 +100,16 @@ public class SavingsAccountData {
|
|||||||
final Collection<EnumOptionData> lockinPeriodFrequencyTypeOptions = null;
|
final Collection<EnumOptionData> lockinPeriodFrequencyTypeOptions = null;
|
||||||
final Collection<SavingsAccountTransactionData> transactions = null;
|
final Collection<SavingsAccountTransactionData> transactions = null;
|
||||||
|
|
||||||
return new SavingsAccountData(id, accountNo, externalId, groupId, groupName, clientId, clientName, productId, productName,
|
return new SavingsAccountData(id, accountNo, externalId, status, activationDate, groupId, groupName, clientId, clientName,
|
||||||
currency, interestRate, interestRatePeriodFrequencyType, annualInterestRate, minRequiredOpeningBalance,
|
productId, productName, currency, interestRate, interestRatePeriodFrequencyType, annualInterestRate,
|
||||||
lockinPeriodFrequency, lockinPeriodFrequencyType, summary, productOptions, interestRatePeriodFrequencyTypeOptions,
|
minRequiredOpeningBalance, lockinPeriodFrequency, lockinPeriodFrequencyType, summary, productOptions,
|
||||||
lockinPeriodFrequencyTypeOptions, transactions);
|
interestRatePeriodFrequencyTypeOptions, lockinPeriodFrequencyTypeOptions, transactions);
|
||||||
}
|
}
|
||||||
|
|
||||||
private SavingsAccountData(final Long id, final String accountNo, final String externalId, final Long groupId, final String groupName,
|
private SavingsAccountData(final Long id, final String accountNo, final String externalId, final SavingsAccountStatusEnumData status,
|
||||||
final Long clientId, final String clientName, final Long productId, final String productName, final CurrencyData currency,
|
final LocalDate activationDate, final Long groupId, final String groupName, final Long clientId, final String clientName,
|
||||||
final BigDecimal interestRate, final EnumOptionData interestRatePeriodFrequencyType, final BigDecimal annualInterestRate,
|
final Long productId, final String productName, final CurrencyData currency, final BigDecimal interestRate,
|
||||||
|
final EnumOptionData interestRatePeriodFrequencyType, final BigDecimal annualInterestRate,
|
||||||
final BigDecimal minRequiredOpeningBalance, final Integer lockinPeriodFrequency,
|
final BigDecimal minRequiredOpeningBalance, final Integer lockinPeriodFrequency,
|
||||||
final EnumOptionData lockinPeriodFrequencyType, final SavingsAccountSummaryData summary,
|
final EnumOptionData lockinPeriodFrequencyType, final SavingsAccountSummaryData summary,
|
||||||
final Collection<SavingsProductData> productOptions, final Collection<EnumOptionData> interestRatePeriodFrequencyTypeOptions,
|
final Collection<SavingsProductData> productOptions, final Collection<EnumOptionData> interestRatePeriodFrequencyTypeOptions,
|
||||||
@@ -109,6 +117,8 @@ public class SavingsAccountData {
|
|||||||
this.id = id;
|
this.id = id;
|
||||||
this.accountNo = accountNo;
|
this.accountNo = accountNo;
|
||||||
this.externalId = externalId;
|
this.externalId = externalId;
|
||||||
|
this.status = status;
|
||||||
|
this.activationDate = activationDate;
|
||||||
this.groupId = groupId;
|
this.groupId = groupId;
|
||||||
this.groupName = groupName;
|
this.groupName = groupName;
|
||||||
this.clientId = clientId;
|
this.clientId = clientId;
|
||||||
|
|||||||
+12
@@ -1,6 +1,8 @@
|
|||||||
package org.mifosplatform.portfolio.savings.data;
|
package org.mifosplatform.portfolio.savings.data;
|
||||||
|
|
||||||
import static org.mifosplatform.portfolio.savings.api.SavingsApiConstants.accountNoParamName;
|
import static org.mifosplatform.portfolio.savings.api.SavingsApiConstants.accountNoParamName;
|
||||||
|
import static org.mifosplatform.portfolio.savings.api.SavingsApiConstants.activationDateParamName;
|
||||||
|
import static org.mifosplatform.portfolio.savings.api.SavingsApiConstants.activeParamName;
|
||||||
import static org.mifosplatform.portfolio.savings.api.SavingsApiConstants.clientIdParamName;
|
import static org.mifosplatform.portfolio.savings.api.SavingsApiConstants.clientIdParamName;
|
||||||
import static org.mifosplatform.portfolio.savings.api.SavingsApiConstants.externalIdParamName;
|
import static org.mifosplatform.portfolio.savings.api.SavingsApiConstants.externalIdParamName;
|
||||||
import static org.mifosplatform.portfolio.savings.api.SavingsApiConstants.groupIdParamName;
|
import static org.mifosplatform.portfolio.savings.api.SavingsApiConstants.groupIdParamName;
|
||||||
@@ -18,6 +20,7 @@ import java.util.List;
|
|||||||
import java.util.Map;
|
import java.util.Map;
|
||||||
|
|
||||||
import org.apache.commons.lang.StringUtils;
|
import org.apache.commons.lang.StringUtils;
|
||||||
|
import org.joda.time.LocalDate;
|
||||||
import org.mifosplatform.infrastructure.core.data.ApiParameterError;
|
import org.mifosplatform.infrastructure.core.data.ApiParameterError;
|
||||||
import org.mifosplatform.infrastructure.core.data.DataValidatorBuilder;
|
import org.mifosplatform.infrastructure.core.data.DataValidatorBuilder;
|
||||||
import org.mifosplatform.infrastructure.core.exception.InvalidJsonException;
|
import org.mifosplatform.infrastructure.core.exception.InvalidJsonException;
|
||||||
@@ -69,6 +72,15 @@ public class SavingsAccountDataValidator {
|
|||||||
final Long productId = fromApiJsonHelper.extractLongNamed(productIdParamName, element);
|
final Long productId = fromApiJsonHelper.extractLongNamed(productIdParamName, element);
|
||||||
baseDataValidator.reset().parameter(productIdParamName).value(productId).notNull().integerGreaterThanZero();
|
baseDataValidator.reset().parameter(productIdParamName).value(productId).notNull().integerGreaterThanZero();
|
||||||
|
|
||||||
|
final Boolean active = fromApiJsonHelper.extractBooleanNamed(activeParamName, element);
|
||||||
|
baseDataValidator.reset().parameter(activeParamName).value(active).notNull();
|
||||||
|
|
||||||
|
LocalDate activationDate = null;
|
||||||
|
if (active != null && active.booleanValue()) {
|
||||||
|
activationDate = fromApiJsonHelper.extractLocalDateNamed(activationDateParamName, element);
|
||||||
|
baseDataValidator.reset().parameter(activationDateParamName).value(activationDate).notNull();
|
||||||
|
}
|
||||||
|
|
||||||
if (fromApiJsonHelper.parameterExists(accountNoParamName, element)) {
|
if (fromApiJsonHelper.parameterExists(accountNoParamName, element)) {
|
||||||
final String accountNo = fromApiJsonHelper.extractStringNamed(accountNoParamName, element);
|
final String accountNo = fromApiJsonHelper.extractStringNamed(accountNoParamName, element);
|
||||||
baseDataValidator.reset().parameter(accountNoParamName).value(accountNo).notBlank().notExceedingLengthOf(20);
|
baseDataValidator.reset().parameter(accountNoParamName).value(accountNo).notBlank().notExceedingLengthOf(20);
|
||||||
|
|||||||
+35
@@ -0,0 +1,35 @@
|
|||||||
|
/**
|
||||||
|
* This Source Code Form is subject to the terms of the Mozilla Public
|
||||||
|
* License, v. 2.0. If a copy of the MPL was not distributed with this file,
|
||||||
|
* You can obtain one at http://mozilla.org/MPL/2.0/.
|
||||||
|
*/
|
||||||
|
package org.mifosplatform.portfolio.savings.data;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Immutable data object represent savings account status enumerations.
|
||||||
|
*/
|
||||||
|
public class SavingsAccountStatusEnumData {
|
||||||
|
|
||||||
|
@SuppressWarnings("unused")
|
||||||
|
private final Long id;
|
||||||
|
@SuppressWarnings("unused")
|
||||||
|
private final String code;
|
||||||
|
@SuppressWarnings("unused")
|
||||||
|
private final String value;
|
||||||
|
@SuppressWarnings("unused")
|
||||||
|
private final boolean unactivated;
|
||||||
|
@SuppressWarnings("unused")
|
||||||
|
private final boolean active;
|
||||||
|
@SuppressWarnings("unused")
|
||||||
|
private final boolean closed;
|
||||||
|
|
||||||
|
public SavingsAccountStatusEnumData(final Long id, final String code, final String value, final boolean unactivated,
|
||||||
|
final boolean active, final boolean closed) {
|
||||||
|
this.id = id;
|
||||||
|
this.code = code;
|
||||||
|
this.value = value;
|
||||||
|
this.unactivated = unactivated;
|
||||||
|
this.active = active;
|
||||||
|
this.closed = closed;
|
||||||
|
}
|
||||||
|
}
|
||||||
+23
-1
@@ -1,5 +1,6 @@
|
|||||||
package org.mifosplatform.portfolio.savings.data;
|
package org.mifosplatform.portfolio.savings.data;
|
||||||
|
|
||||||
|
import static org.mifosplatform.portfolio.savings.api.SavingsApiConstants.activationDateParamName;
|
||||||
import static org.mifosplatform.portfolio.savings.api.SavingsApiConstants.transactionAmountParamName;
|
import static org.mifosplatform.portfolio.savings.api.SavingsApiConstants.transactionAmountParamName;
|
||||||
import static org.mifosplatform.portfolio.savings.api.SavingsApiConstants.transactionDateParamName;
|
import static org.mifosplatform.portfolio.savings.api.SavingsApiConstants.transactionDateParamName;
|
||||||
|
|
||||||
@@ -54,7 +55,28 @@ public class SavingsAccountTransactionDataValidator {
|
|||||||
baseDataValidator.reset().parameter(transactionDateParamName).value(transactionDate).notNull();
|
baseDataValidator.reset().parameter(transactionDateParamName).value(transactionDate).notNull();
|
||||||
|
|
||||||
final BigDecimal transactionAmount = fromApiJsonHelper.extractBigDecimalWithLocaleNamed(transactionAmountParamName, element);
|
final BigDecimal transactionAmount = fromApiJsonHelper.extractBigDecimalWithLocaleNamed(transactionAmountParamName, element);
|
||||||
baseDataValidator.reset().parameter(transactionAmountParamName).value(transactionAmount).notNull().zeroOrPositiveAmount();
|
baseDataValidator.reset().parameter(transactionAmountParamName).value(transactionAmount).notNull().positiveAmount();
|
||||||
|
|
||||||
|
throwExceptionIfValidationWarningsExist(dataValidationErrors);
|
||||||
|
}
|
||||||
|
|
||||||
|
public void validateActivation(final JsonCommand command) {
|
||||||
|
final String json = command.json();
|
||||||
|
|
||||||
|
if (StringUtils.isBlank(json)) { throw new InvalidJsonException(); }
|
||||||
|
|
||||||
|
final Type typeOfMap = new TypeToken<Map<String, Object>>() {}.getType();
|
||||||
|
fromApiJsonHelper.checkForUnsupportedParameters(typeOfMap, json,
|
||||||
|
SavingsApiConstants.SAVINGS_ACCOUNT_ACTIVATION_REQUEST_DATA_PARAMETERS);
|
||||||
|
|
||||||
|
final List<ApiParameterError> dataValidationErrors = new ArrayList<ApiParameterError>();
|
||||||
|
final DataValidatorBuilder baseDataValidator = new DataValidatorBuilder(dataValidationErrors)
|
||||||
|
.resource(SavingsApiConstants.SAVINGS_ACCOUNT_RESOURCE_NAME);
|
||||||
|
|
||||||
|
final JsonElement element = command.parsedJson();
|
||||||
|
|
||||||
|
final LocalDate activationDate = fromApiJsonHelper.extractLocalDateNamed(activationDateParamName, element);
|
||||||
|
baseDataValidator.reset().parameter(activationDateParamName).value(activationDate).notNull();
|
||||||
|
|
||||||
throwExceptionIfValidationWarningsExist(dataValidationErrors);
|
throwExceptionIfValidationWarningsExist(dataValidationErrors);
|
||||||
}
|
}
|
||||||
|
|||||||
+229
-28
@@ -7,6 +7,8 @@ package org.mifosplatform.portfolio.savings.domain;
|
|||||||
|
|
||||||
import java.math.BigDecimal;
|
import java.math.BigDecimal;
|
||||||
import java.util.ArrayList;
|
import java.util.ArrayList;
|
||||||
|
import java.util.Arrays;
|
||||||
|
import java.util.Date;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
import java.util.Map;
|
import java.util.Map;
|
||||||
|
|
||||||
@@ -19,6 +21,8 @@ import javax.persistence.ManyToOne;
|
|||||||
import javax.persistence.OneToMany;
|
import javax.persistence.OneToMany;
|
||||||
import javax.persistence.OrderBy;
|
import javax.persistence.OrderBy;
|
||||||
import javax.persistence.Table;
|
import javax.persistence.Table;
|
||||||
|
import javax.persistence.Temporal;
|
||||||
|
import javax.persistence.TemporalType;
|
||||||
import javax.persistence.Transient;
|
import javax.persistence.Transient;
|
||||||
import javax.persistence.UniqueConstraint;
|
import javax.persistence.UniqueConstraint;
|
||||||
|
|
||||||
@@ -26,7 +30,10 @@ import org.apache.commons.lang.StringUtils;
|
|||||||
import org.hibernate.annotations.LazyCollection;
|
import org.hibernate.annotations.LazyCollection;
|
||||||
import org.hibernate.annotations.LazyCollectionOption;
|
import org.hibernate.annotations.LazyCollectionOption;
|
||||||
import org.joda.time.LocalDate;
|
import org.joda.time.LocalDate;
|
||||||
|
import org.joda.time.format.DateTimeFormatter;
|
||||||
import org.mifosplatform.infrastructure.core.api.JsonCommand;
|
import org.mifosplatform.infrastructure.core.api.JsonCommand;
|
||||||
|
import org.mifosplatform.infrastructure.core.data.ApiParameterError;
|
||||||
|
import org.mifosplatform.infrastructure.core.exception.PlatformApiDataValidationException;
|
||||||
import org.mifosplatform.infrastructure.core.service.DateUtils;
|
import org.mifosplatform.infrastructure.core.service.DateUtils;
|
||||||
import org.mifosplatform.infrastructure.security.service.RandomPasswordGenerator;
|
import org.mifosplatform.infrastructure.security.service.RandomPasswordGenerator;
|
||||||
import org.mifosplatform.organisation.monetary.domain.MonetaryCurrency;
|
import org.mifosplatform.organisation.monetary.domain.MonetaryCurrency;
|
||||||
@@ -36,7 +43,6 @@ import org.mifosplatform.portfolio.group.domain.Group;
|
|||||||
import org.mifosplatform.portfolio.loanproduct.domain.PeriodFrequencyType;
|
import org.mifosplatform.portfolio.loanproduct.domain.PeriodFrequencyType;
|
||||||
import org.mifosplatform.portfolio.savings.api.SavingsApiConstants;
|
import org.mifosplatform.portfolio.savings.api.SavingsApiConstants;
|
||||||
import org.mifosplatform.portfolio.savings.exception.InsufficientAccountBalanceException;
|
import org.mifosplatform.portfolio.savings.exception.InsufficientAccountBalanceException;
|
||||||
import org.mifosplatform.portfolio.savings.exception.InvalidSavingsAccountTransactionException;
|
|
||||||
import org.springframework.data.jpa.domain.AbstractPersistable;
|
import org.springframework.data.jpa.domain.AbstractPersistable;
|
||||||
|
|
||||||
@Entity
|
@Entity
|
||||||
@@ -47,7 +53,7 @@ public class SavingsAccount extends AbstractPersistable<Long> {
|
|||||||
@Column(name = "account_no", length = 20, unique = true, nullable = false)
|
@Column(name = "account_no", length = 20, unique = true, nullable = false)
|
||||||
private String accountNumber;
|
private String accountNumber;
|
||||||
|
|
||||||
@Column(name = "external_id")
|
@Column(name = "external_id", nullable = true)
|
||||||
private String externalId;
|
private String externalId;
|
||||||
|
|
||||||
@ManyToOne(optional = true)
|
@ManyToOne(optional = true)
|
||||||
@@ -62,6 +68,13 @@ public class SavingsAccount extends AbstractPersistable<Long> {
|
|||||||
@JoinColumn(name = "product_id", nullable = false)
|
@JoinColumn(name = "product_id", nullable = false)
|
||||||
private SavingsProduct product;
|
private SavingsProduct product;
|
||||||
|
|
||||||
|
@Column(name = "status_enum", nullable = false)
|
||||||
|
private Integer status;
|
||||||
|
|
||||||
|
@Temporal(TemporalType.DATE)
|
||||||
|
@Column(name = "activation_date", nullable = true)
|
||||||
|
private Date activationDate;
|
||||||
|
|
||||||
@Embedded
|
@Embedded
|
||||||
private MonetaryCurrency currency;
|
private MonetaryCurrency currency;
|
||||||
|
|
||||||
@@ -84,6 +97,15 @@ public class SavingsAccount extends AbstractPersistable<Long> {
|
|||||||
@Column(name = "lockin_period_frequency_enum", nullable = false)
|
@Column(name = "lockin_period_frequency_enum", nullable = false)
|
||||||
private Integer lockinPeriodFrequencyType;
|
private Integer lockinPeriodFrequencyType;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* When account is becomes <code>active</code> this field is derived if
|
||||||
|
* <code>lockinPeriodFrequency</code> and
|
||||||
|
* <code>lockinPeriodFrequencyType</code> details are present.
|
||||||
|
*/
|
||||||
|
@Temporal(TemporalType.DATE)
|
||||||
|
@Column(name = "lockedin_until_date_derived", nullable = true)
|
||||||
|
private Date lockedInUntilDate;
|
||||||
|
|
||||||
@Embedded
|
@Embedded
|
||||||
private SavingsAccountSummary summary;
|
private SavingsAccountSummary summary;
|
||||||
|
|
||||||
@@ -102,18 +124,25 @@ public class SavingsAccount extends AbstractPersistable<Long> {
|
|||||||
}
|
}
|
||||||
|
|
||||||
public static SavingsAccount createNewAccount(final Client client, final Group group, final SavingsProduct product,
|
public static SavingsAccount createNewAccount(final Client client, final Group group, final SavingsProduct product,
|
||||||
final String accountNo, final String externalId, final BigDecimal interestRate,
|
final String accountNo, final String externalId, final boolean active, final LocalDate activationDate,
|
||||||
final PeriodFrequencyType interestRatePeriodFrequencyType, final BigDecimal annualInterestRate,
|
final BigDecimal interestRate, final PeriodFrequencyType interestRatePeriodFrequencyType, final BigDecimal annualInterestRate,
|
||||||
final BigDecimal minRequiredOpeningBalance, final Integer lockinPeriodFrequency,
|
final BigDecimal minRequiredOpeningBalance, final Integer lockinPeriodFrequency,
|
||||||
final PeriodFrequencyType lockinPeriodFrequencyType) {
|
final PeriodFrequencyType lockinPeriodFrequencyType) {
|
||||||
|
|
||||||
return new SavingsAccount(client, group, product, accountNo, externalId, interestRate, interestRatePeriodFrequencyType,
|
SavingsAccountStatusType status = SavingsAccountStatusType.UNACTIVATED;
|
||||||
annualInterestRate, minRequiredOpeningBalance, lockinPeriodFrequency, lockinPeriodFrequencyType);
|
if (active) {
|
||||||
|
status = SavingsAccountStatusType.ACTIVE;
|
||||||
|
}
|
||||||
|
|
||||||
|
return new SavingsAccount(client, group, product, accountNo, externalId, status, activationDate, interestRate,
|
||||||
|
interestRatePeriodFrequencyType, annualInterestRate, minRequiredOpeningBalance, lockinPeriodFrequency,
|
||||||
|
lockinPeriodFrequencyType);
|
||||||
}
|
}
|
||||||
|
|
||||||
private SavingsAccount(final Client client, final Group group, final SavingsProduct product, final String accountNo,
|
private SavingsAccount(final Client client, final Group group, final SavingsProduct product, final String accountNo,
|
||||||
final String externalId, final BigDecimal interestRate, final PeriodFrequencyType interestRatePeriodFrequencyType,
|
final String externalId, final SavingsAccountStatusType status, final LocalDate activationDate, final BigDecimal interestRate,
|
||||||
final BigDecimal annualInterestRate, final BigDecimal minRequiredOpeningBalance, final Integer lockinPeriodFrequency,
|
final PeriodFrequencyType interestRatePeriodFrequencyType, final BigDecimal annualInterestRate,
|
||||||
|
final BigDecimal minRequiredOpeningBalance, final Integer lockinPeriodFrequency,
|
||||||
final PeriodFrequencyType lockinPeriodFrequencyType) {
|
final PeriodFrequencyType lockinPeriodFrequencyType) {
|
||||||
this.client = client;
|
this.client = client;
|
||||||
this.group = group;
|
this.group = group;
|
||||||
@@ -126,6 +155,10 @@ public class SavingsAccount extends AbstractPersistable<Long> {
|
|||||||
}
|
}
|
||||||
this.currency = product.currency();
|
this.currency = product.currency();
|
||||||
this.externalId = externalId;
|
this.externalId = externalId;
|
||||||
|
this.status = status.getValue();
|
||||||
|
if (activationDate != null) {
|
||||||
|
this.activationDate = activationDate.toDate();
|
||||||
|
}
|
||||||
this.interestRate = interestRate;
|
this.interestRate = interestRate;
|
||||||
this.interestRatePeriodFrequencyType = interestRatePeriodFrequencyType.getValue();
|
this.interestRatePeriodFrequencyType = interestRatePeriodFrequencyType.getValue();
|
||||||
this.annualInterestRate = annualInterestRate;
|
this.annualInterestRate = annualInterestRate;
|
||||||
@@ -140,24 +173,121 @@ public class SavingsAccount extends AbstractPersistable<Long> {
|
|||||||
/**
|
/**
|
||||||
* Used after fetching/hydrating a {@link SavingsAccount} object to inject
|
* Used after fetching/hydrating a {@link SavingsAccount} object to inject
|
||||||
* helper services/components used for update summary details after
|
* helper services/components used for update summary details after
|
||||||
* events/transactions on a loan.
|
* events/transactions on a {@link SavingsAccount}.
|
||||||
*/
|
*/
|
||||||
public void setHelpers(final SavingsAccountTransactionSummaryWrapper savingsAccountTransactionSummaryWrapper) {
|
public void setHelpers(final SavingsAccountTransactionSummaryWrapper savingsAccountTransactionSummaryWrapper) {
|
||||||
this.savingsAccountTransactionSummaryWrapper = savingsAccountTransactionSummaryWrapper;
|
this.savingsAccountTransactionSummaryWrapper = savingsAccountTransactionSummaryWrapper;
|
||||||
}
|
}
|
||||||
|
|
||||||
public SavingsAccountTransaction deposit(final LocalDate transactionDate, final BigDecimal transactionAmount) {
|
public boolean isNotActive() {
|
||||||
|
return !isActive();
|
||||||
|
}
|
||||||
|
|
||||||
final Money amount = Money.of(this.currency, transactionAmount);
|
public boolean isActive() {
|
||||||
|
return SavingsAccountStatusType.fromInt(this.status).isActive();
|
||||||
|
}
|
||||||
|
|
||||||
// FIXME - kw - check transactionDate is not before savings account
|
public void activate(final DateTimeFormatter formatter, final LocalDate activationDate) {
|
||||||
// activation date.
|
|
||||||
|
|
||||||
if (isTransactionInTheFuture(transactionDate)) {
|
if (isActive()) {
|
||||||
final String defaultUserMessage = "Transaction date cannot be in the future.";
|
final String defaultUserMessage = "Cannot activate account. Account is already active.";
|
||||||
throw new InvalidSavingsAccountTransactionException("in.the.future", defaultUserMessage, "transactionDate", transactionDate);
|
final ApiParameterError error = ApiParameterError.parameterError("error.msg.savingsaccount.transaction.account.already.active",
|
||||||
|
defaultUserMessage, "activationDate", activationDate.toString(formatter));
|
||||||
|
|
||||||
|
final List<ApiParameterError> dataValidationErrors = new ArrayList<ApiParameterError>();
|
||||||
|
dataValidationErrors.add(error);
|
||||||
|
|
||||||
|
throw new PlatformApiDataValidationException(dataValidationErrors);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (isDateInTheFuture(activationDate)) {
|
||||||
|
|
||||||
|
final String defaultUserMessage = "Activation date cannot be in the future.";
|
||||||
|
final ApiParameterError error = ApiParameterError.parameterError("error.msg.savingsaccount.transaction.in.the.future",
|
||||||
|
defaultUserMessage, "activationDate", activationDate);
|
||||||
|
|
||||||
|
final List<ApiParameterError> dataValidationErrors = new ArrayList<ApiParameterError>();
|
||||||
|
dataValidationErrors.add(error);
|
||||||
|
|
||||||
|
throw new PlatformApiDataValidationException(dataValidationErrors);
|
||||||
|
}
|
||||||
|
|
||||||
|
this.activationDate = activationDate.toDate();
|
||||||
|
this.status = SavingsAccountStatusType.ACTIVE.getValue();
|
||||||
|
|
||||||
|
this.lockedInUntilDate = calculateDateAccountIsLockedUntil(getActivationLocalDate());
|
||||||
|
|
||||||
|
// auto enter deposit for minimum required opening balance when
|
||||||
|
// activating account.
|
||||||
|
final Money minRequiredOpeningBalance = Money.of(this.currency, this.minRequiredOpeningBalance);
|
||||||
|
if (minRequiredOpeningBalance.isGreaterThanZero()) {
|
||||||
|
deposit(formatter, activationDate, minRequiredOpeningBalance.getAmount());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private Date calculateDateAccountIsLockedUntil(final LocalDate activationLocalDate) {
|
||||||
|
|
||||||
|
Date lockedInUntilLocalDate = null;
|
||||||
|
final PeriodFrequencyType lockinPeriodFrequencyType = PeriodFrequencyType.fromInt(this.lockinPeriodFrequencyType);
|
||||||
|
switch (lockinPeriodFrequencyType) {
|
||||||
|
case INVALID:
|
||||||
|
break;
|
||||||
|
case DAYS:
|
||||||
|
lockedInUntilLocalDate = activationLocalDate.plusDays(this.lockinPeriodFrequency).toDate();
|
||||||
|
break;
|
||||||
|
case WEEKS:
|
||||||
|
lockedInUntilLocalDate = activationLocalDate.plusWeeks(this.lockinPeriodFrequency).toDate();
|
||||||
|
break;
|
||||||
|
case MONTHS:
|
||||||
|
lockedInUntilLocalDate = activationLocalDate.plusMonths(this.lockinPeriodFrequency).toDate();
|
||||||
|
break;
|
||||||
|
case YEARS:
|
||||||
|
lockedInUntilLocalDate = activationLocalDate.plusYears(this.lockinPeriodFrequency).toDate();
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
return lockedInUntilLocalDate;
|
||||||
|
}
|
||||||
|
|
||||||
|
public SavingsAccountTransaction deposit(final DateTimeFormatter formatter, final LocalDate transactionDate,
|
||||||
|
final BigDecimal transactionAmount) {
|
||||||
|
|
||||||
|
if (isNotActive()) {
|
||||||
|
final String defaultUserMessage = "Transaction is not allowed. Account is not active.";
|
||||||
|
final ApiParameterError error = ApiParameterError.parameterError("error.msg.savingsaccount.transaction.account.is.not.active",
|
||||||
|
defaultUserMessage, "transactionDate", transactionDate.toString(formatter));
|
||||||
|
|
||||||
|
final List<ApiParameterError> dataValidationErrors = new ArrayList<ApiParameterError>();
|
||||||
|
dataValidationErrors.add(error);
|
||||||
|
|
||||||
|
throw new PlatformApiDataValidationException(dataValidationErrors);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (isDateInTheFuture(transactionDate)) {
|
||||||
|
final String defaultUserMessage = "Transaction date cannot be in the future.";
|
||||||
|
final ApiParameterError error = ApiParameterError.parameterError("error.msg.savingsaccount.transaction.in.the.future",
|
||||||
|
defaultUserMessage, "transactionDate", transactionDate.toString(formatter));
|
||||||
|
|
||||||
|
final List<ApiParameterError> dataValidationErrors = new ArrayList<ApiParameterError>();
|
||||||
|
dataValidationErrors.add(error);
|
||||||
|
|
||||||
|
throw new PlatformApiDataValidationException(dataValidationErrors);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (transactionDate.isBefore(getActivationLocalDate())) {
|
||||||
|
final Object[] defaultUserArgs = Arrays.asList(transactionDate.toString(formatter),
|
||||||
|
getActivationLocalDate().toString(formatter)).toArray();
|
||||||
|
final String defaultUserMessage = "Transaction date cannot be before accounts activation date.";
|
||||||
|
final ApiParameterError error = ApiParameterError.parameterError("error.msg.savingsaccount.transaction.before.activation.date",
|
||||||
|
defaultUserMessage, "transactionDate", defaultUserArgs);
|
||||||
|
|
||||||
|
final List<ApiParameterError> dataValidationErrors = new ArrayList<ApiParameterError>();
|
||||||
|
dataValidationErrors.add(error);
|
||||||
|
|
||||||
|
throw new PlatformApiDataValidationException(dataValidationErrors);
|
||||||
|
}
|
||||||
|
|
||||||
|
final Money amount = Money.of(this.currency, transactionAmount);
|
||||||
final SavingsAccountTransaction transaction = SavingsAccountTransaction.deposit(this, transactionDate, amount);
|
final SavingsAccountTransaction transaction = SavingsAccountTransaction.deposit(this, transactionDate, amount);
|
||||||
this.transactions.add(transaction);
|
this.transactions.add(transaction);
|
||||||
|
|
||||||
@@ -166,19 +296,69 @@ public class SavingsAccount extends AbstractPersistable<Long> {
|
|||||||
return transaction;
|
return transaction;
|
||||||
}
|
}
|
||||||
|
|
||||||
public SavingsAccountTransaction withdrawal(final LocalDate transactionDate, final BigDecimal transactionAmount) {
|
private LocalDate getActivationLocalDate() {
|
||||||
|
LocalDate activationLocalDate = null;
|
||||||
|
if (this.activationDate != null) {
|
||||||
|
activationLocalDate = new LocalDate(this.activationDate);
|
||||||
|
}
|
||||||
|
return activationLocalDate;
|
||||||
|
}
|
||||||
|
|
||||||
|
public SavingsAccountTransaction withdraw(final DateTimeFormatter formatter, final LocalDate transactionDate,
|
||||||
|
final BigDecimal transactionAmount) {
|
||||||
|
|
||||||
|
if (isNotActive()) {
|
||||||
|
|
||||||
|
final String defaultUserMessage = "Transaction is not allowed. Account is not active.";
|
||||||
|
final ApiParameterError error = ApiParameterError.parameterError("error.msg.savingsaccount.transaction.account.is.not.active",
|
||||||
|
defaultUserMessage, "transactionDate", transactionDate.toString(formatter));
|
||||||
|
|
||||||
|
final List<ApiParameterError> dataValidationErrors = new ArrayList<ApiParameterError>();
|
||||||
|
dataValidationErrors.add(error);
|
||||||
|
|
||||||
|
throw new PlatformApiDataValidationException(dataValidationErrors);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (isDateInTheFuture(transactionDate)) {
|
||||||
|
final String defaultUserMessage = "Transaction date cannot be in the future.";
|
||||||
|
final ApiParameterError error = ApiParameterError.parameterError("error.msg.savingsaccount.transaction.in.the.future",
|
||||||
|
defaultUserMessage, "transactionDate", transactionDate.toString(formatter));
|
||||||
|
|
||||||
|
final List<ApiParameterError> dataValidationErrors = new ArrayList<ApiParameterError>();
|
||||||
|
dataValidationErrors.add(error);
|
||||||
|
|
||||||
|
throw new PlatformApiDataValidationException(dataValidationErrors);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (transactionDate.isBefore(getActivationLocalDate())) {
|
||||||
|
final Object[] defaultUserArgs = Arrays.asList(transactionDate.toString(formatter),
|
||||||
|
getActivationLocalDate().toString(formatter)).toArray();
|
||||||
|
final String defaultUserMessage = "Transaction date cannot be before accounts activation date.";
|
||||||
|
final ApiParameterError error = ApiParameterError.parameterError("error.msg.savingsaccount.transaction.before.activation.date",
|
||||||
|
defaultUserMessage, "transactionDate", defaultUserArgs);
|
||||||
|
|
||||||
|
final List<ApiParameterError> dataValidationErrors = new ArrayList<ApiParameterError>();
|
||||||
|
dataValidationErrors.add(error);
|
||||||
|
|
||||||
|
throw new PlatformApiDataValidationException(dataValidationErrors);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (isAccountLocked(transactionDate)) {
|
||||||
|
final String defaultUserMessage = "Withdrawal is not allowed. No withdrawals are allowed until after "
|
||||||
|
+ getLockedInUntilLocalDate().toString(formatter);
|
||||||
|
final ApiParameterError error = ApiParameterError.parameterError(
|
||||||
|
"error.msg.savingsaccount.transaction.withdrawals.blocked.during.lockin.period", defaultUserMessage, "transactionDate",
|
||||||
|
transactionDate.toString(formatter), getLockedInUntilLocalDate().toString(formatter));
|
||||||
|
|
||||||
|
final List<ApiParameterError> dataValidationErrors = new ArrayList<ApiParameterError>();
|
||||||
|
dataValidationErrors.add(error);
|
||||||
|
|
||||||
|
throw new PlatformApiDataValidationException(dataValidationErrors);
|
||||||
|
}
|
||||||
|
|
||||||
final Money amount = Money.of(this.currency, transactionAmount);
|
final Money amount = Money.of(this.currency, transactionAmount);
|
||||||
|
|
||||||
// FIXME - kw - check transactionDate is not before savings account
|
if (isNotEnoughFundsToWithdraw(amount)) {
|
||||||
// activation date.
|
|
||||||
|
|
||||||
if (isTransactionInTheFuture(transactionDate)) {
|
|
||||||
final String defaultUserMessage = "Transaction date cannot be in the future.";
|
|
||||||
throw new InvalidSavingsAccountTransactionException("in.the.future", defaultUserMessage, "transactionDate", transactionDate);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (isNotAllowedToWithdraw(amount)) {
|
|
||||||
//
|
//
|
||||||
throw new InsufficientAccountBalanceException("transactionAmount", getAccountBalance(), transactionAmount);
|
throw new InsufficientAccountBalanceException("transactionAmount", getAccountBalance(), transactionAmount);
|
||||||
}
|
}
|
||||||
@@ -191,7 +371,24 @@ public class SavingsAccount extends AbstractPersistable<Long> {
|
|||||||
return transaction;
|
return transaction;
|
||||||
}
|
}
|
||||||
|
|
||||||
private boolean isTransactionInTheFuture(final LocalDate transactionDate) {
|
private boolean isAccountLocked(final LocalDate transactionDate) {
|
||||||
|
boolean isLocked = false;
|
||||||
|
final boolean accountHasLockedInSetting = this.lockedInUntilDate != null;
|
||||||
|
if (accountHasLockedInSetting) {
|
||||||
|
isLocked = getLockedInUntilLocalDate().isAfter(transactionDate);
|
||||||
|
}
|
||||||
|
return isLocked;
|
||||||
|
}
|
||||||
|
|
||||||
|
private LocalDate getLockedInUntilLocalDate() {
|
||||||
|
LocalDate lockedInUntilLocalDate = null;
|
||||||
|
if (this.lockedInUntilDate != null) {
|
||||||
|
lockedInUntilLocalDate = new LocalDate(this.lockedInUntilDate);
|
||||||
|
}
|
||||||
|
return lockedInUntilLocalDate;
|
||||||
|
}
|
||||||
|
|
||||||
|
private boolean isDateInTheFuture(final LocalDate transactionDate) {
|
||||||
return transactionDate.isAfter(DateUtils.getLocalDateOfTenant());
|
return transactionDate.isAfter(DateUtils.getLocalDateOfTenant());
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -199,7 +396,11 @@ public class SavingsAccount extends AbstractPersistable<Long> {
|
|||||||
return this.summary.getAccountBalance(this.currency).getAmount();
|
return this.summary.getAccountBalance(this.currency).getAmount();
|
||||||
}
|
}
|
||||||
|
|
||||||
private boolean isNotAllowedToWithdraw(final Money amount) {
|
private boolean isNotEnoughFundsToWithdraw(final Money amount) {
|
||||||
|
return !isEnoughFundsToWithdraw(amount);
|
||||||
|
}
|
||||||
|
|
||||||
|
private boolean isEnoughFundsToWithdraw(final Money amount) {
|
||||||
return this.summary.isLessThanOrEqualToAccountBalance(amount);
|
return this.summary.isLessThanOrEqualToAccountBalance(amount);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
+18
-3
@@ -5,6 +5,8 @@
|
|||||||
*/
|
*/
|
||||||
package org.mifosplatform.portfolio.savings.domain;
|
package org.mifosplatform.portfolio.savings.domain;
|
||||||
|
|
||||||
|
import static org.mifosplatform.portfolio.savings.api.SavingsApiConstants.activationDateParamName;
|
||||||
|
import static org.mifosplatform.portfolio.savings.api.SavingsApiConstants.activeParamName;
|
||||||
import static org.mifosplatform.portfolio.savings.api.SavingsApiConstants.interestRateParamName;
|
import static org.mifosplatform.portfolio.savings.api.SavingsApiConstants.interestRateParamName;
|
||||||
import static org.mifosplatform.portfolio.savings.api.SavingsApiConstants.interestRatePeriodFrequencyTypeParamName;
|
import static org.mifosplatform.portfolio.savings.api.SavingsApiConstants.interestRatePeriodFrequencyTypeParamName;
|
||||||
import static org.mifosplatform.portfolio.savings.api.SavingsApiConstants.lockinPeriodFrequencyParamName;
|
import static org.mifosplatform.portfolio.savings.api.SavingsApiConstants.lockinPeriodFrequencyParamName;
|
||||||
@@ -12,7 +14,11 @@ import static org.mifosplatform.portfolio.savings.api.SavingsApiConstants.lockin
|
|||||||
import static org.mifosplatform.portfolio.savings.api.SavingsApiConstants.minRequiredOpeningBalanceParamName;
|
import static org.mifosplatform.portfolio.savings.api.SavingsApiConstants.minRequiredOpeningBalanceParamName;
|
||||||
|
|
||||||
import java.math.BigDecimal;
|
import java.math.BigDecimal;
|
||||||
|
import java.util.Locale;
|
||||||
|
|
||||||
|
import org.joda.time.LocalDate;
|
||||||
|
import org.joda.time.format.DateTimeFormat;
|
||||||
|
import org.joda.time.format.DateTimeFormatter;
|
||||||
import org.mifosplatform.infrastructure.core.api.JsonCommand;
|
import org.mifosplatform.infrastructure.core.api.JsonCommand;
|
||||||
import org.mifosplatform.infrastructure.core.serialization.FromJsonHelper;
|
import org.mifosplatform.infrastructure.core.serialization.FromJsonHelper;
|
||||||
import org.mifosplatform.portfolio.client.domain.Client;
|
import org.mifosplatform.portfolio.client.domain.Client;
|
||||||
@@ -90,6 +96,9 @@ public class SavingsAccountAssembler {
|
|||||||
interestRate = product.interestRate();
|
interestRate = product.interestRate();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
final boolean active = fromApiJsonHelper.extractBooleanNamed(activeParamName, element);
|
||||||
|
final LocalDate activationDate = fromApiJsonHelper.extractLocalDateNamed(activationDateParamName, element);
|
||||||
|
|
||||||
PeriodFrequencyType interestRatePeriodFrequencyType = null;
|
PeriodFrequencyType interestRatePeriodFrequencyType = null;
|
||||||
Integer interestRatePeriodFrequencyTypeValue = null;
|
Integer interestRatePeriodFrequencyTypeValue = null;
|
||||||
if (command.parameterExists(interestRatePeriodFrequencyTypeParamName)) {
|
if (command.parameterExists(interestRatePeriodFrequencyTypeParamName)) {
|
||||||
@@ -128,11 +137,17 @@ public class SavingsAccountAssembler {
|
|||||||
lockinPeriodFrequencyType = product.lockinPeriodFrequencyType();
|
lockinPeriodFrequencyType = product.lockinPeriodFrequencyType();
|
||||||
}
|
}
|
||||||
|
|
||||||
final SavingsAccount account = SavingsAccount.createNewAccount(client, group, product, accountNo, externalId, interestRate,
|
final SavingsAccount account = SavingsAccount.createNewAccount(client, group, product, accountNo, externalId, active,
|
||||||
interestRatePeriodFrequencyType, annualInterestRate, minRequiredOpeningBalance, lockinPeriodFrequency,
|
activationDate, interestRate, interestRatePeriodFrequencyType, annualInterestRate, minRequiredOpeningBalance,
|
||||||
lockinPeriodFrequencyType);
|
lockinPeriodFrequency, lockinPeriodFrequencyType);
|
||||||
account.setHelpers(this.savingsAccountTransactionSummaryWrapper);
|
account.setHelpers(this.savingsAccountTransactionSummaryWrapper);
|
||||||
|
|
||||||
|
if (account.isActive()) {
|
||||||
|
final Locale locale = command.extractLocale();
|
||||||
|
final DateTimeFormatter formatter = DateTimeFormat.forPattern(command.dateFormat()).withLocale(locale);
|
||||||
|
account.activate(formatter, activationDate);
|
||||||
|
}
|
||||||
|
|
||||||
return account;
|
return account;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
+66
@@ -0,0 +1,66 @@
|
|||||||
|
/**
|
||||||
|
* This Source Code Form is subject to the terms of the Mozilla Public
|
||||||
|
* License, v. 2.0. If a copy of the MPL was not distributed with this file,
|
||||||
|
* You can obtain one at http://mozilla.org/MPL/2.0/.
|
||||||
|
*/
|
||||||
|
package org.mifosplatform.portfolio.savings.domain;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Enum representation of {@link SavingsAccount} status states.
|
||||||
|
*/
|
||||||
|
public enum SavingsAccountStatusType {
|
||||||
|
|
||||||
|
INVALID(0, "savingsAccountStatusType.invalid"), //
|
||||||
|
UNACTIVATED(100, "savingsAccountStatusType.unactivated"), //
|
||||||
|
ACTIVE(300, "savingsAccountStatusType.active"), //
|
||||||
|
CLOSED(600, "savingsAccountStatusType.closed");
|
||||||
|
|
||||||
|
private final Integer value;
|
||||||
|
private final String code;
|
||||||
|
|
||||||
|
public static SavingsAccountStatusType fromInt(final Integer type) {
|
||||||
|
|
||||||
|
SavingsAccountStatusType enumeration = SavingsAccountStatusType.INVALID;
|
||||||
|
switch (type) {
|
||||||
|
case 100:
|
||||||
|
enumeration = SavingsAccountStatusType.UNACTIVATED;
|
||||||
|
break;
|
||||||
|
case 300:
|
||||||
|
enumeration = SavingsAccountStatusType.ACTIVE;
|
||||||
|
break;
|
||||||
|
case 600:
|
||||||
|
enumeration = SavingsAccountStatusType.CLOSED;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
return enumeration;
|
||||||
|
}
|
||||||
|
|
||||||
|
private SavingsAccountStatusType(final Integer value, final String code) {
|
||||||
|
this.value = value;
|
||||||
|
this.code = code;
|
||||||
|
}
|
||||||
|
|
||||||
|
public boolean hasStateOf(final SavingsAccountStatusType state) {
|
||||||
|
return this.value.equals(state.getValue());
|
||||||
|
}
|
||||||
|
|
||||||
|
public Integer getValue() {
|
||||||
|
return this.value;
|
||||||
|
}
|
||||||
|
|
||||||
|
public String getCode() {
|
||||||
|
return code;
|
||||||
|
}
|
||||||
|
|
||||||
|
public boolean isUnactivated() {
|
||||||
|
return this.value.equals(SavingsAccountStatusType.UNACTIVATED.getValue());
|
||||||
|
}
|
||||||
|
|
||||||
|
public boolean isActive() {
|
||||||
|
return this.value.equals(SavingsAccountStatusType.ACTIVE.getValue());
|
||||||
|
}
|
||||||
|
|
||||||
|
public boolean isClosed() {
|
||||||
|
return this.value.equals(SavingsAccountStatusType.CLOSED.getValue());
|
||||||
|
}
|
||||||
|
}
|
||||||
+1
-1
@@ -45,7 +45,7 @@ public final class SavingsAccountSummary {
|
|||||||
|
|
||||||
public boolean isLessThanOrEqualToAccountBalance(final Money amount) {
|
public boolean isLessThanOrEqualToAccountBalance(final Money amount) {
|
||||||
final Money accountBalance = getAccountBalance(amount.getCurrency());
|
final Money accountBalance = getAccountBalance(amount.getCurrency());
|
||||||
return accountBalance.isGreaterThanOrEqualTo(accountBalance);
|
return accountBalance.isGreaterThanOrEqualTo(amount);
|
||||||
}
|
}
|
||||||
|
|
||||||
public Money getAccountBalance(final MonetaryCurrency currency) {
|
public Money getAccountBalance(final MonetaryCurrency currency) {
|
||||||
|
|||||||
-15
@@ -1,15 +0,0 @@
|
|||||||
package org.mifosplatform.portfolio.savings.exception;
|
|
||||||
|
|
||||||
import org.mifosplatform.infrastructure.core.exception.AbstractPlatformDomainRuleException;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Thrown when an attempt is made to withdraw money that is greater than the
|
|
||||||
* account balance.
|
|
||||||
*/
|
|
||||||
public class InvalidSavingsAccountTransactionException extends AbstractPlatformDomainRuleException {
|
|
||||||
|
|
||||||
public InvalidSavingsAccountTransactionException(final String errorCode, final String defaultErrorMessage, final String paramName,
|
|
||||||
final Object... defaultUserMessageArgs) {
|
|
||||||
super("error.msg.savingsaccount.transaction." + errorCode, defaultErrorMessage, paramName, defaultUserMessageArgs);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
+26
@@ -0,0 +1,26 @@
|
|||||||
|
package org.mifosplatform.portfolio.savings.handler;
|
||||||
|
|
||||||
|
import org.mifosplatform.commands.handler.NewCommandSourceHandler;
|
||||||
|
import org.mifosplatform.infrastructure.core.api.JsonCommand;
|
||||||
|
import org.mifosplatform.infrastructure.core.data.CommandProcessingResult;
|
||||||
|
import org.mifosplatform.portfolio.savings.service.SavingsAccountWritePlatformService;
|
||||||
|
import org.springframework.beans.factory.annotation.Autowired;
|
||||||
|
import org.springframework.stereotype.Service;
|
||||||
|
import org.springframework.transaction.annotation.Transactional;
|
||||||
|
|
||||||
|
@Service
|
||||||
|
public class ActivateSavingsAccountCommandHandler implements NewCommandSourceHandler {
|
||||||
|
|
||||||
|
private final SavingsAccountWritePlatformService savingAccountWritePlatformService;
|
||||||
|
|
||||||
|
@Autowired
|
||||||
|
public ActivateSavingsAccountCommandHandler(final SavingsAccountWritePlatformService savingAccountWritePlatformService) {
|
||||||
|
this.savingAccountWritePlatformService = savingAccountWritePlatformService;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Transactional
|
||||||
|
@Override
|
||||||
|
public CommandProcessingResult processCommand(final JsonCommand command) {
|
||||||
|
return this.savingAccountWritePlatformService.activate(command.getSavingsId(), command);
|
||||||
|
}
|
||||||
|
}
|
||||||
+1
-1
@@ -21,6 +21,6 @@ public class DepositSavingsAccountCommandHandler implements NewCommandSourceHand
|
|||||||
@Transactional
|
@Transactional
|
||||||
@Override
|
@Override
|
||||||
public CommandProcessingResult processCommand(final JsonCommand command) {
|
public CommandProcessingResult processCommand(final JsonCommand command) {
|
||||||
return this.savingAccountWritePlatformService.deposit(command.getLoanId(), command);
|
return this.savingAccountWritePlatformService.deposit(command.getSavingsId(), command);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
+1
-1
@@ -21,6 +21,6 @@ public class WithdrawSavingsAccountCommandHandler implements NewCommandSourceHan
|
|||||||
@Transactional
|
@Transactional
|
||||||
@Override
|
@Override
|
||||||
public CommandProcessingResult processCommand(final JsonCommand command) {
|
public CommandProcessingResult processCommand(final JsonCommand command) {
|
||||||
return this.savingAccountWritePlatformService.withdrawal(command.getLoanId(), command);
|
return this.savingAccountWritePlatformService.withdrawal(command.getSavingsId(), command);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
+17
-8
@@ -23,6 +23,7 @@ import org.mifosplatform.portfolio.group.data.GroupData;
|
|||||||
import org.mifosplatform.portfolio.group.service.GroupReadPlatformService;
|
import org.mifosplatform.portfolio.group.service.GroupReadPlatformService;
|
||||||
import org.mifosplatform.portfolio.loanproduct.domain.PeriodFrequencyType;
|
import org.mifosplatform.portfolio.loanproduct.domain.PeriodFrequencyType;
|
||||||
import org.mifosplatform.portfolio.savings.data.SavingsAccountData;
|
import org.mifosplatform.portfolio.savings.data.SavingsAccountData;
|
||||||
|
import org.mifosplatform.portfolio.savings.data.SavingsAccountStatusEnumData;
|
||||||
import org.mifosplatform.portfolio.savings.data.SavingsAccountSummaryData;
|
import org.mifosplatform.portfolio.savings.data.SavingsAccountSummaryData;
|
||||||
import org.mifosplatform.portfolio.savings.data.SavingsAccountTransactionData;
|
import org.mifosplatform.portfolio.savings.data.SavingsAccountTransactionData;
|
||||||
import org.mifosplatform.portfolio.savings.data.SavingsAccountTransactionEnumData;
|
import org.mifosplatform.portfolio.savings.data.SavingsAccountTransactionEnumData;
|
||||||
@@ -92,6 +93,7 @@ public class SavingsAccountReadPlatformServiceImpl implements SavingsAccountRead
|
|||||||
public SavingAccountMapper() {
|
public SavingAccountMapper() {
|
||||||
final StringBuilder sqlBuilder = new StringBuilder(400);
|
final StringBuilder sqlBuilder = new StringBuilder(400);
|
||||||
sqlBuilder.append("sa.id as id, sa.account_no as accountNo, sa.external_id as externalId, ");
|
sqlBuilder.append("sa.id as id, sa.account_no as accountNo, sa.external_id as externalId, ");
|
||||||
|
sqlBuilder.append("sa.status_enum as statusEnum, sa.activation_date as activationDate, ");
|
||||||
sqlBuilder.append("c.id as clientId, c.display_name as clientName, ");
|
sqlBuilder.append("c.id as clientId, c.display_name as clientName, ");
|
||||||
sqlBuilder.append("g.id as groupId, g.name as groupName, ");
|
sqlBuilder.append("g.id as groupId, g.name as groupName, ");
|
||||||
sqlBuilder.append("sp.id as productId, sp.name as productName, ");
|
sqlBuilder.append("sp.id as productId, sp.name as productName, ");
|
||||||
@@ -128,9 +130,14 @@ public class SavingsAccountReadPlatformServiceImpl implements SavingsAccountRead
|
|||||||
final String accountNo = rs.getString("accountNo");
|
final String accountNo = rs.getString("accountNo");
|
||||||
final String externalId = rs.getString("externalId");
|
final String externalId = rs.getString("externalId");
|
||||||
|
|
||||||
final Long groupId = rs.getLong("groupId");
|
final Integer statusEnum = JdbcSupport.getInteger(rs, "statusEnum");
|
||||||
|
final SavingsAccountStatusEnumData status = SavingsEnumerations.status(statusEnum);
|
||||||
|
|
||||||
|
final LocalDate activationDate = JdbcSupport.getLocalDate(rs, "activationDate");
|
||||||
|
|
||||||
|
final Long groupId = JdbcSupport.getLong(rs, "groupId");
|
||||||
final String groupName = rs.getString("groupName");
|
final String groupName = rs.getString("groupName");
|
||||||
final Long clientId = rs.getLong("clientId");
|
final Long clientId = JdbcSupport.getLong(rs, "clientId");
|
||||||
final String clientName = rs.getString("clientName");
|
final String clientName = rs.getString("clientName");
|
||||||
|
|
||||||
final Long productId = rs.getLong("productId");
|
final Long productId = rs.getLong("productId");
|
||||||
@@ -167,9 +174,9 @@ public class SavingsAccountReadPlatformServiceImpl implements SavingsAccountRead
|
|||||||
final SavingsAccountSummaryData summary = new SavingsAccountSummaryData(currency, totalDeposits, totalWithdrawals,
|
final SavingsAccountSummaryData summary = new SavingsAccountSummaryData(currency, totalDeposits, totalWithdrawals,
|
||||||
totalInterestPosted, accountBalance);
|
totalInterestPosted, accountBalance);
|
||||||
|
|
||||||
return SavingsAccountData.instance(id, accountNo, externalId, groupId, groupName, clientId, clientName, productId, productName,
|
return SavingsAccountData.instance(id, accountNo, externalId, status, activationDate, groupId, groupName, clientId, clientName,
|
||||||
currency, interestRate, interestRatePeriodFrequencyType, annualInterestRate, minRequiredOpeningBalance,
|
productId, productName, currency, interestRate, interestRatePeriodFrequencyType, annualInterestRate,
|
||||||
lockinPeriodFrequency, lockinPeriodFrequencyType, summary);
|
minRequiredOpeningBalance, lockinPeriodFrequency, lockinPeriodFrequencyType, summary);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -413,10 +420,12 @@ public class SavingsAccountReadPlatformServiceImpl implements SavingsAccountRead
|
|||||||
groupName = group.getName();
|
groupName = group.getName();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
final SavingsAccountStatusEnumData status = null;
|
||||||
|
final LocalDate activationDate = null;
|
||||||
final SavingsAccountSummaryData summary = null;
|
final SavingsAccountSummaryData summary = null;
|
||||||
return SavingsAccountData.instance(null, null, null, groupId, groupName, clientId, clientName, productId, productName,
|
return SavingsAccountData.instance(null, null, null, status, activationDate, groupId, groupName, clientId, clientName,
|
||||||
currency, interestRate, interestRatePeriodFrequencyType, annualInterestRate, minRequiredOpeningBalance,
|
productId, productName, currency, interestRate, interestRatePeriodFrequencyType, annualInterestRate,
|
||||||
lockinPeriodFrequency, lockinPeriodFrequencyType, summary);
|
minRequiredOpeningBalance, lockinPeriodFrequency, lockinPeriodFrequencyType, summary);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
+2
@@ -16,6 +16,8 @@ public interface SavingsAccountWritePlatformService {
|
|||||||
|
|
||||||
CommandProcessingResult deleteSavingAccount(Long accountId);
|
CommandProcessingResult deleteSavingAccount(Long accountId);
|
||||||
|
|
||||||
|
CommandProcessingResult activate(Long savingsId, JsonCommand command);
|
||||||
|
|
||||||
CommandProcessingResult deposit(Long savingsId, JsonCommand command);
|
CommandProcessingResult deposit(Long savingsId, JsonCommand command);
|
||||||
|
|
||||||
CommandProcessingResult withdrawal(Long savingsId, JsonCommand command);
|
CommandProcessingResult withdrawal(Long savingsId, JsonCommand command);
|
||||||
|
|||||||
+51
-12
@@ -7,9 +7,12 @@ package org.mifosplatform.portfolio.savings.service;
|
|||||||
|
|
||||||
import java.math.BigDecimal;
|
import java.math.BigDecimal;
|
||||||
import java.util.LinkedHashMap;
|
import java.util.LinkedHashMap;
|
||||||
|
import java.util.Locale;
|
||||||
import java.util.Map;
|
import java.util.Map;
|
||||||
|
|
||||||
import org.joda.time.LocalDate;
|
import org.joda.time.LocalDate;
|
||||||
|
import org.joda.time.format.DateTimeFormat;
|
||||||
|
import org.joda.time.format.DateTimeFormatter;
|
||||||
import org.mifosplatform.infrastructure.core.api.JsonCommand;
|
import org.mifosplatform.infrastructure.core.api.JsonCommand;
|
||||||
import org.mifosplatform.infrastructure.core.data.CommandProcessingResult;
|
import org.mifosplatform.infrastructure.core.data.CommandProcessingResult;
|
||||||
import org.mifosplatform.infrastructure.core.data.CommandProcessingResultBuilder;
|
import org.mifosplatform.infrastructure.core.data.CommandProcessingResultBuilder;
|
||||||
@@ -61,8 +64,7 @@ public class SavingsAccountWritePlatformServiceJpaRepositoryImpl implements Savi
|
|||||||
public SavingsAccountWritePlatformServiceJpaRepositoryImpl(final PlatformSecurityContext context,
|
public SavingsAccountWritePlatformServiceJpaRepositoryImpl(final PlatformSecurityContext context,
|
||||||
final SavingsAccountRepositoryWrapper savingAccountRepository,
|
final SavingsAccountRepositoryWrapper savingAccountRepository,
|
||||||
final SavingsAccountTransactionRepository savingsAccountTransactionRepository,
|
final SavingsAccountTransactionRepository savingsAccountTransactionRepository,
|
||||||
final SavingsAccountAssembler savingAccountAssembler,
|
final SavingsAccountAssembler savingAccountAssembler, final SavingsAccountDataValidator savingsAccountDataValidator,
|
||||||
final SavingsAccountDataValidator savingsAccountDataValidator,
|
|
||||||
final SavingsAccountTransactionDataValidator savingsAccountTransactionDataValidator,
|
final SavingsAccountTransactionDataValidator savingsAccountTransactionDataValidator,
|
||||||
final AccountNumberGeneratorFactory accountIdentifierGeneratorFactory, final ClientRepository clientRepository,
|
final AccountNumberGeneratorFactory accountIdentifierGeneratorFactory, final ClientRepository clientRepository,
|
||||||
final GroupRepository groupRepository, final SavingsProductRepository savingsProductRepository) {
|
final GroupRepository groupRepository, final SavingsProductRepository savingsProductRepository) {
|
||||||
@@ -124,30 +126,31 @@ public class SavingsAccountWritePlatformServiceJpaRepositoryImpl implements Savi
|
|||||||
this.savingAccountRepository.save(account);
|
this.savingAccountRepository.save(account);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
final Long savingsId = account.getId();
|
||||||
return new CommandProcessingResultBuilder() //
|
return new CommandProcessingResultBuilder() //
|
||||||
.withCommandId(command.commandId()) //
|
.withCommandId(command.commandId()) //
|
||||||
.withEntityId(account.getId()) //
|
.withEntityId(savingsId) //
|
||||||
.withOfficeId(account.officeId()) //
|
.withOfficeId(account.officeId()) //
|
||||||
.withClientId(account.clientId()) //
|
.withClientId(account.clientId()) //
|
||||||
.withGroupId(account.groupId()) //
|
.withGroupId(account.groupId()) //
|
||||||
|
.withSavingsId(savingsId) //
|
||||||
.build();
|
.build();
|
||||||
} catch (DataAccessException dve) {
|
} catch (DataAccessException dve) {
|
||||||
handleDataIntegrityIssues(command, dve);
|
handleDataIntegrityIssues(command, dve);
|
||||||
return new CommandProcessingResult(Long.valueOf(-1));
|
return new CommandProcessingResult(Long.valueOf(-1));
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@Transactional
|
@Transactional
|
||||||
@Override
|
@Override
|
||||||
public CommandProcessingResult updateSavingAccount(final Long accountId, final JsonCommand command) {
|
public CommandProcessingResult updateSavingAccount(final Long savingsId, final JsonCommand command) {
|
||||||
try {
|
try {
|
||||||
this.context.authenticatedUser();
|
this.context.authenticatedUser();
|
||||||
this.savingsAccountDataValidator.validateForUpdate(command.json());
|
this.savingsAccountDataValidator.validateForUpdate(command.json());
|
||||||
|
|
||||||
final Map<String, Object> changes = new LinkedHashMap<String, Object>(20);
|
final Map<String, Object> changes = new LinkedHashMap<String, Object>(20);
|
||||||
|
|
||||||
final SavingsAccount account = this.savingAccountRepository.findOneWithNotFoundDetection(accountId);
|
final SavingsAccount account = this.savingAccountRepository.findOneWithNotFoundDetection(savingsId);
|
||||||
|
|
||||||
account.update(command, changes);
|
account.update(command, changes);
|
||||||
|
|
||||||
@@ -190,10 +193,11 @@ public class SavingsAccountWritePlatformServiceJpaRepositoryImpl implements Savi
|
|||||||
|
|
||||||
return new CommandProcessingResultBuilder() //
|
return new CommandProcessingResultBuilder() //
|
||||||
.withCommandId(command.commandId()) //
|
.withCommandId(command.commandId()) //
|
||||||
.withEntityId(account.getId()) //
|
.withEntityId(savingsId) //
|
||||||
.withOfficeId(account.officeId()) //
|
.withOfficeId(account.officeId()) //
|
||||||
.withClientId(account.clientId()) //
|
.withClientId(account.clientId()) //
|
||||||
.withGroupId(account.groupId()) //
|
.withGroupId(account.groupId()) //
|
||||||
|
.withSavingsId(savingsId) //
|
||||||
.with(changes) //
|
.with(changes) //
|
||||||
.build();
|
.build();
|
||||||
} catch (DataAccessException dve) {
|
} catch (DataAccessException dve) {
|
||||||
@@ -204,19 +208,46 @@ public class SavingsAccountWritePlatformServiceJpaRepositoryImpl implements Savi
|
|||||||
|
|
||||||
@Transactional
|
@Transactional
|
||||||
@Override
|
@Override
|
||||||
public CommandProcessingResult deleteSavingAccount(final Long accountId) {
|
public CommandProcessingResult deleteSavingAccount(final Long savingsId) {
|
||||||
|
|
||||||
this.context.authenticatedUser();
|
this.context.authenticatedUser();
|
||||||
|
|
||||||
final SavingsAccount account = this.savingAccountRepository.findOneWithNotFoundDetection(accountId);
|
final SavingsAccount account = this.savingAccountRepository.findOneWithNotFoundDetection(savingsId);
|
||||||
|
|
||||||
this.savingAccountRepository.delete(account);
|
this.savingAccountRepository.delete(account);
|
||||||
|
|
||||||
return new CommandProcessingResultBuilder() //
|
return new CommandProcessingResultBuilder() //
|
||||||
.withEntityId(accountId) //
|
.withEntityId(savingsId) //
|
||||||
.withOfficeId(account.officeId()) //
|
.withOfficeId(account.officeId()) //
|
||||||
.withClientId(account.clientId()) //
|
.withClientId(account.clientId()) //
|
||||||
.withGroupId(account.groupId()) //
|
.withGroupId(account.groupId()) //
|
||||||
|
.withSavingsId(savingsId) //
|
||||||
|
.build();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Transactional
|
||||||
|
@Override
|
||||||
|
public CommandProcessingResult activate(final Long savingsId, final JsonCommand command) {
|
||||||
|
|
||||||
|
this.context.authenticatedUser();
|
||||||
|
|
||||||
|
this.savingsAccountTransactionDataValidator.validateActivation(command);
|
||||||
|
|
||||||
|
final SavingsAccount account = this.savingAccountRepository.findOneWithNotFoundDetection(savingsId);
|
||||||
|
|
||||||
|
final Locale locale = command.extractLocale();
|
||||||
|
final DateTimeFormatter fmt = DateTimeFormat.forPattern(command.dateFormat()).withLocale(locale);
|
||||||
|
final LocalDate activationDate = command.localDateValueOfParameterNamed("activationDate");
|
||||||
|
account.activate(fmt, activationDate);
|
||||||
|
|
||||||
|
this.savingAccountRepository.save(account);
|
||||||
|
|
||||||
|
return new CommandProcessingResultBuilder() //
|
||||||
|
.withEntityId(savingsId) //
|
||||||
|
.withOfficeId(account.officeId()) //
|
||||||
|
.withClientId(account.clientId()) //
|
||||||
|
.withGroupId(account.groupId()) //
|
||||||
|
.withSavingsId(savingsId) //
|
||||||
.build();
|
.build();
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -230,10 +261,13 @@ public class SavingsAccountWritePlatformServiceJpaRepositoryImpl implements Savi
|
|||||||
|
|
||||||
final SavingsAccount account = this.savingAccountRepository.findOneWithNotFoundDetection(savingsId);
|
final SavingsAccount account = this.savingAccountRepository.findOneWithNotFoundDetection(savingsId);
|
||||||
|
|
||||||
|
final Locale locale = command.extractLocale();
|
||||||
|
final DateTimeFormatter fmt = DateTimeFormat.forPattern(command.dateFormat()).withLocale(locale);
|
||||||
|
|
||||||
final LocalDate transactionDate = command.localDateValueOfParameterNamed("transactionDate");
|
final LocalDate transactionDate = command.localDateValueOfParameterNamed("transactionDate");
|
||||||
final BigDecimal transactionAmount = command.bigDecimalValueOfParameterNamed("transactionAmount");
|
final BigDecimal transactionAmount = command.bigDecimalValueOfParameterNamed("transactionAmount");
|
||||||
|
|
||||||
final SavingsAccountTransaction deposit = account.deposit(transactionDate, transactionAmount);
|
final SavingsAccountTransaction deposit = account.deposit(fmt, transactionDate, transactionAmount);
|
||||||
final Long transactionId = saveTransactionToGenerateTransactionId(deposit);
|
final Long transactionId = saveTransactionToGenerateTransactionId(deposit);
|
||||||
|
|
||||||
this.savingAccountRepository.save(account);
|
this.savingAccountRepository.save(account);
|
||||||
@@ -258,12 +292,17 @@ public class SavingsAccountWritePlatformServiceJpaRepositoryImpl implements Savi
|
|||||||
|
|
||||||
this.context.authenticatedUser();
|
this.context.authenticatedUser();
|
||||||
|
|
||||||
|
this.savingsAccountTransactionDataValidator.validate(command);
|
||||||
|
|
||||||
final SavingsAccount account = this.savingAccountRepository.findOneWithNotFoundDetection(savingsId);
|
final SavingsAccount account = this.savingAccountRepository.findOneWithNotFoundDetection(savingsId);
|
||||||
|
|
||||||
final LocalDate transactionDate = command.localDateValueOfParameterNamed("transactionDate");
|
final LocalDate transactionDate = command.localDateValueOfParameterNamed("transactionDate");
|
||||||
final BigDecimal transactionAmount = command.bigDecimalValueOfParameterNamed("transactionAmount");
|
final BigDecimal transactionAmount = command.bigDecimalValueOfParameterNamed("transactionAmount");
|
||||||
|
|
||||||
final SavingsAccountTransaction withdrawal = account.withdrawal(transactionDate, transactionAmount);
|
final Locale locale = command.extractLocale();
|
||||||
|
final DateTimeFormatter fmt = DateTimeFormat.forPattern(command.dateFormat()).withLocale(locale);
|
||||||
|
|
||||||
|
final SavingsAccountTransaction withdrawal = account.withdraw(fmt, transactionDate, transactionAmount);
|
||||||
final Long transactionId = saveTransactionToGenerateTransactionId(withdrawal);
|
final Long transactionId = saveTransactionToGenerateTransactionId(withdrawal);
|
||||||
this.savingAccountRepository.save(account);
|
this.savingAccountRepository.save(account);
|
||||||
|
|
||||||
|
|||||||
+33
@@ -7,7 +7,9 @@ package org.mifosplatform.portfolio.savings.service;
|
|||||||
|
|
||||||
import org.mifosplatform.infrastructure.core.data.EnumOptionData;
|
import org.mifosplatform.infrastructure.core.data.EnumOptionData;
|
||||||
import org.mifosplatform.portfolio.loanproduct.domain.PeriodFrequencyType;
|
import org.mifosplatform.portfolio.loanproduct.domain.PeriodFrequencyType;
|
||||||
|
import org.mifosplatform.portfolio.savings.data.SavingsAccountStatusEnumData;
|
||||||
import org.mifosplatform.portfolio.savings.data.SavingsAccountTransactionEnumData;
|
import org.mifosplatform.portfolio.savings.data.SavingsAccountTransactionEnumData;
|
||||||
|
import org.mifosplatform.portfolio.savings.domain.SavingsAccountStatusType;
|
||||||
import org.mifosplatform.portfolio.savings.domain.SavingsAccountTransactionType;
|
import org.mifosplatform.portfolio.savings.domain.SavingsAccountTransactionType;
|
||||||
|
|
||||||
public class SavingsEnumerations {
|
public class SavingsEnumerations {
|
||||||
@@ -103,4 +105,35 @@ public class SavingsEnumerations {
|
|||||||
}
|
}
|
||||||
return optionData;
|
return optionData;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public static SavingsAccountStatusEnumData status(final Integer statusEnum) {
|
||||||
|
return status(SavingsAccountStatusType.fromInt(statusEnum));
|
||||||
|
}
|
||||||
|
|
||||||
|
public static SavingsAccountStatusEnumData status(final SavingsAccountStatusType type) {
|
||||||
|
|
||||||
|
SavingsAccountStatusEnumData optionData = new SavingsAccountStatusEnumData(SavingsAccountStatusType.INVALID.getValue().longValue(),
|
||||||
|
SavingsAccountStatusType.INVALID.getCode(), "Invalid", false, false, false);
|
||||||
|
|
||||||
|
switch (type) {
|
||||||
|
case INVALID:
|
||||||
|
optionData = new SavingsAccountStatusEnumData(SavingsAccountStatusType.INVALID.getValue().longValue(),
|
||||||
|
SavingsAccountStatusType.INVALID.getCode(), "Invalid", type.isUnactivated(), type.isActive(), type.isClosed());
|
||||||
|
break;
|
||||||
|
case UNACTIVATED:
|
||||||
|
optionData = new SavingsAccountStatusEnumData(SavingsAccountStatusType.UNACTIVATED.getValue().longValue(),
|
||||||
|
SavingsAccountStatusType.UNACTIVATED.getCode(), "Unactivated", type.isUnactivated(), type.isActive(),
|
||||||
|
type.isClosed());
|
||||||
|
break;
|
||||||
|
case ACTIVE:
|
||||||
|
optionData = new SavingsAccountStatusEnumData(SavingsAccountStatusType.ACTIVE.getValue().longValue(),
|
||||||
|
SavingsAccountStatusType.ACTIVE.getCode(), "Active", type.isUnactivated(), type.isActive(), type.isClosed());
|
||||||
|
break;
|
||||||
|
case CLOSED:
|
||||||
|
optionData = new SavingsAccountStatusEnumData(SavingsAccountStatusType.CLOSED.getValue().longValue(),
|
||||||
|
SavingsAccountStatusType.CLOSED.getCode(), "Closed", type.isUnactivated(), type.isActive(), type.isClosed());
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
return optionData;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
Reference in New Issue
Block a user