diff --git a/api-docs/apiLive.htm b/api-docs/apiLive.htm index d5b485fc5..75227bd99 100644 --- a/api-docs/apiLive.htm +++ b/api-docs/apiLive.htm @@ -10175,7 +10175,7 @@ Content-Type: application/json
An MFIs savings product offerings are modeled using this API.
-When creating savings accounts, the details from the savings product are used to auto fill details of savings account.
+When creating savings accounts, the details from the savings product are used to auto fill details of the savings account application process.
Field Descriptions | |||||||||||||
| The default interest rate set when creating savings accounts of this type of product. e.g. 5% Per year - It number here is always expressed as the Nominal APR. | |||||||||||||
| interestCompoundingPeriodType | |||||||||||||
| The period at which interest rate is compounded. 1=Daily, 2=Weekly (at end of week, sunday), 3=Every two weeks (at end of two weeks, sunday), 4=Monthly (at end of month), 5=Quarterly (at end of quarter, 31st Mar, 30th Jun, 30th Sep, 31st Dec), 6=Bi-Annually (30th June, 31st Dec), 7=Annually (31st Dec), 8=No Compounding - Simple Interest | |||||||||||||
| The period at which interest rate is compounded. 1=Daily, 4=Monthly (at end of month) | |||||||||||||
| interestPostingPeriodType | |||||||||||||
| The period at which interest rate is posted or credited to savings account. 4=Monthly (at end of month), 5=Quarterly (at end of quarter, 31st Mar, 30th Jun, 30th Sep, 31st Dec) | |||||||||||||
| interestCalculationType | |||||||||||||
| The interest calculation method used: 1=Daily Balance or 2=Average Daily Balance |
| Starting State | +Action | +Resultant State | +
| - | +Submit | +Submitted and pending approval | +
| Submitted and pending approval | +Reject | +Closed - Rejected | +
| Submitted and pending approval | +Withdrawn by Applicant | +Closed - Withdrawn by Applicant | +
| Submitted and pending approval | +Approve | +Approved | +
| Approved | +Undo Approval | +Submitted and pending approval | +
| Approved | +Activate | +Active | +
Field Descriptions | |||||||||||||
| The account no. associated with this loan. Is auto generated if not provided at creation time. | |||||||||||||
| externalId | |||||||||||||
| A place to put an external reference for this savings account e.g. The ID another system uses. If provided, it must be unique. | |||||||||||||
| A place to put an external reference for this savings account useful in migrations e.g. The ID another system uses. If provided, it must be unique. | |||||||||||||
| active | |||||||||||||
| Indicates whether this savings account should go into active state or not automatically | |||||||||||||
| activationDate | |||||||||||||
| If active is true the activationDate must be provided. If the savings account has an entry for minRequiredOpeningBalance then a deposit for that amount with activationDate as the date is automatically entered. | |||||||||||||
| submittedOnDate | |||||||||||||
| submittedOnDate must be provided when initially creating savings account application. locale and dateFormat parameters must be provided with this. | |||||||||||||
| nominalAnnualInterestRate | |||||||||||||
| The interest rate set for savings account e.g. 5% Per year - It is always expressed as the Nominal APR. | |||||||||||||
| interestCompoundingPeriodType | |||||||||||||
| The period at which interest rate is compounded. 1=Daily, 2=Weekly (at end of week, sunday), 3=Every two weeks (at end of two weeks, sunday), 4=Monthly (at end of month), 5=Quarterly (at end of quarter, 31st Mar, 30th Jun, 30th Sep, 31st Dec), 6=Bi-Annually (30th June, 31st Dec), 7=Annually (31st Dec), 8=No Compounding - Simple Interest | |||||||||||||
| interestCompoundingPeriodType | |||||||||||||
| The period at which interest rate is compounded. 1=Daily, 4=Monthly (at end of month) | |||||||||||||
| interestPostingPeriodType | |||||||||||||
| The period at which interest rate is posted or credited to savings account. The actual crediting or posting transaction is date as occurring on the day after the end of the period. 4=Monthly (at end of month), 5=Quarterly (at end of quarter, 31st Mar, 30th Jun, 30th Sep, 31st Dec), 7=Annually (at end of calendar year 31st Dec) | |||||||||||||
| interestCalculationType | |||||||||||||
| The interest calculation method used: 1=Daily Balance or 2=Average Daily Balance |
Mandatory Fields |
| clientId or groupId, productId, accountNo, externalId, - active, (activationDate if active is true) |
| clientId or groupId, productId, submittedOnDate |
Optional Fields |
| accountNo, externalId |
| accountNo, externalId, fieldOfficerId |
Inherited from Product (if not provided) |
| nominalAnnualInterestRate, interestCompoundingPeriodType, interestCalculationType, interestCalculationDaysInYearType, minRequiredOpeningBalance, lockinPeriodFrequency, - lockinPeriodFrequencyType, withdrawalFeeAmount, withdrawalFeeType, annualFeeAmount, annualFeeOnMonthDay | +
| nominalAnnualInterestRate, interestCompoundingPeriodType, interestCalculationType, interestCalculationDaysInYearType, minRequiredOpeningBalance, lockinPeriodFrequency, lockinPeriodFrequencyType, withdrawalFeeAmount, withdrawalFeeType, annualFeeAmount, annualFeeOnMonthDay |
Minimal request: accountNo provided (must be unique), remaining details inherited from savings product.
@@ -11295,7 +11358,9 @@ Request Body: { "clientId": 1, "productId": 1, - "active": false, + "locale": "en", + "dateFormat": "dd MMMM yyyy", + "submittedOnDate": "01 March 2011", "accountNo": "SA000023", "externalId": "SYS-23" } @@ -11307,14 +11372,17 @@ Request Body: { "clientId": 1, "productId": 1, + "fieldOfficerId": 1, + "locale": "en", + "dateFormat": "dd MMMM yyyy", + "submittedOnDate": "01 March 2013", "accountNo": "SA000023", "externalId": "SYS-23", - "active": true, - "locale": "en", - "dateFormat": "dd MMMM yyyy", - "activationDate": "01 March 2011", - "interestRate": "5.65", - "interestRatePeriodFrequencyType": 2, + "nominalAnnualInterestRate": "5.65", + "interestCompoundingPeriodType": 1, + "interestPostingPeriodType": 4, + "interestCalculationType": 1, + "interestCalculationDaysInYearType": 365, "minRequiredOpeningBalance": "1,000", "lockinPeriodFrequency": 6, "lockinPeriodFrequencyType": 2 @@ -11322,7 +11390,7 @@ Request Body:
{
- "officeId": 1,
+ "officeId": 2,
"clientId": 1,
"savingsId": 1,
"resourceId": 1
@@ -11331,11 +11399,184 @@ Request Body:
Approves savings application so long as its in 'Submitted and pending approval' state.
+POST https://Domain Name/api/v1/savingsaccounts/{savingsId}?command=approve
+ POST savingsaccount/1?command=approve
+Content-Type: application/json
+Request Body:
+{
+ "locale": "en",
+ "dateFormat": "dd MMMM yyyy",
+ "approvedOnDate": "01 March 2013"
+}
+
+
+{
+ "officeId": 2,
+ "clientId": 1,
+ "savingsId": 1,
+ "resourceId": 1,
+ "changes": {
+ "status": {
+ "id": 200,
+ "code": "savingsAccountStatusType.approved",
+ "value": "Approved",
+ "submittedAndPendingApproval": false,
+ "approved": true,
+ "rejected": false,
+ "withdrawnByApplicant": false,
+ "active": false,
+ "closed": false
+ },
+ "locale": "en",
+ "dateFormat": "dd MMMM yyyy",
+ "approvedOnDate": "02 March 2013"
+ }
+}
+
+ Will move 'approved' savings application back to 'Submitted and pending approval' state.
+POST https://Domain Name/api/v1/savingsaccounts/{savingsId}?command=undoApproval
+ POST savingsaccount/1?command=undoApproval
+Content-Type: application/json
+Request Body:
+{
+}
+
+
+{
+ "officeId": 2,
+ "clientId": 1,
+ "savingsId": 1,
+ "resourceId": 1,
+ "changes": {
+ "status": {
+ "id": 100,
+ "code": "savingsAccountStatusType.submitted.and.pending.approval",
+ "value": "Submitted and pending approval",
+ "submittedAndPendingApproval": true,
+ "approved": false,
+ "rejected": false,
+ "withdrawnByApplicant": false,
+ "active": false,
+ "closed": false
+ },
+ "approvedOnDate": ""
+ }
+}
+
+ Rejects savings application so long as its in 'Submitted and pending approval' state.
+POST https://Domain Name/api/v1/savingsaccounts/{savingsId}?command=reject
+ POST savingsaccount/1?command=reject
+Content-Type: application/json
+Request Body:
+{
+ "locale": "en",
+ "dateFormat": "dd MMMM yyyy",
+ "rejectedOnDate": "03 March 2013"
+}
+
+
+{
+ "officeId": 2,
+ "clientId": 1,
+ "savingsId": 1,
+ "resourceId": 1,
+ "changes": {
+ "status": {
+ "id": 500,
+ "code": "savingsAccountStatusType.rejected",
+ "value": "Rejected",
+ "submittedAndPendingApproval": false,
+ "approved": false,
+ "rejected": true,
+ "withdrawnByApplicant": false,
+ "active": false,
+ "closed": true
+ },
+ "locale": "en",
+ "dateFormat": "dd MMMM yyyy",
+ "rejectedOnDate": "03 March 2013",
+ "closedOnDate": "03 March 2013"
+ }
+}
+
+ Used when an applicant withdraws from the savings application. It must be in 'Submitted and pending approval' state.
+POST https://Domain Name/api/v1/savingsaccounts/{savingsId}?command=withdrawnByApplicant
+ POST savingsaccount/1?command=withdrawnByApplicant
+Content-Type: application/json
+Request Body:
+{
+ "locale": "en",
+ "dateFormat": "dd MMMM yyyy",
+ "withdrawnOnDate": "03 March 2013"
+}
+
+
+{
+ "officeId": 2,
+ "clientId": 1,
+ "savingsId": 1,
+ "resourceId": 1,
+ "changes": {
+ "status": {
+ "id": 400,
+ "code": "savingsAccountStatusType.withdrawn.by.applicant",
+ "value": "Withdrawn by applicant",
+ "submittedAndPendingApproval": false,
+ "approved": false,
+ "rejected": false,
+ "withdrawnByApplicant": true,
+ "active": false,
+ "closed": true
+ },
+ "locale": "en",
+ "dateFormat": "dd MMMM yyyy",
+ "withdrawnOnDate": "03 March 2013",
+ "closedOnDate": "03 March 2013"
+ }
+}
+
+ Activates a savings account.
+Results in an approved savings application being converted into an 'active' savings account.
POST https://Domain Name/api/v1/savingsaccounts/{savingsId}?command=activate
@@ -11345,15 +11586,31 @@ Request Body:
{
"locale": "en",
"dateFormat": "dd MMMM yyyy",
- "activationDate": "01 March 2011"
+ "activatedOnDate": "01 March 2013"
}
{
- "officeId": 1,
+ "officeId": 2,
"clientId": 1,
"savingsId": 1,
- "resourceId": 1
+ "resourceId": 1,
+ "changes": {
+ "status": {
+ "id": 300,
+ "code": "savingsAccountStatusType.active",
+ "value": "Active",
+ "submittedAndPendingApproval": false,
+ "approved": false,
+ "rejected": false,
+ "withdrawnByApplicant": false,
+ "active": true,
+ "closed": false
+ },
+ "locale": "en",
+ "dateFormat": "dd MMMM yyyy",
+ "activatedOnDate": "01 March 2013"
+ }
}
Example Requests:
GET https://Domain Name/api/v1/savingsaccounts
-[
- {
- "id": 1,
- "accountNo": "SA000023",
- "externalId": "SYS-23",
- "groupId": 0,
- "clientId": 1,
- "clientName": "Client A AB",
- "savingsProductId": 1,
- "savingsProductName": "First",
- "currency": {
- "code": "USD",
- "name": "US Dollar",
- "decimalPlaces": 2,
- "displaySymbol": "$",
- "nameCode": "currency.USD",
- "displayLabel": "US Dollar ($)"
- },
- "interestRate": 5.65,
- "interestRatePeriodFrequencyType": {
- "id": 2,
- "code": "savings.interest.rate.periodFrequencyType.months",
- "value": "Per month"
- },
- "annualInterestRate": 67.8,
- "minRequiredOpeningBalance": 1000,
- "lockinPeriodFrequency": 6,
- "lockinPeriodFrequencyType": {
- "id": 2,
- "code": "savings.interest.rate.periodFrequencyType.months",
- "value": "Per month"
+{
+ "totalFilteredRecords": 1,
+ "pageItems": [
+ {
+ "id": 1,
+ "accountNo": "000000001",
+ "clientId": 1,
+ "clientName": "small business",
+ "savingsProductId": 1,
+ "savingsProductName": "Passbook Savings",
+ "fieldOfficerId": 0,
+ "status": {
+ "id": 100,
+ "code": "savingsAccountStatusType.submitted.and.pending.approval",
+ "value": "Submitted and pending approval",
+ "submittedAndPendingApproval": true,
+ "approved": false,
+ "rejected": false,
+ "withdrawnByApplicant": false,
+ "active": false,
+ "closed": false
+ },
+ "timeline": {
+ "submittedOnDate": [
+ 2013,
+ 3,
+ 1
+ ]
+ },
+ "currency": {
+ "code": "USD",
+ "name": "US Dollar",
+ "decimalPlaces": 2,
+ "displaySymbol": "$",
+ "nameCode": "currency.USD",
+ "displayLabel": "US Dollar ($)"
+ },
+ "nominalAnnualInterestRate": 5,
+ "interestCompoundingPeriodType": {
+ "id": 1,
+ "code": "savings.interest.period.savingsCompoundingInterestPeriodType.daily",
+ "value": "Daily"
+ },
+ "interestPostingPeriodType": {
+ "id": 4,
+ "code": "savings.interest.posting.period.savingsPostingInterestPeriodType.monthly",
+ "value": "Monthly"
+ },
+ "interestCalculationType": {
+ "id": 1,
+ "code": "savingsInterestCalculationType.dailybalance",
+ "value": "Daily Balance"
+ },
+ "interestCalculationDaysInYearType": {
+ "id": 365,
+ "code": "savingsInterestCalculationDaysInYearType.days365",
+ "value": "365 Days"
+ },
+ "summary": {
+ "currency": {
+ "code": "USD",
+ "name": "US Dollar",
+ "decimalPlaces": 2,
+ "displaySymbol": "$",
+ "nameCode": "currency.USD",
+ "displayLabel": "US Dollar ($)"
+ },
+ "accountBalance": 0
+ }
}
- }
-]
+ ]
+}
{
"id": 1,
- "accountNo": "000000002",
- "groupId": 0,
+ "accountNo": "000000001",
"clientId": 1,
- "clientName": "Test b Client",
+ "clientName": "small business",
"savingsProductId": 1,
- "savingsProductName": "individual savings",
+ "savingsProductName": "Passbook Savings",
+ "fieldOfficerId": 0,
+ "status": {
+ "id": 100,
+ "code": "savingsAccountStatusType.submitted.and.pending.approval",
+ "value": "Submitted and pending approval",
+ "submittedAndPendingApproval": true,
+ "approved": false,
+ "rejected": false,
+ "withdrawnByApplicant": false,
+ "active": false,
+ "closed": false
+ },
+ "timeline": {
+ "submittedOnDate": [
+ 2013,
+ 3,
+ 1
+ ]
+ },
"currency": {
"code": "USD",
"name": "US Dollar",
@@ -11499,13 +11812,27 @@ Request Body:
"nameCode": "currency.USD",
"displayLabel": "US Dollar ($)"
},
- "interestRate": 9.8,
- "interestRatePeriodFrequencyType": {
- "id": 3,
- "code": "savings.interest.rate.periodFrequencyType.years",
- "value": "Per year"
+ "nominalAnnualInterestRate": 5,
+ "interestCompoundingPeriodType": {
+ "id": 1,
+ "code": "savings.interest.period.savingsCompoundingInterestPeriodType.daily",
+ "value": "Daily"
+ },
+ "interestPostingPeriodType": {
+ "id": 4,
+ "code": "savings.interest.posting.period.savingsPostingInterestPeriodType.monthly",
+ "value": "Monthly"
+ },
+ "interestCalculationType": {
+ "id": 1,
+ "code": "savingsInterestCalculationType.dailybalance",
+ "value": "Daily Balance"
+ },
+ "interestCalculationDaysInYearType": {
+ "id": 365,
+ "code": "savingsInterestCalculationDaysInYearType.days365",
+ "value": "365 Days"
},
- "annualInterestRate": 9.8,
"summary": {
"currency": {
"code": "USD",
@@ -11515,9 +11842,7 @@ Request Body:
"nameCode": "currency.USD",
"displayLabel": "US Dollar ($)"
},
- "totalDeposits": 456.67,
- "totalWithdrawals": 173,
- "accountBalance": 283.67
+ "accountBalance": 0
}
}
@@ -11527,9 +11852,8 @@ Request Body:
Will most likely have a restriction to only allow 'inactive' savings accounts to be updated.
-As other updates like change of interest rate are possibly special cases for savings.
+Savings application can only be modified when in 'Submitted and pending approval' state. Once the application is approved, the details cannot be changed using this method. Specific api endpoints will be created to allow change of interest detail such as rate, compounding period, posting period etc
PUT https://Domain Name/api/v1/savingsaccounts/{accountsId}
@@ -11538,16 +11862,17 @@ Content-Type: application/json
No Request Body:
{
"locale": "en",
- "interestRate": "5.2323"
+ "nominalAnnualInterestRate": "5.65",
}
{
- "officeId": 1,
+ "officeId": 2,
"clientId": 1,
+ "savingsId": 1,
"resourceId": 1,
"changes": {
- "interestRate": 5.2323,
+ "nominalAnnualInterestRate": 5.9999999999,
"locale": "en"
}
}
@@ -11558,8 +11883,8 @@ No Request Body:
- Delete a Savings Account
- At present we support hard delete of savings account but this is likely to change to a savings account closure or De-activation process/command.
+ Delete a savings application
+ At present we support hard delete of savings application so long as its in 'Submitted and pending approval' state. One the application is moves past this state, it is not possible to do a 'hard' delete of the application or the account. An API endpoint will be added to close/de-activate the savings account.
DELETE https://Domain Name/api/v1/savingsaccounts/{accountsId}
@@ -16786,15 +17111,15 @@ GET https://DomainName/api/v1/search?query=000000111
savingsproducts/{productId}
- Retrieve a Savings product
- Update a Savings product
- Delete a Savings product
+ Retrieve a savings product
+ Update a savings product
+ Delete a savings product
Savings Accounts
savingsaccounts
- Create new Savings Account
- List Savings Accounts
+ Submit new savings application
+ List savings application/accounts
@@ -16802,7 +17127,7 @@ GET https://DomainName/api/v1/search?query=000000111
savingsaccounts/template?clientId={clientId}
- Retrieve Savings Account Template
+ Retrieve savings template
@@ -16810,14 +17135,46 @@ GET https://DomainName/api/v1/search?query=000000111
savingsaccounts/{accountId}
- Retrieve a Savings Account
- Update a Savings Account
- Delete a Savings Account
+ Retrieve a savings application/account
+ Modify a savings application
+ Delete a savings application
+
+
+
+ savingsaccounts/{accountId}?command=approve
+ Approve a savings application
+
+
+
+
+
+
+ savingsaccounts/{accountId}?command=undoApproval
+ Undo savings application approval
+
+
+
+
+
+
+ savingsaccounts/{accountId}?command=reject
+ Reject a savings application
+
+
+
+
+
+
+ savingsaccounts/{accountId}?command=withdraw
+ Withdraw savings application
+
+
+
savingsaccounts/{accountId}?command=activate
- Activate a Savings Account
+ Activate a savings account
@@ -16825,7 +17182,7 @@ GET https://DomainName/api/v1/search?query=000000111
savingsaccounts/{accountId}?command=calculateInterest
- Calculate Interest on a Savings Account
+ Calculate interest on a savings account
@@ -16833,7 +17190,7 @@ GET https://DomainName/api/v1/search?query=000000111
savingsaccounts/{accountId}?command=postInterest
- Post Interest on a Savings Account
+ Post interest on a savings account
@@ -16842,14 +17199,14 @@ GET https://DomainName/api/v1/search?query=000000111
savingsaccounts/{accountId}/transactions/template
- Retrieve Savings Account Transaction Template
+ Retrieve savings account transaction template
Savings Transactions
savingsaccounts/{accountId}/transactions?command=deposit
- Make a Deposit
+ Make a deposit
@@ -16857,7 +17214,7 @@ GET https://DomainName/api/v1/search?query=000000111
savingsaccounts/{accountId}/transactions?command=withdrawal
- Make a Withdrawal
+ Make a withdrawal
diff --git a/mifosng-provider/src/main/java/org/mifosplatform/portfolio/savings/SavingsApiConstants.java b/mifosng-provider/src/main/java/org/mifosplatform/portfolio/savings/SavingsApiConstants.java
index cd0746793..baa0f9d04 100644
--- a/mifosng-provider/src/main/java/org/mifosplatform/portfolio/savings/SavingsApiConstants.java
+++ b/mifosng-provider/src/main/java/org/mifosplatform/portfolio/savings/SavingsApiConstants.java
@@ -27,6 +27,7 @@ public class SavingsApiConstants {
public static String withdrawnByApplicantAction = ".withdrawnByApplicant";
public static String activateAction = ".activate";
public static String modifyApplicationAction = ".modify";
+ public static String deleteApplicationAction = ".delete";
// general
public static final String localeParamName = "locale";
diff --git a/mifosng-provider/src/main/java/org/mifosplatform/portfolio/savings/data/SavingsAccountDataValidator.java b/mifosng-provider/src/main/java/org/mifosplatform/portfolio/savings/data/SavingsAccountDataValidator.java
index 64ea723eb..45f5842d1 100644
--- a/mifosng-provider/src/main/java/org/mifosplatform/portfolio/savings/data/SavingsAccountDataValidator.java
+++ b/mifosng-provider/src/main/java/org/mifosplatform/portfolio/savings/data/SavingsAccountDataValidator.java
@@ -85,9 +85,7 @@ public class SavingsAccountDataValidator {
baseDataValidator.reset().parameter(productIdParamName).value(productId).notNull().integerGreaterThanZero();
final LocalDate submittedOnDate = fromApiJsonHelper.extractLocalDateNamed(submittedOnDateParamName, element);
- if (submittedOnDate == null) {
- baseDataValidator.reset().parameter(submittedOnDateParamName).value(submittedOnDate).notNull();
- }
+ baseDataValidator.reset().parameter(submittedOnDateParamName).value(submittedOnDate).notNull();
if (fromApiJsonHelper.parameterExists(accountNoParamName, element)) {
final String accountNo = fromApiJsonHelper.extractStringNamed(accountNoParamName, element);
@@ -264,6 +262,11 @@ public class SavingsAccountDataValidator {
baseDataValidator.reset().parameter(productIdParamName).value(productId).notNull().integerGreaterThanZero();
}
+ if (fromApiJsonHelper.parameterExists(submittedOnDateParamName, element)) {
+ final LocalDate submittedOnDate = fromApiJsonHelper.extractLocalDateNamed(submittedOnDateParamName, element);
+ baseDataValidator.reset().parameter(submittedOnDateParamName).value(submittedOnDate).notNull();
+ }
+
if (fromApiJsonHelper.parameterExists(accountNoParamName, element)) {
final String accountNo = fromApiJsonHelper.extractStringNamed(accountNoParamName, element);
baseDataValidator.reset().parameter(accountNoParamName).value(accountNo).notBlank().notExceedingLengthOf(20);
diff --git a/mifosng-provider/src/main/java/org/mifosplatform/portfolio/savings/domain/SavingsAccount.java b/mifosng-provider/src/main/java/org/mifosplatform/portfolio/savings/domain/SavingsAccount.java
index 9c7d1ff26..380a0d114 100644
--- a/mifosng-provider/src/main/java/org/mifosplatform/portfolio/savings/domain/SavingsAccount.java
+++ b/mifosng-provider/src/main/java/org/mifosplatform/portfolio/savings/domain/SavingsAccount.java
@@ -98,7 +98,6 @@ public class SavingsAccount extends AbstractPersistable {
@JoinColumn(name = "product_id", nullable = false)
private SavingsProduct product;
- @SuppressWarnings("unused")
@ManyToOne
@JoinColumn(name = "field_officer_id", nullable = true)
private Staff fieldOfficer;
@@ -343,6 +342,14 @@ public class SavingsAccount extends AbstractPersistable {
return SavingsAccountStatusType.fromInt(this.status).isActive();
}
+ public boolean isNotSubmittedAndPendingApproval() {
+ return !isSubmittedAndPendingApproval();
+ }
+
+ public boolean isSubmittedAndPendingApproval() {
+ return SavingsAccountStatusType.fromInt(this.status).isSubmittedAndPendingApproval();
+ }
+
public void postInterest(final SavingsHelper savingsHelper, final MathContext mc, final LocalDate interestPostingUpToDate,
final List existingTransactionIds, final List existingReversedTransactionIds) {
@@ -876,6 +883,11 @@ public class SavingsAccount extends AbstractPersistable {
actualChanges.put(SavingsApiConstants.productIdParamName, newValue);
}
+ if (command.isChangeInLongParameterNamed(SavingsApiConstants.fieldOfficerIdParamName, fieldOfficerId())) {
+ final Long newValue = command.longValueOfParameterNamed(SavingsApiConstants.fieldOfficerIdParamName);
+ actualChanges.put(SavingsApiConstants.fieldOfficerIdParamName, newValue);
+ }
+
if (command.isChangeInBigDecimalParameterNamed(SavingsApiConstants.nominalAnnualInterestRateParamName,
this.nominalAnnualInterestRate)) {
final BigDecimal newValue = command.bigDecimalValueOfParameterNamed(SavingsApiConstants.nominalAnnualInterestRateParamName);
@@ -884,6 +896,34 @@ public class SavingsAccount extends AbstractPersistable {
this.nominalAnnualInterestRate = newValue;
}
+ if (command.isChangeInIntegerParameterNamed(SavingsApiConstants.interestCompoundingPeriodTypeParamName,
+ this.interestCompoundingPeriodType)) {
+ final Integer newValue = command.integerValueOfParameterNamed(SavingsApiConstants.interestCompoundingPeriodTypeParamName);
+ this.interestCompoundingPeriodType = newValue != null ? SavingsCompoundingInterestPeriodType.fromInt(newValue).getValue()
+ : newValue;
+ actualChanges.put(SavingsApiConstants.interestCompoundingPeriodTypeParamName, this.interestCompoundingPeriodType);
+ }
+
+ if (command.isChangeInIntegerParameterNamed(SavingsApiConstants.interestPostingPeriodTypeParamName, this.interestPostingPeriodType)) {
+ final Integer newValue = command.integerValueOfParameterNamed(SavingsApiConstants.interestPostingPeriodTypeParamName);
+ this.interestPostingPeriodType = newValue != null ? SavingsPostingInterestPeriodType.fromInt(newValue).getValue() : newValue;
+ actualChanges.put(SavingsApiConstants.interestPostingPeriodTypeParamName, this.interestPostingPeriodType);
+ }
+
+ if (command.isChangeInIntegerParameterNamed(SavingsApiConstants.interestCalculationTypeParamName, this.interestCalculationType)) {
+ final Integer newValue = command.integerValueOfParameterNamed(SavingsApiConstants.interestCalculationTypeParamName);
+ this.interestCalculationType = newValue != null ? SavingsInterestCalculationType.fromInt(newValue).getValue() : newValue;
+ actualChanges.put(SavingsApiConstants.interestCalculationTypeParamName, this.interestCalculationType);
+ }
+
+ if (command.isChangeInIntegerParameterNamed(SavingsApiConstants.interestCalculationDaysInYearTypeParamName,
+ this.interestCalculationDaysInYearType)) {
+ final Integer newValue = command.integerValueOfParameterNamed(SavingsApiConstants.interestCalculationDaysInYearTypeParamName);
+ this.interestCalculationDaysInYearType = newValue != null ? SavingsInterestCalculationDaysInYearType.fromInt(newValue)
+ .getValue() : newValue;
+ actualChanges.put(SavingsApiConstants.interestCalculationDaysInYearTypeParamName, this.interestCalculationDaysInYearType);
+ }
+
if (command.isChangeInBigDecimalParameterNamedDefaultingZeroToNull(SavingsApiConstants.minRequiredOpeningBalanceParamName,
this.minRequiredOpeningBalance)) {
final BigDecimal newValue = command
@@ -1098,6 +1138,10 @@ public class SavingsAccount extends AbstractPersistable {
this.product = product;
}
+ public void update(final Staff fieldOfficer) {
+ this.fieldOfficer = fieldOfficer;
+ }
+
public void updateAccountNo(final String newAccountNo) {
this.accountNumber = newAccountNo;
this.accountNumberRequiresAutoGeneration = false;
@@ -1145,6 +1189,14 @@ public class SavingsAccount extends AbstractPersistable {
return id;
}
+ public Long fieldOfficerId() {
+ Long id = null;
+ if (this.fieldOfficer != null) {
+ id = this.fieldOfficer.getId();
+ }
+ return id;
+ }
+
public MonetaryCurrency getCurrency() {
return this.currency;
}
diff --git a/mifosng-provider/src/main/java/org/mifosplatform/portfolio/savings/service/SavingsApplicationProcessWritePlatformServiceJpaRepositoryImpl.java b/mifosng-provider/src/main/java/org/mifosplatform/portfolio/savings/service/SavingsApplicationProcessWritePlatformServiceJpaRepositoryImpl.java
index ed5bd7846..213580cd3 100644
--- a/mifosng-provider/src/main/java/org/mifosplatform/portfolio/savings/service/SavingsApplicationProcessWritePlatformServiceJpaRepositoryImpl.java
+++ b/mifosng-provider/src/main/java/org/mifosplatform/portfolio/savings/service/SavingsApplicationProcessWritePlatformServiceJpaRepositoryImpl.java
@@ -5,6 +5,8 @@
*/
package org.mifosplatform.portfolio.savings.service;
+import static org.mifosplatform.portfolio.savings.SavingsApiConstants.SAVINGS_ACCOUNT_RESOURCE_NAME;
+
import java.util.ArrayList;
import java.util.LinkedHashMap;
import java.util.List;
@@ -13,14 +15,19 @@ import java.util.Map;
import org.apache.commons.lang.StringUtils;
import org.mifosplatform.accounting.journalentry.service.JournalEntryWritePlatformService;
import org.mifosplatform.infrastructure.core.api.JsonCommand;
+import org.mifosplatform.infrastructure.core.data.ApiParameterError;
import org.mifosplatform.infrastructure.core.data.CommandProcessingResult;
import org.mifosplatform.infrastructure.core.data.CommandProcessingResultBuilder;
+import org.mifosplatform.infrastructure.core.data.DataValidatorBuilder;
+import org.mifosplatform.infrastructure.core.exception.PlatformApiDataValidationException;
import org.mifosplatform.infrastructure.core.exception.PlatformDataIntegrityException;
import org.mifosplatform.infrastructure.core.service.DateUtils;
import org.mifosplatform.infrastructure.security.service.PlatformSecurityContext;
import org.mifosplatform.organisation.monetary.domain.ApplicationCurrency;
import org.mifosplatform.organisation.monetary.domain.ApplicationCurrencyRepositoryWrapper;
import org.mifosplatform.organisation.monetary.domain.MonetaryCurrency;
+import org.mifosplatform.organisation.staff.domain.Staff;
+import org.mifosplatform.organisation.staff.domain.StaffRepositoryWrapper;
import org.mifosplatform.portfolio.client.domain.AccountNumberGenerator;
import org.mifosplatform.portfolio.client.domain.AccountNumberGeneratorFactory;
import org.mifosplatform.portfolio.client.domain.Client;
@@ -60,6 +67,7 @@ public class SavingsApplicationProcessWritePlatformServiceJpaRepositoryImpl impl
private final GroupRepository groupRepository;
private final SavingsProductRepository savingsProductRepository;
private final NoteRepository noteRepository;
+ private final StaffRepositoryWrapper staffRepository;
private final SavingsAccountApplicationTransitionApiJsonValidator savingsAccountApplicationTransitionApiJsonValidator;
private final ApplicationCurrencyRepositoryWrapper applicationCurrencyRepositoryWrapper;
private final JournalEntryWritePlatformService journalEntryWritePlatformService;
@@ -70,7 +78,7 @@ public class SavingsApplicationProcessWritePlatformServiceJpaRepositoryImpl impl
final SavingsAccountDataValidator savingsAccountDataValidator,
final AccountNumberGeneratorFactory accountIdentifierGeneratorFactory, final ClientRepositoryWrapper clientRepository,
final GroupRepository groupRepository, final SavingsProductRepository savingsProductRepository,
- final NoteRepository noteRepository,
+ final NoteRepository noteRepository, final StaffRepositoryWrapper staffRepository,
final SavingsAccountApplicationTransitionApiJsonValidator savingsAccountApplicationTransitionApiJsonValidator,
final ApplicationCurrencyRepositoryWrapper applicationCurrencyRepositoryWrapper,
final JournalEntryWritePlatformService journalEntryWritePlatformService) {
@@ -83,6 +91,7 @@ public class SavingsApplicationProcessWritePlatformServiceJpaRepositoryImpl impl
this.groupRepository = groupRepository;
this.savingsProductRepository = savingsProductRepository;
this.noteRepository = noteRepository;
+ this.staffRepository = staffRepository;
this.savingsAccountApplicationTransitionApiJsonValidator = savingsAccountApplicationTransitionApiJsonValidator;
this.applicationCurrencyRepositoryWrapper = applicationCurrencyRepositoryWrapper;
this.journalEntryWritePlatformService = journalEntryWritePlatformService;
@@ -198,6 +207,13 @@ public class SavingsApplicationProcessWritePlatformServiceJpaRepositoryImpl impl
account.update(product);
}
+ if (changes.containsKey(SavingsApiConstants.fieldOfficerIdParamName)) {
+ final Long fieldOfficerId = command.longValueOfParameterNamed(SavingsApiConstants.fieldOfficerIdParamName);
+ final Staff fieldOfficer = this.staffRepository.findOneWithNotFoundDetection(fieldOfficerId);
+
+ account.update(fieldOfficer);
+ }
+
this.savingAccountRepository.saveAndFlush(account);
}
@@ -220,10 +236,19 @@ public class SavingsApplicationProcessWritePlatformServiceJpaRepositoryImpl impl
@Override
public CommandProcessingResult deleteApplication(final Long savingsId) {
- this.context.authenticatedUser();
-
final SavingsAccount account = this.savingAccountRepository.findOneWithNotFoundDetection(savingsId);
+ if (account.isNotSubmittedAndPendingApproval()) {
+ final List dataValidationErrors = new ArrayList();
+ final DataValidatorBuilder baseDataValidator = new DataValidatorBuilder(dataValidationErrors)
+ .resource(SAVINGS_ACCOUNT_RESOURCE_NAME + SavingsApiConstants.deleteApplicationAction);
+
+ baseDataValidator.reset().parameter(SavingsApiConstants.activatedOnDateParamName)
+ .failWithCodeNoParameterAddedToErrorCode("not.in.submittedandpendingapproval.state");
+
+ if (!dataValidationErrors.isEmpty()) { throw new PlatformApiDataValidationException(dataValidationErrors); }
+ }
+
List relatedNotes = this.noteRepository.findBySavingsAccountId(savingsId);
this.noteRepository.deleteInBatch(relatedNotes);