MIFOSX-541: add application process around savings accounts.
This commit is contained in:
@@ -0,0 +1,69 @@
|
||||
ALTER TABLE `m_note`
|
||||
ADD COLUMN `savings_account_id` BIGINT(20) NULL DEFAULT NULL AFTER `loan_transaction_id`,
|
||||
ADD COLUMN `savings_account_transaction_id` BIGINT(20) NULL DEFAULT NULL AFTER `savings_account_id`;
|
||||
|
||||
ALTER TABLE `m_note` ADD CONSTRAINT `FK_savings_account_id` FOREIGN KEY (`savings_account_id` ) REFERENCES `m_savings_account` (`id` ) ON DELETE NO ACTION ON UPDATE NO ACTION, ADD INDEX `FK_savings_account_id` (`savings_account_id` ASC) ;
|
||||
|
||||
|
||||
ALTER TABLE `m_savings_account_transaction`
|
||||
CHANGE COLUMN `is_reversed` `is_reversed` TINYINT(1) NOT NULL AFTER `transaction_type_enum`,
|
||||
CHANGE COLUMN `balance_end_date_derived` `balance_end_date_derived` DATE NULL DEFAULT NULL AFTER `amount`,
|
||||
CHANGE COLUMN `balance_number_of_days_derived` `balance_number_of_days_derived` INT(11) NULL DEFAULT NULL AFTER `balance_end_date_derived`;
|
||||
|
||||
ALTER TABLE `m_savings_account`
|
||||
ADD COLUMN `field_officer_id` bigint(20) DEFAULT NULL AFTER `product_id`,
|
||||
ADD COLUMN `submittedon_date` DATE NOT NULL AFTER `status_enum`,
|
||||
ADD COLUMN `submittedon_userid` bigint(20) DEFAULT NULL AFTER `submittedon_date`,
|
||||
ADD COLUMN `approvedon_date` DATE DEFAULT NULL AFTER `submittedon_userid`,
|
||||
ADD COLUMN `approvedon_userid` bigint(20) DEFAULT NULL AFTER `approvedon_date`,
|
||||
ADD COLUMN `rejectedon_date` DATE DEFAULT NULL AFTER `approvedon_userid`,
|
||||
ADD COLUMN `rejectedon_userid` bigint(20) DEFAULT NULL AFTER `rejectedon_date`,
|
||||
ADD COLUMN `withdrawnon_date` DATE DEFAULT NULL AFTER `rejectedon_userid`,
|
||||
ADD COLUMN `withdrawnon_userid` bigint(20) DEFAULT NULL AFTER `withdrawnon_date`;
|
||||
|
||||
ALTER TABLE `m_savings_account`
|
||||
CHANGE COLUMN `activation_date` `activatedon_date` DATE NULL DEFAULT NULL AFTER `withdrawnon_userid`;
|
||||
|
||||
ALTER TABLE `m_savings_account`
|
||||
ADD COLUMN `activatedon_userid` bigint(20) DEFAULT NULL AFTER `activatedon_date`,
|
||||
ADD COLUMN `closedon_date` DATE DEFAULT NULL AFTER `activatedon_userid`,
|
||||
ADD COLUMN `closedon_userid` bigint(20) DEFAULT NULL AFTER `closedon_date`;
|
||||
|
||||
UPDATE `m_savings_account`
|
||||
SET
|
||||
`submittedon_date`=`activatedon_date`,
|
||||
`approvedon_date`=`activatedon_date`;
|
||||
|
||||
|
||||
INSERT INTO `mifostenant-default`.`m_permission`
|
||||
(`grouping`,`code`,`entity_name`,`action_name`,`can_maker_checker`)
|
||||
VALUES
|
||||
('transaction_savings', 'APPROVE_SAVINGSACCOUNT', 'SAVINGSACCOUNT', 'APPROVE', 1),
|
||||
('transaction_savings', 'REJECT_SAVINGSACCOUNT', 'SAVINGSACCOUNT', 'REJECT', 1),
|
||||
('transaction_savings', 'WITHDRAW_SAVINGSACCOUNT', 'SAVINGSACCOUNT', 'WITHDRAW', 1),
|
||||
('transaction_savings', 'APPROVALUNDO_SAVINGSACCOUNT', 'SAVINGSACCOUNT', 'APPROVALUNDO', 1),
|
||||
('transaction_savings', 'CLOSE_SAVINGSACCOUNT', 'SAVINGSACCOUNT', 'CLOSE', 1);
|
||||
|
||||
INSERT INTO `mifostenant-default`.`m_permission`
|
||||
(`grouping`,`code`,`entity_name`,`action_name`,`can_maker_checker`)
|
||||
VALUES
|
||||
('transaction_savings', 'APPROVE_SAVINGSACCOUNT_CHECKER', 'SAVINGSACCOUNT', 'APPROVE', 0),
|
||||
('transaction_savings', 'REJECT_SAVINGSACCOUNT_CHECKER', 'SAVINGSACCOUNT', 'REJECT', 0),
|
||||
('transaction_savings', 'WITHDRAW_SAVINGSACCOUNT_CHECKER', 'SAVINGSACCOUNT', 'WITHDRAW', 0),
|
||||
('transaction_savings', 'APPROVALUNDO_SAVINGSACCOUNT_CHECKER', 'SAVINGSACCOUNT', 'APPROVALUNDO', 0),
|
||||
('transaction_savings', 'CLOSE_SAVINGSACCOUNT_CHECKER', 'SAVINGSACCOUNT', 'CLOSE', 0);
|
||||
|
||||
|
||||
-- Remove permissions with 'in the past' permissions
|
||||
|
||||
DELETE FROM `m_permission` WHERE `id`='210';
|
||||
|
||||
DELETE FROM `m_permission` WHERE `id`='212';
|
||||
DELETE FROM `m_permission` WHERE `id`='214';
|
||||
DELETE FROM `m_permission` WHERE `id`='217';
|
||||
DELETE FROM `m_permission` WHERE `id`='220';
|
||||
DELETE FROM `m_permission` WHERE `id`='233';
|
||||
DELETE FROM `m_permission` WHERE `id`='235';
|
||||
DELETE FROM `m_permission` WHERE `id`='237';
|
||||
DELETE FROM `m_permission` WHERE `id`='240';
|
||||
DELETE FROM `m_permission` WHERE `id`='243';
|
||||
@@ -53,7 +53,7 @@ project.ext.springVersion = '3.2.3.RELEASE'
|
||||
project.ext.springSecurityVersion = '3.1.4.RELEASE'
|
||||
project.ext.hibernateCoreVersion = '4.1.9.Final'
|
||||
project.ext.jerseyVersion = '1.17'
|
||||
project.ext.springDataJpaVersion = '1.3.0.RELEASE'
|
||||
project.ext.springDataJpaVersion = '1.3.2.RELEASE'
|
||||
|
||||
project.ext.mysqlUser='root'
|
||||
project.ext.mysqlPassword='mysql'
|
||||
@@ -123,8 +123,8 @@ dependencies {
|
||||
|
||||
[group: 'joda-time', name: 'joda-time', version: '2.1'],
|
||||
[group: 'net.sourceforge.javacsv', name: 'javacsv', version: '2.0'],
|
||||
[group: 'org.apache.commons', name: 'commons-email', version: '1.2'],
|
||||
[group: 'commons-lang', name: 'commons-lang', version: '2.4'],
|
||||
[group: 'org.apache.commons', name: 'commons-email', version: '1.3.1'],
|
||||
[group: 'org.apache.commons', name: 'commons-lang3', version: '3.1'],
|
||||
|
||||
[group: 'org.slf4j', name: 'slf4j-api', version: '1.7.5'],
|
||||
[group: 'org.slf4j', name: 'jcl-over-slf4j', version: '1.7.5'],
|
||||
@@ -164,7 +164,8 @@ dependencies {
|
||||
[group: 'com.amazonaws', name: 'aws-java-sdk', version: '1.2.1']
|
||||
)
|
||||
|
||||
testCompile 'junit:junit:4.11',
|
||||
testCompile 'junit:junit:4.10',
|
||||
'junit:junit-dep:4.10',
|
||||
'org.mockito:mockito-all:1.9.5',
|
||||
'com.jayway.restassured:rest-assured:1.7.2'
|
||||
|
||||
|
||||
+2
-1
@@ -23,7 +23,8 @@ import org.mifosplatform.infrastructure.core.serialization.FromJsonHelper;
|
||||
import org.mifosplatform.portfolio.loanproduct.domain.LoanProduct;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.stereotype.Component;
|
||||
import static org.mifosplatform.portfolio.savings.api.SavingsApiConstants.*;
|
||||
|
||||
import static org.mifosplatform.portfolio.savings.SavingsApiConstants.*;
|
||||
|
||||
import com.google.gson.JsonElement;
|
||||
|
||||
|
||||
+2
-1
@@ -21,7 +21,8 @@ import org.mifosplatform.infrastructure.core.serialization.FromJsonHelper;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.stereotype.Service;
|
||||
import org.springframework.transaction.annotation.Transactional;
|
||||
import static org.mifosplatform.portfolio.savings.api.SavingsApiConstants.*;
|
||||
|
||||
import static org.mifosplatform.portfolio.savings.SavingsApiConstants.*;
|
||||
|
||||
import com.google.gson.JsonElement;
|
||||
|
||||
|
||||
+16
-36
@@ -415,42 +415,6 @@ public class CommandWrapper {
|
||||
return isUserResource() && isUpdate() && loggedInUserId.equals(this.entityId);
|
||||
}
|
||||
|
||||
public boolean isDepositProductResource() {
|
||||
return this.entityName.equalsIgnoreCase("DEPOSITPRODUCT");
|
||||
}
|
||||
|
||||
public boolean isDepositAccountResource() {
|
||||
return this.entityName.equalsIgnoreCase("DEPOSITACCOUNT");
|
||||
}
|
||||
|
||||
public boolean isApprovalOfDeposit() {
|
||||
return this.actionName.equalsIgnoreCase("APPROVE") && this.entityName.equalsIgnoreCase("DEPOSITACCOUNT");
|
||||
}
|
||||
|
||||
public boolean isWithdrawDepositAmount() {
|
||||
return this.actionName.equalsIgnoreCase("WITHDRAWAL") && this.entityName.equalsIgnoreCase("DEPOSITACCOUNT");
|
||||
}
|
||||
|
||||
public boolean isWithdrawInterest() {
|
||||
return this.actionName.equalsIgnoreCase("INTEREST") && this.entityName.equalsIgnoreCase("DEPOSITACCOUNT");
|
||||
}
|
||||
|
||||
public boolean isRenewOfDepositApplicaion() {
|
||||
return this.actionName.equalsIgnoreCase("RENEW") && this.entityName.equalsIgnoreCase("DEPOSITACCOUNT");
|
||||
}
|
||||
|
||||
public boolean isRejectionOfDepositApplicaion() {
|
||||
return this.actionName.equalsIgnoreCase("REJECT") && this.entityName.equalsIgnoreCase("DEPOSITACCOUNT");
|
||||
}
|
||||
|
||||
public boolean isWithdrawByApplicant() {
|
||||
return this.actionName.equalsIgnoreCase("WITHDRAW") && this.entityName.equalsIgnoreCase("DEPOSITACCOUNT");
|
||||
}
|
||||
|
||||
public boolean isUndoApprovalOfDepositApplication() {
|
||||
return this.actionName.equalsIgnoreCase("APPROVALUNDO") && this.entityName.equalsIgnoreCase("DEPOSITACCOUNT");
|
||||
}
|
||||
|
||||
public boolean isSavingsProductResource() {
|
||||
return this.entityName.equalsIgnoreCase("SAVINGSPRODUCT");
|
||||
}
|
||||
@@ -459,6 +423,22 @@ public class CommandWrapper {
|
||||
return this.entityName.equalsIgnoreCase("SAVINGSACCOUNT");
|
||||
}
|
||||
|
||||
public boolean isRejectionOfSavingsAccountApplication() {
|
||||
return this.actionName.equalsIgnoreCase("REJECT") && this.entityName.equalsIgnoreCase("SAVINGSACCOUNT");
|
||||
}
|
||||
|
||||
public boolean isWithdrawFromSavingsAccountApplicationByApplicant() {
|
||||
return this.actionName.equalsIgnoreCase("WITHDRAW") && this.entityName.equalsIgnoreCase("SAVINGSACCOUNT");
|
||||
}
|
||||
|
||||
public boolean isApprovalOfSavingsAccountApplication() {
|
||||
return this.actionName.equalsIgnoreCase("APPROVE") && this.entityName.equalsIgnoreCase("SAVINGSACCOUNT");
|
||||
}
|
||||
|
||||
public boolean isUndoApprovalOfSavingsAccountApplication() {
|
||||
return this.actionName.equalsIgnoreCase("APPROVALUNDO") && this.entityName.equalsIgnoreCase("SAVINGSACCOUNT");
|
||||
}
|
||||
|
||||
public boolean isSavingsAccountActivation() {
|
||||
return this.actionName.equalsIgnoreCase("ACTIVATE") && this.entityName.equalsIgnoreCase("SAVINGSACCOUNT");
|
||||
}
|
||||
|
||||
+41
-5
@@ -757,6 +757,42 @@ public class CommandWrapperBuilder {
|
||||
return this;
|
||||
}
|
||||
|
||||
public CommandWrapperBuilder rejectSavingsAccountApplication(final Long accountId) {
|
||||
this.actionName = "REJECT";
|
||||
this.entityName = "SAVINGSACCOUNT";
|
||||
this.entityId = accountId;
|
||||
this.savingsId = accountId;
|
||||
this.href = "/savingsaccounts/" + accountId + "?command=reject";
|
||||
return this;
|
||||
}
|
||||
|
||||
public CommandWrapperBuilder withdrawSavingsAccountApplication(final Long accountId) {
|
||||
this.actionName = "WITHDRAW";
|
||||
this.entityName = "SAVINGSACCOUNT";
|
||||
this.entityId = accountId;
|
||||
this.savingsId = accountId;
|
||||
this.href = "/savingsaccounts/" + accountId + "?command=withdrawnByApplicant";
|
||||
return this;
|
||||
}
|
||||
|
||||
public CommandWrapperBuilder approveSavingsAccountApplication(final Long accountId) {
|
||||
this.actionName = "APPROVE";
|
||||
this.entityName = "SAVINGSACCOUNT";
|
||||
this.entityId = accountId;
|
||||
this.savingsId = accountId;
|
||||
this.href = "/savingsaccounts/" + accountId + "?command=approve";
|
||||
return this;
|
||||
}
|
||||
|
||||
public CommandWrapperBuilder undoSavingsAccountApplication(final Long accountId) {
|
||||
this.actionName = "APPROVALUNDO";
|
||||
this.entityName = "SAVINGSACCOUNT";
|
||||
this.entityId = accountId;
|
||||
this.savingsId = accountId;
|
||||
this.href = "/savingsaccounts/" + accountId + "?command=undoapproval";
|
||||
return this;
|
||||
}
|
||||
|
||||
public CommandWrapperBuilder savingsAccountActivation(final Long accountId) {
|
||||
this.actionName = "ACTIVATE";
|
||||
this.entityName = "SAVINGSACCOUNT";
|
||||
@@ -1036,7 +1072,7 @@ public class CommandWrapperBuilder {
|
||||
return this;
|
||||
}
|
||||
|
||||
public CommandWrapperBuilder assignRole(Long groupId) {
|
||||
public CommandWrapperBuilder assignRole(final Long groupId) {
|
||||
this.actionName = "ASSIGNROLE";
|
||||
this.entityName = "GROUP";
|
||||
this.groupId = groupId;
|
||||
@@ -1045,7 +1081,7 @@ public class CommandWrapperBuilder {
|
||||
return this;
|
||||
}
|
||||
|
||||
public CommandWrapperBuilder unassignRole(Long groupId, Long roleId) {
|
||||
public CommandWrapperBuilder unassignRole(final Long groupId, final Long roleId) {
|
||||
this.actionName = "UNASSIGNROLE";
|
||||
this.entityName = "GROUP";
|
||||
this.groupId = groupId;
|
||||
@@ -1054,7 +1090,7 @@ public class CommandWrapperBuilder {
|
||||
return this;
|
||||
}
|
||||
|
||||
public CommandWrapperBuilder updateRole(Long groupId, Long roleId) {
|
||||
public CommandWrapperBuilder updateRole(final Long groupId, final Long roleId) {
|
||||
this.actionName = "UPDATEROLE";
|
||||
this.entityName = "GROUP";
|
||||
this.groupId = groupId;
|
||||
@@ -1063,7 +1099,7 @@ public class CommandWrapperBuilder {
|
||||
return this;
|
||||
}
|
||||
|
||||
public CommandWrapperBuilder unassignClientStaff(Long clientId) {
|
||||
public CommandWrapperBuilder unassignClientStaff(final Long clientId) {
|
||||
this.actionName = "UNASSIGNSTAFF";
|
||||
this.entityName = "CLIENT";
|
||||
this.entityId = clientId;
|
||||
@@ -1072,7 +1108,7 @@ public class CommandWrapperBuilder {
|
||||
return this;
|
||||
}
|
||||
|
||||
public CommandWrapperBuilder assignClientStaff(Long clientId) {
|
||||
public CommandWrapperBuilder assignClientStaff(final Long clientId) {
|
||||
this.actionName = "ASSIGNSTAFF";
|
||||
this.entityName = "CLIENT";
|
||||
this.entityId = clientId;
|
||||
|
||||
+15
-3
@@ -374,11 +374,23 @@ public class SynchronousCommandProcessingService implements CommandProcessingSer
|
||||
}
|
||||
} else if (wrapper.isSavingsAccountResource()) {
|
||||
if (wrapper.isCreate()) {
|
||||
handler = this.applicationContext.getBean("createSavingsAccountCommandHandler", NewCommandSourceHandler.class);
|
||||
handler = this.applicationContext
|
||||
.getBean("savingsAccountApplicationSubmittalCommandHandler", NewCommandSourceHandler.class);
|
||||
} else if (wrapper.isUpdate()) {
|
||||
handler = this.applicationContext.getBean("updateSavingsAccountCommandHandler", NewCommandSourceHandler.class);
|
||||
handler = this.applicationContext.getBean("savingsAccountApplicationModificationCommandHandler",
|
||||
NewCommandSourceHandler.class);
|
||||
} else if (wrapper.isDelete()) {
|
||||
handler = this.applicationContext.getBean("deleteSavingsAccountCommandHandler", NewCommandSourceHandler.class);
|
||||
handler = this.applicationContext.getBean("savingsAccountApplicationDeletionCommandHandler", NewCommandSourceHandler.class);
|
||||
} else if (wrapper.isRejectionOfSavingsAccountApplication()) {
|
||||
handler = this.applicationContext.getBean("savingsAccountApplicationRejectedCommandHandler", NewCommandSourceHandler.class);
|
||||
} else if (wrapper.isWithdrawFromSavingsAccountApplicationByApplicant()) {
|
||||
handler = this.applicationContext.getBean("savingsAccountApplicationWithdrawnByApplicantCommandHandler",
|
||||
NewCommandSourceHandler.class);
|
||||
} else if (wrapper.isApprovalOfSavingsAccountApplication()) {
|
||||
handler = this.applicationContext.getBean("savingsAccountApplicationApprovalCommandHandler", NewCommandSourceHandler.class);
|
||||
} else if (wrapper.isUndoApprovalOfSavingsAccountApplication()) {
|
||||
handler = this.applicationContext.getBean("savingsAccountApplicationApprovalUndoCommandHandler",
|
||||
NewCommandSourceHandler.class);
|
||||
} else if (wrapper.isSavingsAccountDeposit()) {
|
||||
handler = this.applicationContext.getBean("depositSavingsAccountCommandHandler", NewCommandSourceHandler.class);
|
||||
} else if (wrapper.isSavingsAccountWithdrawal()) {
|
||||
|
||||
+60
-18
@@ -46,6 +46,7 @@ public final class JsonCommand {
|
||||
private final Long supportedEntityId;
|
||||
private final String transactionId;
|
||||
private final String url;
|
||||
|
||||
public static JsonCommand from(final String jsonCommand, final JsonElement parsedCommand, final FromJsonHelper fromApiJsonHelper,
|
||||
final String entityName, final Long resourceId, final Long subresourceId, final Long groupId, final Long clientId,
|
||||
final Long loanId, final Long savingsId, final Long codeId, final String supportedEntityType, final Long supportedEntityId,
|
||||
@@ -64,8 +65,7 @@ public final class JsonCommand {
|
||||
public JsonCommand(final Long commandId, final String jsonCommand, final JsonElement parsedCommand,
|
||||
final FromJsonHelper fromApiJsonHelper, final String entityName, final Long resourceId, final Long subresourceId,
|
||||
final Long groupId, final Long clientId, final Long loanId, final Long savingsId, final Long codeId,
|
||||
final String supportedEntityType, final Long supportedEntityId, final String transactionId,
|
||||
final String url) {
|
||||
final String supportedEntityType, final Long supportedEntityId, final String transactionId, final String url) {
|
||||
this.commandId = commandId;
|
||||
this.jsonCommand = jsonCommand;
|
||||
this.parsedCommand = parsedCommand;
|
||||
@@ -148,9 +148,9 @@ public final class JsonCommand {
|
||||
public String getTransactionId() {
|
||||
return this.transactionId;
|
||||
}
|
||||
|
||||
|
||||
public String getUrl() {
|
||||
return this.url;
|
||||
return this.url;
|
||||
}
|
||||
|
||||
private boolean differenceExists(final LocalDate baseValue, final LocalDate workingCopyValue) {
|
||||
@@ -187,10 +187,10 @@ public final class JsonCommand {
|
||||
boolean differenceExists = false;
|
||||
|
||||
if (baseValue != null) {
|
||||
if(workingCopyValue != null) {
|
||||
differenceExists = !baseValue.equals(workingCopyValue);
|
||||
if (workingCopyValue != null) {
|
||||
differenceExists = !baseValue.equals(workingCopyValue);
|
||||
} else {
|
||||
differenceExists = true;
|
||||
differenceExists = true;
|
||||
}
|
||||
} else {
|
||||
differenceExists = workingCopyValue != null;
|
||||
@@ -203,11 +203,11 @@ public final class JsonCommand {
|
||||
boolean differenceExists = false;
|
||||
|
||||
if (baseValue != null) {
|
||||
if(workingCopyValue != null) {
|
||||
differenceExists = baseValue.compareTo(workingCopyValue) != 0;
|
||||
}else {
|
||||
differenceExists = true;
|
||||
}
|
||||
if (workingCopyValue != null) {
|
||||
differenceExists = baseValue.compareTo(workingCopyValue) != 0;
|
||||
} else {
|
||||
differenceExists = true;
|
||||
}
|
||||
} else {
|
||||
differenceExists = workingCopyValue != null;
|
||||
}
|
||||
@@ -301,6 +301,15 @@ public final class JsonCommand {
|
||||
return StringUtils.defaultIfEmpty(value, "");
|
||||
}
|
||||
|
||||
public boolean isChangeInBigDecimalParameterNamedDefaultingZeroToNull(final String parameterName, final BigDecimal existingValue) {
|
||||
boolean isChanged = false;
|
||||
if (parameterExists(parameterName)) {
|
||||
final BigDecimal workingValue = bigDecimalValueOfParameterNamedDefaultToNullIfZero(parameterName);
|
||||
isChanged = differenceExists(existingValue, workingValue);
|
||||
}
|
||||
return isChanged;
|
||||
}
|
||||
|
||||
public boolean isChangeInBigDecimalParameterNamed(final String parameterName, final BigDecimal existingValue) {
|
||||
boolean isChanged = false;
|
||||
if (parameterExists(parameterName)) {
|
||||
@@ -309,24 +318,53 @@ public final class JsonCommand {
|
||||
}
|
||||
return isChanged;
|
||||
}
|
||||
|
||||
|
||||
public boolean isChangeInBigDecimalParameterNamedWithNullCheck(final String parameterName, final BigDecimal existingValue) {
|
||||
boolean isChanged = false;
|
||||
if (parameterExists(parameterName)) {
|
||||
final BigDecimal workingValue = bigDecimalValueOfParameterNamed(parameterName);
|
||||
if(workingValue == null && existingValue != null){
|
||||
if (workingValue == null && existingValue != null) {
|
||||
isChanged = true;
|
||||
}else{
|
||||
} else {
|
||||
isChanged = differenceExists(existingValue, workingValue);
|
||||
}
|
||||
}
|
||||
return isChanged;
|
||||
}
|
||||
|
||||
private static BigDecimal defaultToNullIfZero(final BigDecimal value) {
|
||||
BigDecimal result = value;
|
||||
if (value != null && BigDecimal.ZERO.compareTo(value) == 0) {
|
||||
result = null;
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
private static Integer defaultToNullIfZero(final Integer value) {
|
||||
Integer result = value;
|
||||
if (value != null && value == 0) {
|
||||
result = null;
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
public BigDecimal bigDecimalValueOfParameterNamed(final String parameterName) {
|
||||
return this.fromApiJsonHelper.extractBigDecimalWithLocaleNamed(parameterName, parsedCommand);
|
||||
}
|
||||
|
||||
public BigDecimal bigDecimalValueOfParameterNamedDefaultToNullIfZero(final String parameterName) {
|
||||
return defaultToNullIfZero(bigDecimalValueOfParameterNamed(parameterName));
|
||||
}
|
||||
|
||||
public boolean isChangeInIntegerParameterNamedDefaultingZeroToNull(final String parameterName, final Integer existingValue) {
|
||||
boolean isChanged = false;
|
||||
if (parameterExists(parameterName)) {
|
||||
final Integer workingValue = integerValueOfParameterNamedDefaultToNullIfZero(parameterName);
|
||||
isChanged = differenceExists(existingValue, workingValue);
|
||||
}
|
||||
return isChanged;
|
||||
}
|
||||
|
||||
public boolean isChangeInIntegerParameterNamed(final String parameterName, final Integer existingValue) {
|
||||
boolean isChanged = false;
|
||||
if (parameterExists(parameterName)) {
|
||||
@@ -340,19 +378,23 @@ public final class JsonCommand {
|
||||
boolean isChanged = false;
|
||||
if (parameterExists(parameterName)) {
|
||||
final Integer workingValue = integerValueOfParameterNamed(parameterName);
|
||||
if(workingValue == null && existingValue != null){
|
||||
if (workingValue == null && existingValue != null) {
|
||||
isChanged = true;
|
||||
}else{
|
||||
} else {
|
||||
isChanged = differenceExists(existingValue, workingValue);
|
||||
}
|
||||
}
|
||||
return isChanged;
|
||||
}
|
||||
|
||||
|
||||
public Integer integerValueOfParameterNamed(final String parameterName) {
|
||||
return this.fromApiJsonHelper.extractIntegerWithLocaleNamed(parameterName, parsedCommand);
|
||||
}
|
||||
|
||||
public Integer integerValueOfParameterNamedDefaultToNullIfZero(final String parameterName) {
|
||||
return defaultToNullIfZero(integerValueOfParameterNamed(parameterName));
|
||||
}
|
||||
|
||||
public boolean isChangeInIntegerSansLocaleParameterNamed(final String parameterName, final Integer existingValue) {
|
||||
boolean isChanged = false;
|
||||
if (parameterExists(parameterName)) {
|
||||
|
||||
+73
-45
@@ -209,25 +209,24 @@ public class DataValidatorBuilder {
|
||||
public DataValidatorBuilder isOneOfTheseValues(final Object... values) {
|
||||
if (value == null && ignoreNullValue) { return this; }
|
||||
|
||||
if (value != null) {
|
||||
List<Object> valuesList = Arrays.asList(values);
|
||||
String valuesListStr = StringUtils.join(valuesList, ", ");
|
||||
List<Object> valuesList = Arrays.asList(values);
|
||||
String valuesListStr = StringUtils.join(valuesList, ", ");
|
||||
|
||||
if (!valuesList.contains(this.value)) {
|
||||
StringBuilder validationErrorCode = new StringBuilder("validation.msg.").append(resource).append(".").append(parameter)
|
||||
.append(".is.not.one.of.expected.enumerations");
|
||||
StringBuilder defaultEnglishMessage = new StringBuilder("The parameter ").append(parameter).append(" must be one of [ ")
|
||||
.append(valuesListStr).append(" ] ").append(".");
|
||||
if (this.value == null || !valuesList.contains(this.value)) {
|
||||
StringBuilder validationErrorCode = new StringBuilder("validation.msg.").append(resource).append(".").append(parameter)
|
||||
.append(".is.not.one.of.expected.enumerations");
|
||||
StringBuilder defaultEnglishMessage = new StringBuilder("The parameter ").append(parameter).append(" must be one of [ ")
|
||||
.append(valuesListStr).append(" ] ").append(".");
|
||||
|
||||
ApiParameterError error = ApiParameterError.parameterError(validationErrorCode.toString(),
|
||||
defaultEnglishMessage.toString(), parameter, this.value, values);
|
||||
ApiParameterError error = ApiParameterError.parameterError(validationErrorCode.toString(), defaultEnglishMessage.toString(),
|
||||
parameter, this.value, values);
|
||||
|
||||
dataValidationErrors.add(error);
|
||||
}
|
||||
dataValidationErrors.add(error);
|
||||
}
|
||||
|
||||
return this;
|
||||
}
|
||||
|
||||
|
||||
public DataValidatorBuilder isNotOneOfTheseValues(final Object... values) {
|
||||
if (value == null && ignoreNullValue) { return this; }
|
||||
|
||||
@@ -238,8 +237,8 @@ public class DataValidatorBuilder {
|
||||
if (valuesList.contains(this.value)) {
|
||||
StringBuilder validationErrorCode = new StringBuilder("validation.msg.").append(resource).append(".").append(parameter)
|
||||
.append(".is.one.of.unwanted.enumerations");
|
||||
StringBuilder defaultEnglishMessage = new StringBuilder("The parameter ").append(parameter).append(" must not be any of [ ")
|
||||
.append(valuesListStr).append(" ] ").append(".");
|
||||
StringBuilder defaultEnglishMessage = new StringBuilder("The parameter ").append(parameter)
|
||||
.append(" must not be any of [ ").append(valuesListStr).append(" ] ").append(".");
|
||||
|
||||
ApiParameterError error = ApiParameterError.parameterError(validationErrorCode.toString(),
|
||||
defaultEnglishMessage.toString(), parameter, this.value, values);
|
||||
@@ -268,6 +267,9 @@ public class DataValidatorBuilder {
|
||||
return this;
|
||||
}
|
||||
|
||||
/*
|
||||
* should be used with .notNull() before it
|
||||
*/
|
||||
public DataValidatorBuilder zeroOrPositiveAmount() {
|
||||
if (value == null && ignoreNullValue) { return this; }
|
||||
|
||||
@@ -286,6 +288,30 @@ public class DataValidatorBuilder {
|
||||
return this;
|
||||
}
|
||||
|
||||
/*
|
||||
* should be used with .notNull() before it
|
||||
*/
|
||||
public DataValidatorBuilder integerZeroOrGreater() {
|
||||
if (value == null && ignoreNullValue) { return this; }
|
||||
|
||||
if (value != null) {
|
||||
Integer number = Integer.valueOf(value.toString());
|
||||
if (number < 0) {
|
||||
StringBuilder validationErrorCode = new StringBuilder("validation.msg.").append(resource).append(".").append(parameter)
|
||||
.append(".not.zero.or.greater");
|
||||
StringBuilder defaultEnglishMessage = new StringBuilder("The parameter ").append(parameter).append(
|
||||
" must be zero or greater.");
|
||||
ApiParameterError error = ApiParameterError.parameterError(validationErrorCode.toString(),
|
||||
defaultEnglishMessage.toString(), parameter, number, 0);
|
||||
dataValidationErrors.add(error);
|
||||
}
|
||||
}
|
||||
return this;
|
||||
}
|
||||
|
||||
/*
|
||||
* should be used with .notNull() before it
|
||||
*/
|
||||
public DataValidatorBuilder integerGreaterThanZero() {
|
||||
if (value == null && ignoreNullValue) { return this; }
|
||||
|
||||
@@ -304,6 +330,9 @@ public class DataValidatorBuilder {
|
||||
return this;
|
||||
}
|
||||
|
||||
/*
|
||||
* should be used with .notNull() before it
|
||||
*/
|
||||
public DataValidatorBuilder longGreaterThanZero() {
|
||||
if (value == null && ignoreNullValue) { return this; }
|
||||
|
||||
@@ -337,11 +366,11 @@ public class DataValidatorBuilder {
|
||||
}
|
||||
return this;
|
||||
}
|
||||
|
||||
|
||||
public DataValidatorBuilder jsonArrayNotEmpty() {
|
||||
if (value == null && ignoreNullValue) { return this; }
|
||||
|
||||
JsonArray array = (JsonArray)value;
|
||||
JsonArray array = (JsonArray) value;
|
||||
if (value != null && !array.iterator().hasNext()) {
|
||||
StringBuilder validationErrorCode = new StringBuilder("validation.msg.").append(resource).append(".").append(parameter)
|
||||
.append(".cannot.be.empty");
|
||||
@@ -427,14 +456,14 @@ public class DataValidatorBuilder {
|
||||
dataValidationErrors.add(error);
|
||||
return this;
|
||||
}
|
||||
|
||||
|
||||
public DataValidatorBuilder cantBeBlankWhenParameterProvidedIs(final String parameterName, final Object parameterValue) {
|
||||
if (value != null && StringUtils.isNotBlank(value.toString())) { return this; }
|
||||
|
||||
StringBuilder validationErrorCode = new StringBuilder("validation.msg.").append(resource).append(".").append(parameter)
|
||||
.append(".must.be.provided.when.").append(parameterName).append(".is.").append(parameterValue);
|
||||
StringBuilder defaultEnglishMessage = new StringBuilder("The parameter ").append(parameter)
|
||||
.append(" must be provided when ").append(parameterName).append(" is ").append(parameterValue);
|
||||
StringBuilder defaultEnglishMessage = new StringBuilder("The parameter ").append(parameter).append(" must be provided when ")
|
||||
.append(parameterName).append(" is ").append(parameterValue);
|
||||
ApiParameterError error = ApiParameterError.parameterError(validationErrorCode.toString(), defaultEnglishMessage.toString(),
|
||||
parameter, value, parameterName, parameterValue);
|
||||
dataValidationErrors.add(error);
|
||||
@@ -457,12 +486,12 @@ public class DataValidatorBuilder {
|
||||
}
|
||||
|
||||
public DataValidatorBuilder inMinAndMaxAmountRange(final BigDecimal minimumAmount, final BigDecimal maximumAmount) {
|
||||
if (minimumAmount != null && maximumAmount != null && value != null){
|
||||
if (minimumAmount != null && maximumAmount != null && value != null) {
|
||||
BigDecimal amount = BigDecimal.valueOf(Double.valueOf(value.toString()));
|
||||
if (amount.compareTo(minimumAmount) == -1 || amount.compareTo(maximumAmount) == 1) {
|
||||
StringBuilder validationErrorCode = new StringBuilder("validation.msg.").append(resource).append(".").append(parameter)
|
||||
.append(".amount.is.not.within.min.max.range");
|
||||
StringBuilder defaultEnglishMessage = new StringBuilder("The ").append(parameter) .append(" amount ").append(amount)
|
||||
StringBuilder defaultEnglishMessage = new StringBuilder("The ").append(parameter).append(" amount ").append(amount)
|
||||
.append(" must be between ").append(minimumAmount).append(" and ").append(maximumAmount).append(" .");
|
||||
ApiParameterError error = ApiParameterError.parameterError(validationErrorCode.toString(),
|
||||
defaultEnglishMessage.toString(), parameter, amount, minimumAmount, maximumAmount);
|
||||
@@ -472,14 +501,14 @@ public class DataValidatorBuilder {
|
||||
}
|
||||
return this;
|
||||
}
|
||||
|
||||
|
||||
public DataValidatorBuilder notLessThanMin(final BigDecimal min) {
|
||||
if (min != null && value != null){
|
||||
if (min != null && value != null) {
|
||||
BigDecimal amount = BigDecimal.valueOf(Double.valueOf(value.toString()));
|
||||
if (amount.compareTo(min) == -1) {
|
||||
StringBuilder validationErrorCode = new StringBuilder("validation.msg.").append(resource).append(".").append(parameter)
|
||||
.append(".is.less.than.min");
|
||||
StringBuilder defaultEnglishMessage = new StringBuilder("The ").append(parameter) .append(" value ").append(amount)
|
||||
StringBuilder defaultEnglishMessage = new StringBuilder("The ").append(parameter).append(" value ").append(amount)
|
||||
.append(" must not be less than minimum value ").append(min);
|
||||
ApiParameterError error = ApiParameterError.parameterError(validationErrorCode.toString(),
|
||||
defaultEnglishMessage.toString(), parameter, amount, min);
|
||||
@@ -489,14 +518,14 @@ public class DataValidatorBuilder {
|
||||
}
|
||||
return this;
|
||||
}
|
||||
|
||||
|
||||
public DataValidatorBuilder notGreaterThanMax(final BigDecimal max) {
|
||||
if (max != null && value != null){
|
||||
if (max != null && value != null) {
|
||||
BigDecimal amount = BigDecimal.valueOf(Double.valueOf(value.toString()));
|
||||
if (amount.compareTo(max) == 1) {
|
||||
StringBuilder validationErrorCode = new StringBuilder("validation.msg.").append(resource).append(".").append(parameter)
|
||||
.append(".is.greater.than.max");
|
||||
StringBuilder defaultEnglishMessage = new StringBuilder("The ").append(parameter) .append(" value ").append(amount)
|
||||
StringBuilder defaultEnglishMessage = new StringBuilder("The ").append(parameter).append(" value ").append(amount)
|
||||
.append(" must not be more than maximum value ").append(max);
|
||||
ApiParameterError error = ApiParameterError.parameterError(validationErrorCode.toString(),
|
||||
defaultEnglishMessage.toString(), parameter, amount, max);
|
||||
@@ -541,7 +570,7 @@ public class DataValidatorBuilder {
|
||||
}
|
||||
return this;
|
||||
}
|
||||
|
||||
|
||||
public DataValidatorBuilder notLessThanMin(final Integer min) {
|
||||
if (value == null && ignoreNullValue) { return this; }
|
||||
|
||||
@@ -559,7 +588,7 @@ public class DataValidatorBuilder {
|
||||
}
|
||||
return this;
|
||||
}
|
||||
|
||||
|
||||
public DataValidatorBuilder notGreaterThanMax(final Integer max) {
|
||||
if (value == null && ignoreNullValue) { return this; }
|
||||
|
||||
@@ -577,26 +606,25 @@ public class DataValidatorBuilder {
|
||||
}
|
||||
return this;
|
||||
}
|
||||
|
||||
public DataValidatorBuilder matchesRegularExpression(final String expression) {
|
||||
if (value == null && ignoreNullValue) { return this; }
|
||||
|
||||
if (value != null && !value.toString().matches(expression)) {
|
||||
StringBuilder validationErrorCode = new StringBuilder("validation.msg.").append(resource).append(".").append(parameter)
|
||||
public DataValidatorBuilder matchesRegularExpression(final String expression) {
|
||||
if (value == null && ignoreNullValue) { return this; }
|
||||
|
||||
if (value != null && !value.toString().matches(expression)) {
|
||||
StringBuilder validationErrorCode = new StringBuilder("validation.msg.").append(resource).append(".").append(parameter)
|
||||
.append(".does.not.match.regexp");
|
||||
StringBuilder defaultEnglishMessage = new StringBuilder("The parameter ").append(parameter)
|
||||
.append(" must match the provided regular expression [ ")
|
||||
.append(expression).append(" ] ").append(".");
|
||||
.append(" must match the provided regular expression [ ").append(expression).append(" ] ").append(".");
|
||||
|
||||
ApiParameterError error = ApiParameterError.parameterError(validationErrorCode.toString(),
|
||||
defaultEnglishMessage.toString(), parameter, this.value, expression);
|
||||
ApiParameterError error = ApiParameterError.parameterError(validationErrorCode.toString(), defaultEnglishMessage.toString(),
|
||||
parameter, this.value, expression);
|
||||
|
||||
dataValidationErrors.add(error);
|
||||
}
|
||||
|
||||
return this;
|
||||
|
||||
return this;
|
||||
}
|
||||
|
||||
|
||||
private DataValidatorBuilder validateStringFor(final String validInputs) {
|
||||
if (this.value == null && this.ignoreNullValue) { return this; }
|
||||
final String[] inputs = validInputs.split(VALID_INPUT_SEPERATOR);
|
||||
@@ -610,15 +638,15 @@ public class DataValidatorBuilder {
|
||||
if (validationErr) {
|
||||
final StringBuilder validationErrorCode = new StringBuilder("validation.msg.").append(this.resource).append(".")
|
||||
.append(this.parameter).append(".value.should.true.or.false");
|
||||
final StringBuilder defaultEnglishMessage = new StringBuilder("The parameter ").append(this.parameter)
|
||||
.append(" value should true or false ");
|
||||
final StringBuilder defaultEnglishMessage = new StringBuilder("The parameter ").append(this.parameter).append(
|
||||
" value should true or false ");
|
||||
final ApiParameterError error = ApiParameterError.parameterError(validationErrorCode.toString(),
|
||||
defaultEnglishMessage.toString(), this.parameter, this.value);
|
||||
this.dataValidationErrors.add(error);
|
||||
}
|
||||
return this;
|
||||
}
|
||||
|
||||
|
||||
public DataValidatorBuilder validateForBooleanValue() {
|
||||
return validateStringFor("TRUE" + VALID_INPUT_SEPERATOR + "FALSE");
|
||||
}
|
||||
|
||||
+15
@@ -5,6 +5,8 @@
|
||||
*/
|
||||
package org.mifosplatform.infrastructure.core.domain;
|
||||
|
||||
import org.apache.commons.lang3.builder.ToStringBuilder;
|
||||
import org.apache.commons.lang3.builder.ToStringStyle;
|
||||
import org.joda.time.Days;
|
||||
import org.joda.time.LocalDate;
|
||||
|
||||
@@ -38,6 +40,14 @@ public class LocalDateInterval {
|
||||
return Days.daysBetween(this.startDate, this.endDate).getDays();
|
||||
}
|
||||
|
||||
public boolean containsPortionOf(final LocalDateInterval interval) {
|
||||
return contains(interval.startDate) || contains(interval.endDate);
|
||||
}
|
||||
|
||||
public boolean contains(final LocalDateInterval interval) {
|
||||
return contains(interval.startDate) && contains(interval.endDate);
|
||||
}
|
||||
|
||||
public boolean contains(final LocalDate target) {
|
||||
return isBetweenInclusive(this.startDate, this.endDate, target);
|
||||
}
|
||||
@@ -49,4 +59,9 @@ public class LocalDateInterval {
|
||||
public boolean fallsBefore(final LocalDate dateToCheck) {
|
||||
return this.endDate.isBefore(dateToCheck);
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return ToStringBuilder.reflectionToString(this, ToStringStyle.MULTI_LINE_STYLE);
|
||||
}
|
||||
}
|
||||
+1
-1
@@ -5,7 +5,7 @@
|
||||
*/
|
||||
package org.mifosplatform.portfolio.client.data;
|
||||
|
||||
import static org.mifosplatform.portfolio.savings.api.SavingsApiConstants.activationDateParamName;
|
||||
import static org.mifosplatform.portfolio.savings.SavingsApiConstants.activationDateParamName;
|
||||
|
||||
import java.lang.reflect.Type;
|
||||
import java.util.ArrayList;
|
||||
|
||||
+5
-1
@@ -452,7 +452,7 @@ public final class Client extends AbstractPersistable<Long> {
|
||||
this.staff = null;
|
||||
}
|
||||
|
||||
public void assignStaff(Staff staff) {
|
||||
public void assignStaff(final Staff staff) {
|
||||
this.staff = staff;
|
||||
}
|
||||
|
||||
@@ -466,4 +466,8 @@ public final class Client extends AbstractPersistable<Long> {
|
||||
public Integer getStatus() {
|
||||
return status;
|
||||
}
|
||||
|
||||
public boolean isActivatedAfter(final LocalDate submittedOn) {
|
||||
return getActivationLocalDate().isAfter(submittedOn);
|
||||
}
|
||||
}
|
||||
@@ -179,6 +179,10 @@ public final class Group extends AbstractPersistable<Long> {
|
||||
this.status = GroupingTypeStatus.ACTIVE.getValue();
|
||||
}
|
||||
|
||||
public boolean isActivatedAfter(final LocalDate submittedOn) {
|
||||
return getActivationLocalDate().isAfter(submittedOn);
|
||||
}
|
||||
|
||||
public boolean isNotActive() {
|
||||
return !isActive();
|
||||
}
|
||||
|
||||
+49
-49
@@ -137,9 +137,9 @@ public class Loan extends AbstractPersistable<Long> {
|
||||
@Column(name = "loan_status_id", nullable = false)
|
||||
private Integer loanStatus;
|
||||
|
||||
@Column(name = "sync_disbursement_with_meeting", nullable = true)
|
||||
private Boolean syncDisbursementWithMeeting;
|
||||
|
||||
@Column(name = "sync_disbursement_with_meeting", nullable = true)
|
||||
private Boolean syncDisbursementWithMeeting;
|
||||
|
||||
// loan application states
|
||||
@Temporal(TemporalType.DATE)
|
||||
@Column(name = "submittedon_date")
|
||||
@@ -231,10 +231,10 @@ public class Loan extends AbstractPersistable<Long> {
|
||||
@SuppressWarnings("unused")
|
||||
@Column(name = "total_overpaid_derived", scale = 6, precision = 19)
|
||||
private BigDecimal totalOverpaid;
|
||||
|
||||
|
||||
@Column(name = "loan_counter")
|
||||
private Integer loanCounter;
|
||||
|
||||
|
||||
@Column(name = "loan_product_counter")
|
||||
private Integer loanProductCounter;
|
||||
|
||||
@@ -294,7 +294,7 @@ public class Loan extends AbstractPersistable<Long> {
|
||||
public static Loan newGroupLoanApplication(final String accountNo, final Group group, final Integer loanType,
|
||||
final LoanProduct loanProduct, final Fund fund, final Staff officer,
|
||||
final LoanTransactionProcessingStrategy transactionProcessingStrategy,
|
||||
final LoanProductRelatedDetail loanRepaymentScheduleDetail, final Set<LoanCharge> loanCharges,
|
||||
final LoanProductRelatedDetail loanRepaymentScheduleDetail, final Set<LoanCharge> loanCharges,
|
||||
final Boolean syncDisbursementWithMeeting) {
|
||||
final LoanStatus status = null;
|
||||
final CodeValue loanPurpose = null;
|
||||
@@ -307,7 +307,7 @@ public class Loan extends AbstractPersistable<Long> {
|
||||
public static Loan newIndividualLoanApplicationFromGroup(final String accountNo, final Client client, final Group group,
|
||||
final Integer loanType, final LoanProduct loanProduct, final Fund fund, final Staff officer,
|
||||
final LoanTransactionProcessingStrategy transactionProcessingStrategy,
|
||||
final LoanProductRelatedDetail loanRepaymentScheduleDetail, final Set<LoanCharge> loanCharges,
|
||||
final LoanProductRelatedDetail loanRepaymentScheduleDetail, final Set<LoanCharge> loanCharges,
|
||||
final Boolean syncDisbursementWithMeeting) {
|
||||
final LoanStatus status = null;
|
||||
final CodeValue loanPurpose = null;
|
||||
@@ -361,7 +361,7 @@ public class Loan extends AbstractPersistable<Long> {
|
||||
this.collateral = null;
|
||||
}
|
||||
this.loanOfficerHistory = null;
|
||||
|
||||
|
||||
this.syncDisbursementWithMeeting = syncDisbursementWithMeeting;
|
||||
}
|
||||
|
||||
@@ -830,7 +830,7 @@ public class Loan extends AbstractPersistable<Long> {
|
||||
}
|
||||
|
||||
// add clientId, groupId and loanType changes to actual changes
|
||||
|
||||
|
||||
final String clientIdParamName = "clientId";
|
||||
final Long clientId = this.client == null ? null : this.client.getId();
|
||||
if (command.isChangeInLongParameterNamed(clientIdParamName, clientId)) {
|
||||
@@ -932,11 +932,11 @@ public class Loan extends AbstractPersistable<Long> {
|
||||
|
||||
final String syncDisbursementParameterName = "syncDisbursementWithMeeting";
|
||||
if (command.isChangeInBooleanParameterNamed(syncDisbursementParameterName, isSyncDisbursementWithMeeting())) {
|
||||
final Boolean valueAsInput = command.booleanObjectValueOfParameterNamed(syncDisbursementParameterName);
|
||||
actualChanges.put(syncDisbursementParameterName, valueAsInput);
|
||||
this.syncDisbursementWithMeeting = valueAsInput;
|
||||
final Boolean valueAsInput = command.booleanObjectValueOfParameterNamed(syncDisbursementParameterName);
|
||||
actualChanges.put(syncDisbursementParameterName, valueAsInput);
|
||||
this.syncDisbursementWithMeeting = valueAsInput;
|
||||
}
|
||||
|
||||
|
||||
final String interestChargedFromDateParamName = "interestChargedFromDate";
|
||||
if (command.isChangeInLocalDateParameterNamed(interestChargedFromDateParamName, getInterestChargedFromDate())) {
|
||||
final String valueAsInput = command.stringValueOfParameterNamed(interestChargedFromDateParamName);
|
||||
@@ -1003,14 +1003,14 @@ public class Loan extends AbstractPersistable<Long> {
|
||||
actualChanges.put(collateralParamName, listOfLoanCollateralData(possiblyModifedLoanCollateralItems));
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
final String loanTermFrequencyParamName = "loanTermFrequency";
|
||||
if (command.isChangeInIntegerParameterNamed(loanTermFrequencyParamName, this.termFrequency)) {
|
||||
final Integer newValue = command.integerValueOfParameterNamed(loanTermFrequencyParamName);
|
||||
actualChanges.put(externalIdParamName, newValue);
|
||||
this.termFrequency = newValue;
|
||||
}
|
||||
|
||||
|
||||
final String loanTermFrequencyTypeParamName = "loanTermFrequencyType";
|
||||
if (command.isChangeInIntegerParameterNamed(loanTermFrequencyTypeParamName, this.termPeriodFrequencyType)) {
|
||||
final Integer newValue = command.integerValueOfParameterNamed(loanTermFrequencyTypeParamName);
|
||||
@@ -1100,18 +1100,12 @@ public class Loan extends AbstractPersistable<Long> {
|
||||
throw new InvalidLoanStateTransitionException("submittal", "cannot.be.a.future.date", errorMessage, submittedOn);
|
||||
}
|
||||
|
||||
if (!(client == null)) {
|
||||
if (submittedOn.isBefore(client.getActivationLocalDate())) {
|
||||
final String errorMessage = "The date on which a loan is submitted cannot be earlier than client's activation date.";
|
||||
throw new InvalidLoanStateTransitionException("submittal", "cannot.be.before.client.activation.date", errorMessage,
|
||||
submittedOn);
|
||||
}
|
||||
} else if (!(group == null)) {
|
||||
if (submittedOn.isBefore(group.getActivationLocalDate())) {
|
||||
final String errorMessage = "The date on which a loan is submitted cannot be earlier than groups's activation date.";
|
||||
throw new InvalidLoanStateTransitionException("submittal", "cannot.be.before.group.activation.date", errorMessage,
|
||||
submittedOn);
|
||||
}
|
||||
if (client != null && client.isActivatedAfter(submittedOn)) {
|
||||
final String errorMessage = "The date on which a loan is submitted cannot be earlier than client's activation date.";
|
||||
throw new InvalidLoanStateTransitionException("submittal", "cannot.be.before.client.activation.date", errorMessage, submittedOn);
|
||||
} else if (group != null && group.isActivatedAfter(submittedOn)) {
|
||||
final String errorMessage = "The date on which a loan is submitted cannot be earlier than groups's activation date.";
|
||||
throw new InvalidLoanStateTransitionException("submittal", "cannot.be.before.group.activation.date", errorMessage, submittedOn);
|
||||
}
|
||||
|
||||
if (submittedOn.isAfter(getExpectedDisbursedOnLocalDate())) {
|
||||
@@ -1379,14 +1373,17 @@ public class Loan extends AbstractPersistable<Long> {
|
||||
|
||||
final Integer loanTermFrequency = this.termFrequency;
|
||||
final PeriodFrequencyType loanTermPeriodFrequencyType = PeriodFrequencyType.fromInt(this.termPeriodFrequencyType);
|
||||
//If ExpectedFirstRepaymentOnDate is null and repayment is synced with meeting then use firstRepaymentMeetingDate
|
||||
//to generate repayment schedule dates
|
||||
final LocalDate firstRepaymentOnDate = (getExpectedFirstRepaymentOnDate() == null) ? firstRepaymentMeetingDate : getExpectedFirstRepaymentOnDate();
|
||||
// If ExpectedFirstRepaymentOnDate is null and repayment is synced with
|
||||
// meeting then use firstRepaymentMeetingDate
|
||||
// to generate repayment schedule dates
|
||||
final LocalDate firstRepaymentOnDate = (getExpectedFirstRepaymentOnDate() == null) ? firstRepaymentMeetingDate
|
||||
: getExpectedFirstRepaymentOnDate();
|
||||
LoanApplicationTerms loanApplicationTerms = LoanApplicationTerms.assembleFrom(applicationCurrency, loanTermFrequency,
|
||||
loanTermPeriodFrequencyType, getDisbursementDate(), firstRepaymentOnDate, getInArrearsTolerance(),
|
||||
this.loanRepaymentScheduleDetail);
|
||||
|
||||
LoanScheduleModel loanSchedule = loanScheduleGenerator.generate(mc, applicationCurrency, loanApplicationTerms, this.charges, isHolidayEnabled, holidays);
|
||||
LoanScheduleModel loanSchedule = loanScheduleGenerator.generate(mc, applicationCurrency, loanApplicationTerms, this.charges,
|
||||
isHolidayEnabled, holidays);
|
||||
|
||||
updateLoanSchedule(loanSchedule);
|
||||
}
|
||||
@@ -2348,34 +2345,37 @@ public class Loan extends AbstractPersistable<Long> {
|
||||
return this.closedOnDate;
|
||||
}
|
||||
|
||||
public void updateLoanRepaymentScheduleDates(final LocalDate meetingStartDate, final String recuringRule, final boolean isHolidayEnabled, final List<Holiday> holidays) {
|
||||
//update repayment dates of repayment schedule installaments
|
||||
LocalDate tmpFromDate = this.getDisbursementDate();//first repayment's from date is same as disbursement date.
|
||||
public void updateLoanRepaymentScheduleDates(final LocalDate meetingStartDate, final String recuringRule,
|
||||
final boolean isHolidayEnabled, final List<Holiday> holidays) {
|
||||
// update repayment dates of repayment schedule installaments
|
||||
LocalDate tmpFromDate = this.getDisbursementDate();// first repayment's
|
||||
// from date is same
|
||||
// as disbursement
|
||||
// date.
|
||||
LocalDate newRepaymentDate = null;
|
||||
for (LoanRepaymentScheduleInstallment loanRepaymentScheduleInstallment : this.repaymentScheduleInstallments) {
|
||||
final LocalDate oldDueDate = loanRepaymentScheduleInstallment.getDueDate();
|
||||
//FIXME: AA this won't update repayment dates before current date.
|
||||
// FIXME: AA this won't update repayment dates before current date.
|
||||
if (oldDueDate.isAfter(meetingStartDate) && oldDueDate.isAfter(DateUtils.getLocalDateOfTenant())) {
|
||||
final PeriodFrequencyType repaymentPeriodFrequencyType = this.loanRepaymentScheduleDetail.getRepaymentPeriodFrequencyType();
|
||||
final String frequency = CalendarHelper.getMeetingFrequencyFromPeriodFrequencyType(repaymentPeriodFrequencyType);
|
||||
final Integer loanRepaymentInterval = this.loanRepaymentScheduleDetail.getRepayEvery();
|
||||
// reset repayment date with new meeting date
|
||||
newRepaymentDate = CalendarHelper.getNewRepaymentMeetingDate(recuringRule, meetingStartDate, oldDueDate, loanRepaymentInterval, frequency);
|
||||
if(isHolidayEnabled){
|
||||
newRepaymentDate = CalendarHelper.getNewRepaymentMeetingDate(recuringRule, meetingStartDate, oldDueDate,
|
||||
loanRepaymentInterval, frequency);
|
||||
if (isHolidayEnabled) {
|
||||
newRepaymentDate = HolidayUtil.getRepaymentRescheduleDateToIfHoliday(newRepaymentDate, holidays);
|
||||
}
|
||||
loanRepaymentScheduleInstallment.updateDueDate(newRepaymentDate);
|
||||
//reset from date to get actual daysInPeriod
|
||||
// reset from date to get actual daysInPeriod
|
||||
loanRepaymentScheduleInstallment.updateFromDate(tmpFromDate);
|
||||
tmpFromDate = newRepaymentDate;//update with new repayment date
|
||||
}else{
|
||||
tmpFromDate = newRepaymentDate;// update with new repayment date
|
||||
} else {
|
||||
tmpFromDate = oldDueDate;
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
public void applyHolidayToRepaymentScheduleDates(final Holiday holiday) {
|
||||
// first repayment's from date is same as disbursement date.
|
||||
@@ -2383,9 +2383,10 @@ public class Loan extends AbstractPersistable<Long> {
|
||||
// Loop through all loanRepayments
|
||||
for (LoanRepaymentScheduleInstallment loanRepaymentScheduleInstallment : this.repaymentScheduleInstallments) {
|
||||
final LocalDate oldDueDate = loanRepaymentScheduleInstallment.getDueDate();
|
||||
|
||||
//update from date if it's not same as previous installament's due date.
|
||||
if(!loanRepaymentScheduleInstallment.getFromDate().isEqual(tmpFromDate)){
|
||||
|
||||
// update from date if it's not same as previous installament's due
|
||||
// date.
|
||||
if (!loanRepaymentScheduleInstallment.getFromDate().isEqual(tmpFromDate)) {
|
||||
loanRepaymentScheduleInstallment.updateFromDate(tmpFromDate);
|
||||
}
|
||||
if (oldDueDate.isAfter(holiday.getToDateLocalDate())) break;
|
||||
@@ -2412,11 +2413,11 @@ public class Loan extends AbstractPersistable<Long> {
|
||||
return this.loanProductCounter;
|
||||
}
|
||||
|
||||
public void updateClientLoanCounter(Integer newLoanCounter) {
|
||||
public void updateClientLoanCounter(final Integer newLoanCounter) {
|
||||
this.loanCounter = newLoanCounter;
|
||||
}
|
||||
|
||||
public void updateLoanProductLoanCounter(Integer newLoanProductLoanCounter) {
|
||||
public void updateLoanProductLoanCounter(final Integer newLoanProductLoanCounter) {
|
||||
this.loanProductCounter = newLoanProductLoanCounter;
|
||||
}
|
||||
|
||||
@@ -2432,7 +2433,6 @@ public class Loan extends AbstractPersistable<Long> {
|
||||
return this.termFrequency;
|
||||
}
|
||||
|
||||
|
||||
public Integer getTermPeriodFrequencyType() {
|
||||
return this.termPeriodFrequencyType;
|
||||
}
|
||||
|
||||
+1
-1
@@ -27,6 +27,6 @@ public class LoanApplicationApprovalCommandHandler implements NewCommandSourceHa
|
||||
@Override
|
||||
public CommandProcessingResult processCommand(final JsonCommand command) {
|
||||
|
||||
return this.writePlatformService.approveLoanApplication(command.entityId(), command);
|
||||
return this.writePlatformService.approveApplication(command.entityId(), command);
|
||||
}
|
||||
}
|
||||
+1
-1
@@ -27,6 +27,6 @@ public class LoanApplicationApprovalUndoCommandHandler implements NewCommandSour
|
||||
@Override
|
||||
public CommandProcessingResult processCommand(final JsonCommand command) {
|
||||
|
||||
return this.writePlatformService.undoLoanApplicationApproval(command.entityId(), command);
|
||||
return this.writePlatformService.undoApplicationApproval(command.entityId(), command);
|
||||
}
|
||||
}
|
||||
+1
-1
@@ -27,6 +27,6 @@ public class LoanApplicationDeletionCommandHandler implements NewCommandSourceHa
|
||||
@Override
|
||||
public CommandProcessingResult processCommand(final JsonCommand command) {
|
||||
|
||||
return this.writePlatformService.deleteLoanApplication(command.entityId());
|
||||
return this.writePlatformService.deleteApplication(command.entityId());
|
||||
}
|
||||
}
|
||||
+1
-1
@@ -27,6 +27,6 @@ public class LoanApplicationModificationCommandHandler implements NewCommandSour
|
||||
@Override
|
||||
public CommandProcessingResult processCommand(final JsonCommand command) {
|
||||
|
||||
return this.writePlatformService.modifyLoanApplication(command.getLoanId(), command);
|
||||
return this.writePlatformService.modifyApplication(command.getLoanId(), command);
|
||||
}
|
||||
}
|
||||
+1
-1
@@ -27,6 +27,6 @@ public class LoanApplicationRejectedCommandHandler implements NewCommandSourceHa
|
||||
@Override
|
||||
public CommandProcessingResult processCommand(final JsonCommand command) {
|
||||
|
||||
return this.writePlatformService.rejectLoanApplication(command.entityId(), command);
|
||||
return this.writePlatformService.rejectApplication(command.entityId(), command);
|
||||
}
|
||||
}
|
||||
+1
-1
@@ -27,6 +27,6 @@ public class LoanApplicationSubmittalCommandHandler implements NewCommandSourceH
|
||||
@Override
|
||||
public CommandProcessingResult processCommand(final JsonCommand command) {
|
||||
|
||||
return this.writePlatformService.submitLoanApplication(command);
|
||||
return this.writePlatformService.submitApplication(command);
|
||||
}
|
||||
}
|
||||
+1
-1
@@ -27,6 +27,6 @@ public class LoanApplicationWithdrawnByApplicantCommandHandler implements NewCom
|
||||
@Override
|
||||
public CommandProcessingResult processCommand(final JsonCommand command) {
|
||||
|
||||
return this.writePlatformService.applicantWithdrawsFromLoanApplication(command.entityId(), command);
|
||||
return this.writePlatformService.applicantWithdrawsFromApplication(command.entityId(), command);
|
||||
}
|
||||
}
|
||||
+1
-2
@@ -647,8 +647,7 @@ public final class LoanApplicationCommandFromApiJsonHelper {
|
||||
baseDataValidator.reset().parameter(note).value(noteText).notExceedingLengthOf(1000);
|
||||
}
|
||||
|
||||
if (!dataValidationErrors.isEmpty()) { throw new PlatformApiDataValidationException("validation.msg.validation.errors.exist",
|
||||
"Validation errors exist.", dataValidationErrors); }
|
||||
if (!dataValidationErrors.isEmpty()) { throw new PlatformApiDataValidationException(dataValidationErrors); }
|
||||
}
|
||||
|
||||
public void validateMinMaxConstraintValues(final JsonElement element, final LoanProduct loanProduct) {
|
||||
|
||||
+7
-7
@@ -10,17 +10,17 @@ import org.mifosplatform.infrastructure.core.data.CommandProcessingResult;
|
||||
|
||||
public interface LoanApplicationWritePlatformService {
|
||||
|
||||
CommandProcessingResult submitLoanApplication(JsonCommand command);
|
||||
CommandProcessingResult submitApplication(JsonCommand command);
|
||||
|
||||
CommandProcessingResult modifyLoanApplication(Long loanId, JsonCommand command);
|
||||
CommandProcessingResult modifyApplication(Long loanId, JsonCommand command);
|
||||
|
||||
CommandProcessingResult deleteLoanApplication(Long loanId);
|
||||
CommandProcessingResult deleteApplication(Long loanId);
|
||||
|
||||
CommandProcessingResult approveLoanApplication(Long loanId, JsonCommand command);
|
||||
CommandProcessingResult approveApplication(Long loanId, JsonCommand command);
|
||||
|
||||
CommandProcessingResult undoLoanApplicationApproval(Long loanId, JsonCommand command);
|
||||
CommandProcessingResult undoApplicationApproval(Long loanId, JsonCommand command);
|
||||
|
||||
CommandProcessingResult rejectLoanApplication(Long loanId, JsonCommand command);
|
||||
CommandProcessingResult rejectApplication(Long loanId, JsonCommand command);
|
||||
|
||||
CommandProcessingResult applicantWithdrawsFromLoanApplication(Long loanId, JsonCommand command);
|
||||
CommandProcessingResult applicantWithdrawsFromApplication(Long loanId, JsonCommand command);
|
||||
}
|
||||
+7
-7
@@ -138,7 +138,7 @@ public class LoanApplicationWritePlatformServiceJpaRepositoryImpl implements Loa
|
||||
|
||||
@Transactional
|
||||
@Override
|
||||
public CommandProcessingResult submitLoanApplication(final JsonCommand command) {
|
||||
public CommandProcessingResult submitApplication(final JsonCommand command) {
|
||||
|
||||
final AppUser currentUser = context.authenticatedUser();
|
||||
|
||||
@@ -205,7 +205,7 @@ public class LoanApplicationWritePlatformServiceJpaRepositoryImpl implements Loa
|
||||
|
||||
@Transactional
|
||||
@Override
|
||||
public CommandProcessingResult modifyLoanApplication(final Long loanId, final JsonCommand command) {
|
||||
public CommandProcessingResult modifyApplication(final Long loanId, final JsonCommand command) {
|
||||
|
||||
try {
|
||||
context.authenticatedUser();
|
||||
@@ -384,7 +384,7 @@ public class LoanApplicationWritePlatformServiceJpaRepositoryImpl implements Loa
|
||||
|
||||
@Transactional
|
||||
@Override
|
||||
public CommandProcessingResult deleteLoanApplication(final Long loanId) {
|
||||
public CommandProcessingResult deleteApplication(final Long loanId) {
|
||||
|
||||
context.authenticatedUser();
|
||||
|
||||
@@ -408,7 +408,7 @@ public class LoanApplicationWritePlatformServiceJpaRepositoryImpl implements Loa
|
||||
|
||||
@Transactional
|
||||
@Override
|
||||
public CommandProcessingResult approveLoanApplication(final Long loanId, final JsonCommand command) {
|
||||
public CommandProcessingResult approveApplication(final Long loanId, final JsonCommand command) {
|
||||
|
||||
final AppUser currentUser = context.authenticatedUser();
|
||||
|
||||
@@ -441,7 +441,7 @@ public class LoanApplicationWritePlatformServiceJpaRepositoryImpl implements Loa
|
||||
|
||||
@Transactional
|
||||
@Override
|
||||
public CommandProcessingResult undoLoanApplicationApproval(final Long loanId, final JsonCommand command) {
|
||||
public CommandProcessingResult undoApplicationApproval(final Long loanId, final JsonCommand command) {
|
||||
|
||||
context.authenticatedUser();
|
||||
|
||||
@@ -473,7 +473,7 @@ public class LoanApplicationWritePlatformServiceJpaRepositoryImpl implements Loa
|
||||
|
||||
@Transactional
|
||||
@Override
|
||||
public CommandProcessingResult rejectLoanApplication(final Long loanId, final JsonCommand command) {
|
||||
public CommandProcessingResult rejectApplication(final Long loanId, final JsonCommand command) {
|
||||
|
||||
final AppUser currentUser = context.authenticatedUser();
|
||||
|
||||
@@ -505,7 +505,7 @@ public class LoanApplicationWritePlatformServiceJpaRepositoryImpl implements Loa
|
||||
|
||||
@Transactional
|
||||
@Override
|
||||
public CommandProcessingResult applicantWithdrawsFromLoanApplication(final Long loanId, final JsonCommand command) {
|
||||
public CommandProcessingResult applicantWithdrawsFromApplication(final Long loanId, final JsonCommand command) {
|
||||
|
||||
final AppUser currentUser = context.authenticatedUser();
|
||||
|
||||
|
||||
@@ -21,6 +21,7 @@ import org.mifosplatform.portfolio.client.domain.Client;
|
||||
import org.mifosplatform.portfolio.group.domain.Group;
|
||||
import org.mifosplatform.portfolio.loanaccount.domain.Loan;
|
||||
import org.mifosplatform.portfolio.loanaccount.domain.LoanTransaction;
|
||||
import org.mifosplatform.portfolio.savings.domain.SavingsAccount;
|
||||
import org.mifosplatform.useradministration.domain.AppUser;
|
||||
|
||||
@Entity
|
||||
@@ -53,10 +54,10 @@ public class Note extends AbstractAuditableCustom<AppUser, Long> {
|
||||
@Column(name = "note_type_enum")
|
||||
private final Integer noteTypeId;
|
||||
|
||||
// @SuppressWarnings("unused")
|
||||
// @ManyToOne
|
||||
// @JoinColumn(name = "saving_account_id", nullable = true)
|
||||
// private SavingAccount savingAccount;
|
||||
@SuppressWarnings("unused")
|
||||
@ManyToOne
|
||||
@JoinColumn(name = "savings_account_id", nullable = true)
|
||||
private SavingsAccount savingsAccount;
|
||||
|
||||
public static Note clientNoteFromJson(final Client client, final JsonCommand command) {
|
||||
final String note = command.stringValueOfParameterNamed("note");
|
||||
@@ -76,10 +77,9 @@ public class Note extends AbstractAuditableCustom<AppUser, Long> {
|
||||
return new Note(loan, loanTransaction, note);
|
||||
}
|
||||
|
||||
// public static Note savingNote(final SavingAccount account, final String
|
||||
// note) {
|
||||
// return new Note(account, note);
|
||||
// }
|
||||
public static Note savingNote(final SavingsAccount account, final String note) {
|
||||
return new Note(account, note);
|
||||
}
|
||||
|
||||
private Note(final Client client, final String note) {
|
||||
this.client = client;
|
||||
@@ -118,12 +118,12 @@ public class Note extends AbstractAuditableCustom<AppUser, Long> {
|
||||
this.noteTypeId = null;
|
||||
}
|
||||
|
||||
// public Note(final SavingAccount account, final String note) {
|
||||
// this.savingAccount = account;
|
||||
// this.client = account.getClient();
|
||||
// this.note = note;
|
||||
// this.noteTypeId = NoteType.SAVING_ACCOUNT.getValue();
|
||||
// }
|
||||
public Note(final SavingsAccount account, final String note) {
|
||||
this.savingsAccount = account;
|
||||
this.client = account.getClient();
|
||||
this.note = note;
|
||||
this.noteTypeId = NoteType.SAVING_ACCOUNT.getValue();
|
||||
}
|
||||
|
||||
public Map<String, Object> update(final JsonCommand command) {
|
||||
final Map<String, Object> actualChanges = new LinkedHashMap<String, Object>(7);
|
||||
|
||||
+2
-2
@@ -26,7 +26,7 @@ public interface NoteRepository extends JpaRepository<Note, Long>, JpaSpecificat
|
||||
|
||||
Note findByLoanTransactionIdAndId(Long loanTransactionId, Long id);
|
||||
|
||||
// Note findByDepositAccountIdAndId(Long depositAccountId, Long id);
|
||||
List<Note> findBySavingsAccountId(Long savingAccountId);
|
||||
|
||||
// Note findBySavingAccountIdAndId(Long savingAccountId, Long id);
|
||||
// Note findBySavingsAccountIdAndId(Long savingAccountId, Long id);
|
||||
}
|
||||
+3
-1
@@ -3,7 +3,9 @@
|
||||
* 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;
|
||||
package org.mifosplatform.portfolio.savings;
|
||||
|
||||
import org.mifosplatform.portfolio.savings.domain.SavingsAccount;
|
||||
|
||||
/**
|
||||
* An enumeration of different transactions that can occur on a
|
||||
+7
-5
@@ -3,7 +3,7 @@
|
||||
* 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.api;
|
||||
package org.mifosplatform.portfolio.savings;
|
||||
|
||||
import java.util.Arrays;
|
||||
import java.util.HashSet;
|
||||
@@ -32,8 +32,10 @@ public class SavingsApiConstants {
|
||||
public static final String clientIdParamName = "clientId";
|
||||
public static final String groupIdParamName = "groupId";
|
||||
public static final String productIdParamName = "productId";
|
||||
public static final String fieldOfficerIdParamName = "fieldOfficerId";
|
||||
public static final String submittedOnDateParamName = "submittedOnDate";
|
||||
public static final String activeParamName = "active";
|
||||
public static final String activationDateParamName = "activationDate";
|
||||
public static final String activationDateParamName = "activatedOnDate";
|
||||
public static final String nameParamName = "name";
|
||||
public static final String descriptionParamName = "description";
|
||||
public static final String currencyCodeParamName = "currencyCode";
|
||||
@@ -52,7 +54,7 @@ public class SavingsApiConstants {
|
||||
public static final String annualFeeOnMonthDayParamName = "annualFeeOnMonthDay";
|
||||
public static final String accountingRuleParamName = "accountingRule";
|
||||
public static final String paymentTypeIdParamName = "paymentTypeId";
|
||||
public static final String accountNumberParamName = "accountNumber";
|
||||
public static final String transactionAccountNumberParamName = "accountNumber";
|
||||
public static final String checkNumberParamName = "checkNumber";
|
||||
public static final String routingCodeParamName = "routingCode";
|
||||
public static final String receiptNumberParamName = "receiptNumber";
|
||||
@@ -89,7 +91,7 @@ public class SavingsApiConstants {
|
||||
|
||||
public static final Set<String> SAVINGS_ACCOUNT_REQUEST_DATA_PARAMETERS = new HashSet<String>(Arrays.asList(localeParamName,
|
||||
dateFormatParamName, monthDayFormatParamName, accountNoParamName, externalIdParamName, clientIdParamName, groupIdParamName,
|
||||
productIdParamName, activeParamName, activationDateParamName, nominalAnnualInterestRateParamName,
|
||||
productIdParamName, fieldOfficerIdParamName, submittedOnDateParamName, nominalAnnualInterestRateParamName,
|
||||
interestCompoundingPeriodTypeParamName, interestPostingPeriodTypeParamName, interestCalculationTypeParamName,
|
||||
interestCalculationDaysInYearTypeParamName, minRequiredOpeningBalanceParamName, lockinPeriodFrequencyParamName,
|
||||
lockinPeriodFrequencyTypeParamName, withdrawalFeeAmountParamName, withdrawalFeeTypeParamName, annualFeeAmountParamName,
|
||||
@@ -112,7 +114,7 @@ public class SavingsApiConstants {
|
||||
|
||||
public static final Set<String> SAVINGS_ACCOUNT_TRANSACTION_REQUEST_DATA_PARAMETERS = new HashSet<String>(Arrays.asList(
|
||||
localeParamName, dateFormatParamName, transactionDateParamName, transactionAmountParamName, paymentTypeIdParamName,
|
||||
accountNumberParamName, checkNumberParamName, routingCodeParamName, receiptNumberParamName, bankNumberParamName));
|
||||
transactionAccountNumberParamName, checkNumberParamName, routingCodeParamName, receiptNumberParamName, bankNumberParamName));
|
||||
|
||||
public static final Set<String> SAVINGS_TRANSACTION_RESPONSE_DATA_PARAMETERS = new HashSet<String>(Arrays.asList(idParamName,
|
||||
"accountId", accountNoParamName, "currency", "amount"));
|
||||
+34
-15
@@ -3,7 +3,11 @@
|
||||
* 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;
|
||||
package org.mifosplatform.portfolio.savings;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
|
||||
|
||||
/**
|
||||
* <p>
|
||||
@@ -15,13 +19,13 @@ public enum SavingsCompoundingInterestPeriodType {
|
||||
|
||||
INVALID(0, "savingsCompoundingInterestPeriodType.invalid"), //
|
||||
DAILY(1, "savingsCompoundingInterestPeriodType.daily"), //
|
||||
WEEKLY(2, "savingsCompoundingInterestPeriodType.weekly"), //
|
||||
BIWEEKLY(3, "savingsCompoundingInterestPeriodType.biweekly"), //
|
||||
MONTHLY(4, "savingsCompoundingInterestPeriodType.monthly"), //
|
||||
QUATERLY(5, "savingsCompoundingInterestPeriodType.quarterly"), //
|
||||
BI_ANNUAL(6, "savingsCompoundingInterestPeriodType.biannual"), //
|
||||
ANNUAL(7, "savingsCompoundingInterestPeriodType.annual"), //
|
||||
NO_COMPOUNDING_SIMPLE_INTEREST(8, "savingsCompoundingInterestPeriodType.nocompounding");
|
||||
// WEEKLY(2, "savingsCompoundingInterestPeriodType.weekly"), //
|
||||
// BIWEEKLY(3, "savingsCompoundingInterestPeriodType.biweekly"), //
|
||||
MONTHLY(4, "savingsCompoundingInterestPeriodType.monthly");
|
||||
// QUATERLY(5, "savingsCompoundingInterestPeriodType.quarterly"), //
|
||||
// BI_ANNUAL(6, "savingsCompoundingInterestPeriodType.biannual"), //
|
||||
// ANNUAL(7, "savingsCompoundingInterestPeriodType.annual"), //
|
||||
// NO_COMPOUNDING_SIMPLE_INTEREST(8, "savingsCompoundingInterestPeriodType.nocompounding");
|
||||
|
||||
private final Integer value;
|
||||
private final String code;
|
||||
@@ -39,6 +43,15 @@ public enum SavingsCompoundingInterestPeriodType {
|
||||
return code;
|
||||
}
|
||||
|
||||
public static Object[] integerValues() {
|
||||
List<Integer> values = new ArrayList<Integer>();
|
||||
for (SavingsCompoundingInterestPeriodType enumType : values()) {
|
||||
values.add(enumType.getValue());
|
||||
}
|
||||
|
||||
return values.toArray();
|
||||
}
|
||||
|
||||
public static SavingsCompoundingInterestPeriodType fromInt(final Integer type) {
|
||||
SavingsCompoundingInterestPeriodType repaymentFrequencyType = SavingsCompoundingInterestPeriodType.INVALID;
|
||||
if (type != null) {
|
||||
@@ -47,28 +60,34 @@ public enum SavingsCompoundingInterestPeriodType {
|
||||
repaymentFrequencyType = SavingsCompoundingInterestPeriodType.DAILY;
|
||||
break;
|
||||
case 2:
|
||||
repaymentFrequencyType = SavingsCompoundingInterestPeriodType.WEEKLY;
|
||||
// repaymentFrequencyType =
|
||||
// SavingsCompoundingInterestPeriodType.WEEKLY;
|
||||
break;
|
||||
case 3:
|
||||
repaymentFrequencyType = SavingsCompoundingInterestPeriodType.BIWEEKLY;
|
||||
// repaymentFrequencyType =
|
||||
// SavingsCompoundingInterestPeriodType.BIWEEKLY;
|
||||
break;
|
||||
case 4:
|
||||
repaymentFrequencyType = SavingsCompoundingInterestPeriodType.MONTHLY;
|
||||
break;
|
||||
case 5:
|
||||
repaymentFrequencyType = SavingsCompoundingInterestPeriodType.QUATERLY;
|
||||
// repaymentFrequencyType =
|
||||
// SavingsCompoundingInterestPeriodType.QUATERLY;
|
||||
break;
|
||||
case 6:
|
||||
repaymentFrequencyType = SavingsCompoundingInterestPeriodType.BI_ANNUAL;
|
||||
// repaymentFrequencyType =
|
||||
// SavingsCompoundingInterestPeriodType.BI_ANNUAL;
|
||||
break;
|
||||
case 7:
|
||||
repaymentFrequencyType = SavingsCompoundingInterestPeriodType.ANNUAL;
|
||||
// repaymentFrequencyType =
|
||||
// SavingsCompoundingInterestPeriodType.ANNUAL;
|
||||
break;
|
||||
case 8:
|
||||
repaymentFrequencyType = SavingsCompoundingInterestPeriodType.NO_COMPOUNDING_SIMPLE_INTEREST;
|
||||
// repaymentFrequencyType =
|
||||
// SavingsCompoundingInterestPeriodType.NO_COMPOUNDING_SIMPLE_INTEREST;
|
||||
break;
|
||||
}
|
||||
}
|
||||
return repaymentFrequencyType;
|
||||
}
|
||||
}
|
||||
}
|
||||
+1
-1
@@ -3,7 +3,7 @@
|
||||
* 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;
|
||||
package org.mifosplatform.portfolio.savings;
|
||||
|
||||
/**
|
||||
* <ul>
|
||||
+1
-1
@@ -3,7 +3,7 @@
|
||||
* 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;
|
||||
package org.mifosplatform.portfolio.savings;
|
||||
|
||||
/**
|
||||
* <ul>
|
||||
+1
-1
@@ -3,7 +3,7 @@
|
||||
* 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;
|
||||
package org.mifosplatform.portfolio.savings;
|
||||
|
||||
/**
|
||||
* An enumeration of supported calendar periods used in savings.
|
||||
+52
@@ -0,0 +1,52 @@
|
||||
/**
|
||||
* 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;
|
||||
|
||||
/**
|
||||
* The interest posting period is the span of time at the end of which savings
|
||||
* earned but not yet credited/posted in a client's account is credited/posted.
|
||||
*/
|
||||
public enum SavingsPostingInterestPeriodType {
|
||||
|
||||
INVALID(0, "savingsPostingInterestPeriodType.invalid"), //
|
||||
MONTHLY(4, "savingsPostingInterestPeriodType.monthly"), //
|
||||
QUATERLY(5, "savingsPostingInterestPeriodType.quarterly"), //
|
||||
ANNUAL(7, "savingsPostingInterestPeriodType.annual");
|
||||
|
||||
private final Integer value;
|
||||
private final String code;
|
||||
|
||||
private SavingsPostingInterestPeriodType(final Integer value, final String code) {
|
||||
this.value = value;
|
||||
this.code = code;
|
||||
}
|
||||
|
||||
public Integer getValue() {
|
||||
return this.value;
|
||||
}
|
||||
|
||||
public String getCode() {
|
||||
return code;
|
||||
}
|
||||
|
||||
public static SavingsPostingInterestPeriodType fromInt(final Integer type) {
|
||||
SavingsPostingInterestPeriodType repaymentFrequencyType = SavingsPostingInterestPeriodType.INVALID;
|
||||
if (type != null) {
|
||||
switch (type) {
|
||||
case 4:
|
||||
repaymentFrequencyType = SavingsPostingInterestPeriodType.MONTHLY;
|
||||
break;
|
||||
case 5:
|
||||
repaymentFrequencyType = SavingsPostingInterestPeriodType.QUATERLY;
|
||||
break;
|
||||
case 7:
|
||||
repaymentFrequencyType = SavingsPostingInterestPeriodType.ANNUAL;
|
||||
break;
|
||||
}
|
||||
}
|
||||
return repaymentFrequencyType;
|
||||
}
|
||||
}
|
||||
+1
-1
@@ -3,7 +3,7 @@
|
||||
* 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;
|
||||
package org.mifosplatform.portfolio.savings;
|
||||
|
||||
public enum SavingsWithdrawalFeesType {
|
||||
|
||||
+3
-1
@@ -31,6 +31,7 @@ import org.mifosplatform.infrastructure.core.serialization.ApiRequestJsonSeriali
|
||||
import org.mifosplatform.infrastructure.core.serialization.DefaultToApiJsonSerializer;
|
||||
import org.mifosplatform.infrastructure.security.service.PlatformSecurityContext;
|
||||
import org.mifosplatform.portfolio.paymentdetail.PaymentDetailConstants;
|
||||
import org.mifosplatform.portfolio.savings.SavingsApiConstants;
|
||||
import org.mifosplatform.portfolio.savings.data.SavingsAccountTransactionData;
|
||||
import org.mifosplatform.portfolio.savings.service.SavingsAccountReadPlatformService;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
@@ -72,7 +73,8 @@ public class SavingsAccountTransactionsApiResource {
|
||||
@Path("template")
|
||||
@Consumes({ MediaType.APPLICATION_JSON })
|
||||
@Produces({ MediaType.APPLICATION_JSON })
|
||||
public String retrieveTemplate(@PathParam("savingsId") final Long savingsId, @QueryParam("command") final String commandParam,
|
||||
public String retrieveTemplate(@PathParam("savingsId") final Long savingsId,
|
||||
// @QueryParam("command") final String commandParam,
|
||||
@Context final UriInfo uriInfo) {
|
||||
|
||||
context.authenticatedUser().validateHasReadPermission(SavingsApiConstants.SAVINGS_ACCOUNT_RESOURCE_NAME);
|
||||
|
||||
+62
-10
@@ -12,6 +12,7 @@ import java.util.Set;
|
||||
|
||||
import javax.ws.rs.Consumes;
|
||||
import javax.ws.rs.DELETE;
|
||||
import javax.ws.rs.DefaultValue;
|
||||
import javax.ws.rs.GET;
|
||||
import javax.ws.rs.POST;
|
||||
import javax.ws.rs.PUT;
|
||||
@@ -36,7 +37,9 @@ import org.mifosplatform.infrastructure.core.serialization.ApiRequestJsonSeriali
|
||||
import org.mifosplatform.infrastructure.core.serialization.DefaultToApiJsonSerializer;
|
||||
import org.mifosplatform.infrastructure.core.service.Page;
|
||||
import org.mifosplatform.infrastructure.security.service.PlatformSecurityContext;
|
||||
import org.mifosplatform.organisation.staff.data.StaffData;
|
||||
import org.mifosplatform.portfolio.group.service.SearchParameters;
|
||||
import org.mifosplatform.portfolio.savings.SavingsApiConstants;
|
||||
import org.mifosplatform.portfolio.savings.data.SavingsAccountData;
|
||||
import org.mifosplatform.portfolio.savings.data.SavingsAccountTransactionData;
|
||||
import org.mifosplatform.portfolio.savings.data.SavingsProductData;
|
||||
@@ -81,12 +84,15 @@ public class SavingsAccountsApiResource {
|
||||
@Path("template")
|
||||
@Consumes({ MediaType.APPLICATION_JSON })
|
||||
@Produces({ MediaType.APPLICATION_JSON })
|
||||
public String retrieveTemplate(@QueryParam("clientId") final Long clientId, @QueryParam("groupId") final Long groupId,
|
||||
@QueryParam("productId") final Long productId, @Context final UriInfo uriInfo) {
|
||||
public String template(@QueryParam("clientId") final Long clientId, @QueryParam("groupId") final Long groupId,
|
||||
@QueryParam("productId") final Long productId,
|
||||
@DefaultValue("false") @QueryParam("staffInSelectedOfficeOnly") final boolean staffInSelectedOfficeOnly,
|
||||
@Context final UriInfo uriInfo) {
|
||||
|
||||
context.authenticatedUser().validateHasReadPermission(SavingsApiConstants.SAVINGS_ACCOUNT_RESOURCE_NAME);
|
||||
|
||||
final SavingsAccountData savingsAccount = this.savingsAccountReadPlatformService.retrieveTemplate(clientId, groupId, productId);
|
||||
final SavingsAccountData savingsAccount = this.savingsAccountReadPlatformService.retrieveTemplate(clientId, groupId, productId,
|
||||
staffInSelectedOfficeOnly);
|
||||
|
||||
final ApiRequestJsonSerializationSettings settings = apiRequestParameterHelper.process(uriInfo.getQueryParameters());
|
||||
return this.toApiJsonSerializer.serialize(settings, savingsAccount, SavingsApiConstants.SAVINGS_ACCOUNT_RESPONSE_DATA_PARAMETERS);
|
||||
@@ -113,7 +119,7 @@ public class SavingsAccountsApiResource {
|
||||
@POST
|
||||
@Consumes({ MediaType.APPLICATION_JSON })
|
||||
@Produces({ MediaType.APPLICATION_JSON })
|
||||
public String create(final String apiRequestBodyAsJson) {
|
||||
public String submitApplication(final String apiRequestBodyAsJson) {
|
||||
|
||||
final CommandWrapper commandRequest = new CommandWrapperBuilder().createSavingsAccount().withJson(apiRequestBodyAsJson).build();
|
||||
|
||||
@@ -147,6 +153,7 @@ public class SavingsAccountsApiResource {
|
||||
|
||||
Collection<SavingsAccountTransactionData> transactions = null;
|
||||
Collection<SavingsProductData> productOptions = null;
|
||||
Collection<StaffData> fieldOfficerOptions = null;
|
||||
Collection<EnumOptionData> interestCompoundingPeriodTypeOptions = null;
|
||||
Collection<EnumOptionData> interestCompoundingPostingTypeOptions = null;
|
||||
Collection<EnumOptionData> interestCalculationTypeOptions = null;
|
||||
@@ -174,16 +181,49 @@ public class SavingsAccountsApiResource {
|
||||
final ApiRequestJsonSerializationSettings settings = apiRequestParameterHelper.process(uriInfo.getQueryParameters());
|
||||
if (settings.isTemplate()) {
|
||||
productOptions = this.savingsProductReadPlatformService.retrieveAllForLookup();
|
||||
|
||||
// FIXME - FOR CHANGE SAVINGS ACCOUNT APPLICATION need to determine
|
||||
// office id of savings account
|
||||
// if (savingsAccount.officeId() != null) {
|
||||
//
|
||||
// if (staffInSelectedOfficeOnly) {
|
||||
// // only bring back loan officers in selected branch/office
|
||||
// Collection<StaffData> fieldOfficersInBranch =
|
||||
// this.staffReadPlatformService
|
||||
// .retrieveAllLoanOfficersInOfficeById(officeId);
|
||||
//
|
||||
// if (!CollectionUtils.isEmpty(fieldOfficersInBranch)) {
|
||||
// fieldOfficerOptions = new
|
||||
// ArrayList<StaffData>(fieldOfficersInBranch);
|
||||
// }
|
||||
// } else {
|
||||
// // by default bring back all officers in selected
|
||||
// // branch/office as well as officers in office above
|
||||
// // this office
|
||||
// final boolean restrictToLoanOfficersOnly = true;
|
||||
// Collection<StaffData> loanOfficersInHierarchy =
|
||||
// this.staffReadPlatformService
|
||||
// .retrieveAllStaffInOfficeAndItsParentOfficeHierarchy(officeId,
|
||||
// restrictToLoanOfficersOnly);
|
||||
//
|
||||
// if (!CollectionUtils.isEmpty(loanOfficersInHierarchy)) {
|
||||
// fieldOfficerOptions = new
|
||||
// ArrayList<StaffData>(loanOfficersInHierarchy);
|
||||
// }
|
||||
// }
|
||||
// }
|
||||
|
||||
interestCompoundingPeriodTypeOptions = this.dropdownReadPlatformService.retrieveCompoundingInterestPeriodTypeOptions();
|
||||
interestCompoundingPostingTypeOptions = this.dropdownReadPlatformService.retrieveInterestPostingPeriodTypeOptions();
|
||||
interestCalculationTypeOptions = this.dropdownReadPlatformService.retrieveInterestCalculationTypeOptions();
|
||||
interestCalculationDaysInYearTypeOptions = this.dropdownReadPlatformService.retrieveInterestCalculationDaysInYearTypeOptions();
|
||||
lockinPeriodFrequencyTypeOptions = this.dropdownReadPlatformService.retrieveLockinPeriodFrequencyTypeOptions();
|
||||
withdrawalFeeTypeOptions = this.dropdownReadPlatformService.retrievewithdrawalFeeTypeOptions();
|
||||
}
|
||||
|
||||
return SavingsAccountData.withTemplateOptions(savingsAccount, productOptions, interestCompoundingPeriodTypeOptions,
|
||||
interestCompoundingPostingTypeOptions, interestCalculationTypeOptions, interestCalculationDaysInYearTypeOptions,
|
||||
lockinPeriodFrequencyTypeOptions, withdrawalFeeTypeOptions, transactions);
|
||||
return SavingsAccountData.withTemplateOptions(savingsAccount, productOptions, fieldOfficerOptions,
|
||||
interestCompoundingPeriodTypeOptions, interestCompoundingPostingTypeOptions, interestCalculationTypeOptions,
|
||||
interestCalculationDaysInYearTypeOptions, lockinPeriodFrequencyTypeOptions, withdrawalFeeTypeOptions, transactions);
|
||||
}
|
||||
|
||||
@PUT
|
||||
@@ -210,7 +250,19 @@ public class SavingsAccountsApiResource {
|
||||
final CommandWrapperBuilder builder = new CommandWrapperBuilder().withJson(apiRequestBodyAsJson);
|
||||
|
||||
CommandProcessingResult result = null;
|
||||
if (is(commandParam, "activate")) {
|
||||
if (is(commandParam, "reject")) {
|
||||
final CommandWrapper commandRequest = builder.rejectSavingsAccountApplication(accountId).build();
|
||||
result = this.commandsSourceWritePlatformService.logCommandSource(commandRequest);
|
||||
} else if (is(commandParam, "withdrawnByApplicant")) {
|
||||
final CommandWrapper commandRequest = builder.withdrawSavingsAccountApplication(accountId).build();
|
||||
result = this.commandsSourceWritePlatformService.logCommandSource(commandRequest);
|
||||
} else if (is(commandParam, "approve")) {
|
||||
final CommandWrapper commandRequest = builder.approveSavingsAccountApplication(accountId).build();
|
||||
result = this.commandsSourceWritePlatformService.logCommandSource(commandRequest);
|
||||
} else if (is(commandParam, "undoapproval")) {
|
||||
final CommandWrapper commandRequest = builder.undoSavingsAccountApplication(accountId).build();
|
||||
result = this.commandsSourceWritePlatformService.logCommandSource(commandRequest);
|
||||
} else if (is(commandParam, "activate")) {
|
||||
final CommandWrapper commandRequest = builder.savingsAccountActivation(accountId).build();
|
||||
result = this.commandsSourceWritePlatformService.logCommandSource(commandRequest);
|
||||
} else if (is(commandParam, "calculateInterest")) {
|
||||
@@ -223,8 +275,8 @@ public class SavingsAccountsApiResource {
|
||||
|
||||
if (result == null) {
|
||||
//
|
||||
throw new UnrecognizedQueryParamException("command", commandParam, new Object[] { "activate", "calculateInterest",
|
||||
"postInterest" });
|
||||
throw new UnrecognizedQueryParamException("command", commandParam, new Object[] { "reject", "withdrawnByApplicant", "approve",
|
||||
"undoapproval", "activate", "calculateInterest", "postInterest" });
|
||||
}
|
||||
|
||||
return this.toApiJsonSerializer.serialize(result);
|
||||
|
||||
+6
-5
@@ -42,11 +42,12 @@ import org.mifosplatform.infrastructure.security.service.PlatformSecurityContext
|
||||
import org.mifosplatform.organisation.monetary.data.CurrencyData;
|
||||
import org.mifosplatform.organisation.monetary.service.CurrencyReadPlatformService;
|
||||
import org.mifosplatform.portfolio.paymentdetail.PaymentDetailConstants;
|
||||
import org.mifosplatform.portfolio.savings.SavingsApiConstants;
|
||||
import org.mifosplatform.portfolio.savings.SavingsCompoundingInterestPeriodType;
|
||||
import org.mifosplatform.portfolio.savings.SavingsInterestCalculationDaysInYearType;
|
||||
import org.mifosplatform.portfolio.savings.SavingsInterestCalculationType;
|
||||
import org.mifosplatform.portfolio.savings.SavingsPostingInterestPeriodType;
|
||||
import org.mifosplatform.portfolio.savings.data.SavingsProductData;
|
||||
import org.mifosplatform.portfolio.savings.domain.SavingsCompoundingInterestPeriodType;
|
||||
import org.mifosplatform.portfolio.savings.domain.SavingsInterestCalculationDaysInYearType;
|
||||
import org.mifosplatform.portfolio.savings.domain.SavingsInterestCalculationType;
|
||||
import org.mifosplatform.portfolio.savings.domain.SavingsInterestPostingPeriodType;
|
||||
import org.mifosplatform.portfolio.savings.service.SavingsDropdownReadPlatformService;
|
||||
import org.mifosplatform.portfolio.savings.service.SavingsEnumerations;
|
||||
import org.mifosplatform.portfolio.savings.service.SavingsProductReadPlatformService;
|
||||
@@ -180,7 +181,7 @@ public class SavingsProductsApiResource {
|
||||
.compoundingInterestPeriodType(SavingsCompoundingInterestPeriodType.DAILY);
|
||||
|
||||
final EnumOptionData interestPostingPeriodType = SavingsEnumerations
|
||||
.interestPostingPeriodType(SavingsInterestPostingPeriodType.MONTHLY);
|
||||
.interestPostingPeriodType(SavingsPostingInterestPeriodType.MONTHLY);
|
||||
|
||||
final EnumOptionData interestCalculationType = SavingsEnumerations
|
||||
.interestCalculationType(SavingsInterestCalculationType.DAILY_BALANCE);
|
||||
|
||||
+109
@@ -0,0 +1,109 @@
|
||||
/**
|
||||
* 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;
|
||||
|
||||
import org.joda.time.LocalDate;
|
||||
|
||||
/**
|
||||
* Immutable data object represent the important time-line events of a savings
|
||||
* account application.
|
||||
*/
|
||||
@SuppressWarnings("unused")
|
||||
public class SavingsAccountApplicationTimelineData {
|
||||
|
||||
private final LocalDate submittedOnDate;
|
||||
private final String submittedByUsername;
|
||||
private final String submittedByFirstname;
|
||||
private final String submittedByLastname;
|
||||
private final LocalDate rejectedOnDate;
|
||||
private final String rejectedByUsername;
|
||||
private final String rejectedByFirstname;
|
||||
private final String rejectedByLastname;
|
||||
private final LocalDate withdrawnOnDate;
|
||||
private final String withdrawnByUsername;
|
||||
private final String withdrawnByFirstname;
|
||||
private final String withdrawnByLastname;
|
||||
private final LocalDate approvedOnDate;
|
||||
private final String approvedByUsername;
|
||||
private final String approvedByFirstname;
|
||||
private final String approvedByLastname;
|
||||
private final LocalDate activatedOnDate;
|
||||
private final String activatedByUsername;
|
||||
private final String activatedByFirstname;
|
||||
private final String activatedByLastname;
|
||||
private final LocalDate closedOnDate;
|
||||
private final String closedByUsername;
|
||||
private final String closedByFirstname;
|
||||
private final String closedByLastname;
|
||||
|
||||
public static SavingsAccountApplicationTimelineData templateDefault() {
|
||||
|
||||
final LocalDate submittedOnDate = null;
|
||||
final String submittedByUsername = null;
|
||||
final String submittedByFirstname = null;
|
||||
final String submittedByLastname = null;
|
||||
final LocalDate rejectedOnDate = null;
|
||||
final String rejectedByUsername = null;
|
||||
final String rejectedByFirstname = null;
|
||||
final String rejectedByLastname = null;
|
||||
final LocalDate withdrawnOnDate = null;
|
||||
final String withdrawnByUsername = null;
|
||||
final String withdrawnByFirstname = null;
|
||||
final String withdrawnByLastname = null;
|
||||
final LocalDate approvedOnDate = null;
|
||||
final String approvedByUsername = null;
|
||||
final String approvedByFirstname = null;
|
||||
final String approvedByLastname = null;
|
||||
final LocalDate activatedOnDate = null;
|
||||
final String activatedByUsername = null;
|
||||
final String activatedByFirstname = null;
|
||||
final String activatedByLastname = null;
|
||||
final LocalDate closedOnDate = null;
|
||||
final String closedByUsername = null;
|
||||
final String closedByFirstname = null;
|
||||
final String closedByLastname = null;
|
||||
|
||||
return new SavingsAccountApplicationTimelineData(submittedOnDate, submittedByUsername, submittedByFirstname, submittedByLastname,
|
||||
rejectedOnDate, rejectedByUsername, rejectedByFirstname, rejectedByLastname, withdrawnOnDate, withdrawnByUsername,
|
||||
withdrawnByFirstname, withdrawnByLastname, approvedOnDate, approvedByUsername, approvedByFirstname, approvedByLastname,
|
||||
activatedOnDate, activatedByUsername, activatedByFirstname, activatedByLastname, closedOnDate, closedByUsername,
|
||||
closedByFirstname, closedByLastname);
|
||||
}
|
||||
|
||||
public SavingsAccountApplicationTimelineData(final LocalDate submittedOnDate, final String submittedByUsername,
|
||||
final String submittedByFirstname, final String submittedByLastname, final LocalDate rejectedOnDate,
|
||||
final String rejectedByUsername, final String rejectedByFirstname, final String rejectedByLastname,
|
||||
final LocalDate withdrawnOnDate, final String withdrawnByUsername, final String withdrawnByFirstname,
|
||||
final String withdrawnByLastname, final LocalDate approvedOnDate, final String approvedByUsername,
|
||||
final String approvedByFirstname, final String approvedByLastname, final LocalDate activatedOnDate,
|
||||
final String activatedByUsername, final String activatedByFirstname, final String activatedByLastname,
|
||||
final LocalDate closedOnDate, final String closedByUsername, final String closedByFirstname, final String closedByLastname) {
|
||||
this.submittedOnDate = submittedOnDate;
|
||||
this.submittedByUsername = submittedByUsername;
|
||||
this.submittedByFirstname = submittedByFirstname;
|
||||
this.submittedByLastname = submittedByLastname;
|
||||
this.rejectedOnDate = rejectedOnDate;
|
||||
this.rejectedByUsername = rejectedByUsername;
|
||||
this.rejectedByFirstname = rejectedByFirstname;
|
||||
this.rejectedByLastname = rejectedByLastname;
|
||||
this.withdrawnOnDate = withdrawnOnDate;
|
||||
this.withdrawnByUsername = withdrawnByUsername;
|
||||
this.withdrawnByFirstname = withdrawnByFirstname;
|
||||
this.withdrawnByLastname = withdrawnByLastname;
|
||||
this.approvedOnDate = approvedOnDate;
|
||||
this.approvedByUsername = approvedByUsername;
|
||||
this.approvedByFirstname = approvedByFirstname;
|
||||
this.approvedByLastname = approvedByLastname;
|
||||
this.activatedOnDate = activatedOnDate;
|
||||
this.activatedByUsername = activatedByUsername;
|
||||
this.activatedByFirstname = activatedByFirstname;
|
||||
this.activatedByLastname = activatedByLastname;
|
||||
this.closedOnDate = closedOnDate;
|
||||
this.closedByUsername = closedByUsername;
|
||||
this.closedByFirstname = closedByFirstname;
|
||||
this.closedByLastname = closedByLastname;
|
||||
}
|
||||
}
|
||||
+65
-49
@@ -12,6 +12,7 @@ import org.joda.time.LocalDate;
|
||||
import org.joda.time.MonthDay;
|
||||
import org.mifosplatform.infrastructure.core.data.EnumOptionData;
|
||||
import org.mifosplatform.organisation.monetary.data.CurrencyData;
|
||||
import org.mifosplatform.organisation.staff.data.StaffData;
|
||||
|
||||
/**
|
||||
* Immutable data object representing a savings account.
|
||||
@@ -21,14 +22,16 @@ public class SavingsAccountData {
|
||||
private final Long id;
|
||||
private final String accountNo;
|
||||
private final String externalId;
|
||||
private final SavingsAccountStatusEnumData status;
|
||||
private final LocalDate activationDate;
|
||||
private final Long groupId;
|
||||
private final String groupName;
|
||||
private final Long clientId;
|
||||
private final String clientName;
|
||||
private final Long savingsProductId;
|
||||
private final String savingsProductName;
|
||||
private final Long fieldofficerId;
|
||||
private final String fieldofficerName;
|
||||
private final SavingsAccountStatusEnumData status;
|
||||
private final SavingsAccountApplicationTimelineData timeline;
|
||||
private final CurrencyData currency;
|
||||
private final BigDecimal nominalAnnualInterestRate;
|
||||
private final EnumOptionData interestCompoundingPeriodType;
|
||||
@@ -53,6 +56,8 @@ public class SavingsAccountData {
|
||||
@SuppressWarnings("unused")
|
||||
private final Collection<SavingsProductData> productOptions;
|
||||
@SuppressWarnings("unused")
|
||||
private final Collection<StaffData> fieldOfficerOptions;
|
||||
@SuppressWarnings("unused")
|
||||
private final Collection<EnumOptionData> interestCompoundingPeriodTypeOptions;
|
||||
@SuppressWarnings("unused")
|
||||
private final Collection<EnumOptionData> interestPostingPeriodTypeOptions;
|
||||
@@ -65,17 +70,19 @@ public class SavingsAccountData {
|
||||
@SuppressWarnings("unused")
|
||||
private final Collection<EnumOptionData> withdrawalFeeTypeOptions;
|
||||
|
||||
public static SavingsAccountData instance(final Long id, final String accountNo, final String externalId,
|
||||
final SavingsAccountStatusEnumData status, final LocalDate activationDate, final Long groupId, final String groupName,
|
||||
final Long clientId, final String clientName, final Long productId, final String productName, final CurrencyData currency,
|
||||
final BigDecimal interestRate, final EnumOptionData interestCompoundingPeriodType,
|
||||
final EnumOptionData interestPostingPeriodType, final EnumOptionData interestCalculationType,
|
||||
final EnumOptionData interestCalculationDaysInYearType, final BigDecimal minRequiredOpeningBalance,
|
||||
final Integer lockinPeriodFrequency, final EnumOptionData lockinPeriodFrequencyType, final BigDecimal withdrawalFeeAmount,
|
||||
final EnumOptionData withdrawalFeeType, final BigDecimal annualFeeAmount, final MonthDay annualFeeOnMonthDay,
|
||||
final LocalDate annualFeeNextDueDate, final SavingsAccountSummaryData summary) {
|
||||
public static SavingsAccountData instance(final Long id, final String accountNo, final String externalId, final Long groupId,
|
||||
final String groupName, final Long clientId, final String clientName, final Long productId, final String productName,
|
||||
final Long fieldOfficerId, final String fieldOfficerName, final SavingsAccountStatusEnumData status,
|
||||
final SavingsAccountApplicationTimelineData timeline, final CurrencyData currency, final BigDecimal interestRate,
|
||||
final EnumOptionData interestCompoundingPeriodType, final EnumOptionData interestPostingPeriodType,
|
||||
final EnumOptionData interestCalculationType, final EnumOptionData interestCalculationDaysInYearType,
|
||||
final BigDecimal minRequiredOpeningBalance, final Integer lockinPeriodFrequency,
|
||||
final EnumOptionData lockinPeriodFrequencyType, final BigDecimal withdrawalFeeAmount, final EnumOptionData withdrawalFeeType,
|
||||
final BigDecimal annualFeeAmount, final MonthDay annualFeeOnMonthDay, final LocalDate annualFeeNextDueDate,
|
||||
final SavingsAccountSummaryData summary) {
|
||||
|
||||
final Collection<SavingsProductData> productOptions = null;
|
||||
final Collection<StaffData> fieldOfficerOptions = null;
|
||||
final Collection<EnumOptionData> interestCompoundingPeriodTypeOptions = null;
|
||||
final Collection<EnumOptionData> interestPostingPeriodTypeOptions = null;
|
||||
final Collection<EnumOptionData> interestCalculationTypeOptions = null;
|
||||
@@ -85,32 +92,34 @@ public class SavingsAccountData {
|
||||
|
||||
final Collection<SavingsAccountTransactionData> transactions = null;
|
||||
|
||||
return new SavingsAccountData(id, accountNo, externalId, status, activationDate, groupId, groupName, clientId, clientName,
|
||||
productId, productName, currency, interestRate, interestCompoundingPeriodType, interestPostingPeriodType,
|
||||
interestCalculationType, interestCalculationDaysInYearType, minRequiredOpeningBalance, lockinPeriodFrequency,
|
||||
lockinPeriodFrequencyType, withdrawalFeeAmount, withdrawalFeeType, annualFeeAmount, annualFeeOnMonthDay,
|
||||
annualFeeNextDueDate, summary, transactions, productOptions, interestCompoundingPeriodTypeOptions,
|
||||
interestPostingPeriodTypeOptions, interestCalculationTypeOptions, interestCalculationDaysInYearTypeOptions,
|
||||
lockinPeriodFrequencyTypeOptions, withdrawalFeeTypeOptions);
|
||||
return new SavingsAccountData(id, accountNo, externalId, groupId, groupName, clientId, clientName, productId, productName,
|
||||
fieldOfficerId, fieldOfficerName, status, timeline, currency, interestRate, interestCompoundingPeriodType,
|
||||
interestPostingPeriodType, interestCalculationType, interestCalculationDaysInYearType, minRequiredOpeningBalance,
|
||||
lockinPeriodFrequency, lockinPeriodFrequencyType, withdrawalFeeAmount, withdrawalFeeType, annualFeeAmount,
|
||||
annualFeeOnMonthDay, annualFeeNextDueDate, summary, transactions, productOptions, fieldOfficerOptions,
|
||||
interestCompoundingPeriodTypeOptions, interestPostingPeriodTypeOptions, interestCalculationTypeOptions,
|
||||
interestCalculationDaysInYearTypeOptions, lockinPeriodFrequencyTypeOptions, withdrawalFeeTypeOptions);
|
||||
}
|
||||
|
||||
public static SavingsAccountData withTemplateOptions(final SavingsAccountData account,
|
||||
final Collection<SavingsProductData> productOptions, final Collection<EnumOptionData> interestCompoundingPeriodTypeOptions,
|
||||
final Collection<SavingsProductData> productOptions, final Collection<StaffData> fieldOfficerOptions,
|
||||
final Collection<EnumOptionData> interestCompoundingPeriodTypeOptions,
|
||||
final Collection<EnumOptionData> interestPostingPeriodTypeOptions,
|
||||
final Collection<EnumOptionData> interestCalculationTypeOptions,
|
||||
final Collection<EnumOptionData> interestCalculationDaysInYearTypeOptions,
|
||||
final Collection<EnumOptionData> lockinPeriodFrequencyTypeOptions, final Collection<EnumOptionData> withdrawalFeeTypeOptions,
|
||||
final Collection<SavingsAccountTransactionData> transactions) {
|
||||
|
||||
return new SavingsAccountData(account.id, account.accountNo, account.externalId, account.status, account.activationDate,
|
||||
account.groupId, account.groupName, account.clientId, account.clientName, account.savingsProductId,
|
||||
account.savingsProductName, account.currency, account.nominalAnnualInterestRate, account.interestCompoundingPeriodType,
|
||||
account.interestPostingPeriodType, account.interestCalculationType, account.interestCalculationDaysInYearType,
|
||||
account.minRequiredOpeningBalance, account.lockinPeriodFrequency, account.lockinPeriodFrequencyType,
|
||||
account.withdrawalFeeAmount, account.withdrawalFeeType, account.annualFeeAmount, account.annualFeeOnMonthDay,
|
||||
account.annualFeeNextDueDate, account.summary, transactions, productOptions, interestCompoundingPeriodTypeOptions,
|
||||
interestPostingPeriodTypeOptions, interestCalculationTypeOptions, interestCalculationDaysInYearTypeOptions,
|
||||
lockinPeriodFrequencyTypeOptions, withdrawalFeeTypeOptions);
|
||||
return new SavingsAccountData(account.id, account.accountNo, account.externalId, account.groupId, account.groupName,
|
||||
account.clientId, account.clientName, account.savingsProductId, account.savingsProductName, account.fieldofficerId,
|
||||
account.fieldofficerName, account.status, account.timeline, account.currency, account.nominalAnnualInterestRate,
|
||||
account.interestCompoundingPeriodType, account.interestPostingPeriodType, account.interestCalculationType,
|
||||
account.interestCalculationDaysInYearType, account.minRequiredOpeningBalance, account.lockinPeriodFrequency,
|
||||
account.lockinPeriodFrequencyType, account.withdrawalFeeAmount, account.withdrawalFeeType, account.annualFeeAmount,
|
||||
account.annualFeeOnMonthDay, account.annualFeeNextDueDate, account.summary, transactions, productOptions,
|
||||
fieldOfficerOptions, interestCompoundingPeriodTypeOptions, interestPostingPeriodTypeOptions,
|
||||
interestCalculationTypeOptions, interestCalculationDaysInYearTypeOptions, lockinPeriodFrequencyTypeOptions,
|
||||
withdrawalFeeTypeOptions);
|
||||
}
|
||||
|
||||
public static SavingsAccountData withClientTemplate(final Long clientId, final String clientName, final Long groupId,
|
||||
@@ -119,10 +128,12 @@ public class SavingsAccountData {
|
||||
final Long id = null;
|
||||
final String accountNo = null;
|
||||
final String externalId = null;
|
||||
final SavingsAccountStatusEnumData status = null;
|
||||
final LocalDate activationDate = null;
|
||||
final Long productId = null;
|
||||
final String productName = null;
|
||||
final Long fieldOfficerId = null;
|
||||
final String fieldOfficerName = null;
|
||||
final SavingsAccountStatusEnumData status = null;
|
||||
final SavingsAccountApplicationTimelineData timeline = null;
|
||||
final CurrencyData currency = null;
|
||||
final BigDecimal nominalAnnualInterestRate = null;
|
||||
final EnumOptionData interestPeriodType = null;
|
||||
@@ -142,6 +153,7 @@ public class SavingsAccountData {
|
||||
final Collection<SavingsAccountTransactionData> transactions = null;
|
||||
|
||||
final Collection<SavingsProductData> productOptions = null;
|
||||
final Collection<StaffData> fieldOfficerOptions = null;
|
||||
final Collection<EnumOptionData> interestCompoundingPeriodTypeOptions = null;
|
||||
final Collection<EnumOptionData> interestPostingPeriodTypeOptions = null;
|
||||
final Collection<EnumOptionData> interestCalculationTypeOptions = null;
|
||||
@@ -149,25 +161,26 @@ public class SavingsAccountData {
|
||||
final Collection<EnumOptionData> lockinPeriodFrequencyTypeOptions = null;
|
||||
final Collection<EnumOptionData> withdrawalFeeTypeOptions = null;
|
||||
|
||||
return new SavingsAccountData(id, accountNo, externalId, status, activationDate, groupId, groupName, clientId, clientName,
|
||||
productId, productName, currency, nominalAnnualInterestRate, interestPeriodType, interestPostingPeriodType,
|
||||
interestCalculationType, interestCalculationDaysInYearType, minRequiredOpeningBalance, lockinPeriodFrequency,
|
||||
lockinPeriodFrequencyType, withdrawalFeeAmount, withdrawalFeeType, annualFeeAmount, annualFeeOnMonthDay,
|
||||
annualFeeNextDueDate, summary, transactions, productOptions, interestCompoundingPeriodTypeOptions,
|
||||
interestPostingPeriodTypeOptions, interestCalculationTypeOptions, interestCalculationDaysInYearTypeOptions,
|
||||
lockinPeriodFrequencyTypeOptions, withdrawalFeeTypeOptions);
|
||||
return new SavingsAccountData(id, accountNo, externalId, groupId, groupName, clientId, clientName, productId, productName,
|
||||
fieldOfficerId, fieldOfficerName, status, timeline, currency, nominalAnnualInterestRate, interestPeriodType,
|
||||
interestPostingPeriodType, interestCalculationType, interestCalculationDaysInYearType, minRequiredOpeningBalance,
|
||||
lockinPeriodFrequency, lockinPeriodFrequencyType, withdrawalFeeAmount, withdrawalFeeType, annualFeeAmount,
|
||||
annualFeeOnMonthDay, annualFeeNextDueDate, summary, transactions, productOptions, fieldOfficerOptions,
|
||||
interestCompoundingPeriodTypeOptions, interestPostingPeriodTypeOptions, interestCalculationTypeOptions,
|
||||
interestCalculationDaysInYearTypeOptions, lockinPeriodFrequencyTypeOptions, withdrawalFeeTypeOptions);
|
||||
}
|
||||
|
||||
private SavingsAccountData(final Long id, final String accountNo, final String externalId, final SavingsAccountStatusEnumData status,
|
||||
final LocalDate activationDate, final Long groupId, final String groupName, final Long clientId, final String clientName,
|
||||
final Long productId, final String productName, final CurrencyData currency, final BigDecimal nominalAnnualInterestRate,
|
||||
final EnumOptionData interestPeriodType, final EnumOptionData interestPostingPeriodType,
|
||||
final EnumOptionData interestCalculationType, final EnumOptionData interestCalculationDaysInYearType,
|
||||
final BigDecimal minRequiredOpeningBalance, final Integer lockinPeriodFrequency,
|
||||
final EnumOptionData lockinPeriodFrequencyType, final BigDecimal withdrawalFeeAmount, final EnumOptionData withdrawalFeeType,
|
||||
final BigDecimal annualFeeAmount, final MonthDay annualFeeOnMonthDay, final LocalDate annualFeeNextDueDate,
|
||||
final SavingsAccountSummaryData summary, final Collection<SavingsAccountTransactionData> transactions,
|
||||
final Collection<SavingsProductData> productOptions, final Collection<EnumOptionData> interestCompoundingPeriodTypeOptions,
|
||||
private SavingsAccountData(final Long id, final String accountNo, final String externalId, final Long groupId, final String groupName,
|
||||
final Long clientId, final String clientName, final Long productId, final String productName, final Long fieldofficerId,
|
||||
final String fieldofficerName, final SavingsAccountStatusEnumData status, final SavingsAccountApplicationTimelineData timeline,
|
||||
final CurrencyData currency, final BigDecimal nominalAnnualInterestRate, final EnumOptionData interestPeriodType,
|
||||
final EnumOptionData interestPostingPeriodType, final EnumOptionData interestCalculationType,
|
||||
final EnumOptionData interestCalculationDaysInYearType, final BigDecimal minRequiredOpeningBalance,
|
||||
final Integer lockinPeriodFrequency, final EnumOptionData lockinPeriodFrequencyType, final BigDecimal withdrawalFeeAmount,
|
||||
final EnumOptionData withdrawalFeeType, final BigDecimal annualFeeAmount, final MonthDay annualFeeOnMonthDay,
|
||||
final LocalDate annualFeeNextDueDate, final SavingsAccountSummaryData summary,
|
||||
final Collection<SavingsAccountTransactionData> transactions, final Collection<SavingsProductData> productOptions,
|
||||
final Collection<StaffData> fieldOfficerOptions, final Collection<EnumOptionData> interestCompoundingPeriodTypeOptions,
|
||||
final Collection<EnumOptionData> interestPostingPeriodTypeOptions,
|
||||
final Collection<EnumOptionData> interestCalculationTypeOptions,
|
||||
final Collection<EnumOptionData> interestCalculationDaysInYearTypeOptions,
|
||||
@@ -175,14 +188,16 @@ public class SavingsAccountData {
|
||||
this.id = id;
|
||||
this.accountNo = accountNo;
|
||||
this.externalId = externalId;
|
||||
this.status = status;
|
||||
this.activationDate = activationDate;
|
||||
this.groupId = groupId;
|
||||
this.groupName = groupName;
|
||||
this.clientId = clientId;
|
||||
this.clientName = clientName;
|
||||
this.savingsProductId = productId;
|
||||
this.savingsProductName = productName;
|
||||
this.fieldofficerId = fieldofficerId;
|
||||
this.fieldofficerName = fieldofficerName;
|
||||
this.status = status;
|
||||
this.timeline = timeline;
|
||||
this.currency = currency;
|
||||
this.nominalAnnualInterestRate = nominalAnnualInterestRate;
|
||||
this.interestCompoundingPeriodType = interestPeriodType;
|
||||
@@ -202,6 +217,7 @@ public class SavingsAccountData {
|
||||
this.transactions = transactions;
|
||||
|
||||
this.productOptions = productOptions;
|
||||
this.fieldOfficerOptions = fieldOfficerOptions;
|
||||
this.interestCompoundingPeriodTypeOptions = interestCompoundingPeriodTypeOptions;
|
||||
this.interestPostingPeriodTypeOptions = interestPostingPeriodTypeOptions;
|
||||
this.interestCalculationTypeOptions = interestCalculationTypeOptions;
|
||||
|
||||
+63
-58
@@ -5,25 +5,24 @@
|
||||
*/
|
||||
package org.mifosplatform.portfolio.savings.data;
|
||||
|
||||
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.annualFeeAmountParamName;
|
||||
import static org.mifosplatform.portfolio.savings.api.SavingsApiConstants.annualFeeOnMonthDayParamName;
|
||||
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.groupIdParamName;
|
||||
import static org.mifosplatform.portfolio.savings.api.SavingsApiConstants.interestCalculationDaysInYearTypeParamName;
|
||||
import static org.mifosplatform.portfolio.savings.api.SavingsApiConstants.interestCalculationTypeParamName;
|
||||
import static org.mifosplatform.portfolio.savings.api.SavingsApiConstants.interestCompoundingPeriodTypeParamName;
|
||||
import static org.mifosplatform.portfolio.savings.api.SavingsApiConstants.interestPostingPeriodTypeParamName;
|
||||
import static org.mifosplatform.portfolio.savings.api.SavingsApiConstants.lockinPeriodFrequencyParamName;
|
||||
import static org.mifosplatform.portfolio.savings.api.SavingsApiConstants.lockinPeriodFrequencyTypeParamName;
|
||||
import static org.mifosplatform.portfolio.savings.api.SavingsApiConstants.minRequiredOpeningBalanceParamName;
|
||||
import static org.mifosplatform.portfolio.savings.api.SavingsApiConstants.nominalAnnualInterestRateParamName;
|
||||
import static org.mifosplatform.portfolio.savings.api.SavingsApiConstants.productIdParamName;
|
||||
import static org.mifosplatform.portfolio.savings.api.SavingsApiConstants.withdrawalFeeAmountParamName;
|
||||
import static org.mifosplatform.portfolio.savings.api.SavingsApiConstants.withdrawalFeeTypeParamName;
|
||||
import static org.mifosplatform.portfolio.savings.SavingsApiConstants.accountNoParamName;
|
||||
import static org.mifosplatform.portfolio.savings.SavingsApiConstants.annualFeeAmountParamName;
|
||||
import static org.mifosplatform.portfolio.savings.SavingsApiConstants.annualFeeOnMonthDayParamName;
|
||||
import static org.mifosplatform.portfolio.savings.SavingsApiConstants.clientIdParamName;
|
||||
import static org.mifosplatform.portfolio.savings.SavingsApiConstants.externalIdParamName;
|
||||
import static org.mifosplatform.portfolio.savings.SavingsApiConstants.groupIdParamName;
|
||||
import static org.mifosplatform.portfolio.savings.SavingsApiConstants.interestCalculationDaysInYearTypeParamName;
|
||||
import static org.mifosplatform.portfolio.savings.SavingsApiConstants.interestCalculationTypeParamName;
|
||||
import static org.mifosplatform.portfolio.savings.SavingsApiConstants.interestCompoundingPeriodTypeParamName;
|
||||
import static org.mifosplatform.portfolio.savings.SavingsApiConstants.interestPostingPeriodTypeParamName;
|
||||
import static org.mifosplatform.portfolio.savings.SavingsApiConstants.lockinPeriodFrequencyParamName;
|
||||
import static org.mifosplatform.portfolio.savings.SavingsApiConstants.lockinPeriodFrequencyTypeParamName;
|
||||
import static org.mifosplatform.portfolio.savings.SavingsApiConstants.minRequiredOpeningBalanceParamName;
|
||||
import static org.mifosplatform.portfolio.savings.SavingsApiConstants.nominalAnnualInterestRateParamName;
|
||||
import static org.mifosplatform.portfolio.savings.SavingsApiConstants.productIdParamName;
|
||||
import static org.mifosplatform.portfolio.savings.SavingsApiConstants.submittedOnDateParamName;
|
||||
import static org.mifosplatform.portfolio.savings.SavingsApiConstants.withdrawalFeeAmountParamName;
|
||||
import static org.mifosplatform.portfolio.savings.SavingsApiConstants.withdrawalFeeTypeParamName;
|
||||
|
||||
import java.lang.reflect.Type;
|
||||
import java.math.BigDecimal;
|
||||
@@ -39,7 +38,7 @@ import org.mifosplatform.infrastructure.core.data.DataValidatorBuilder;
|
||||
import org.mifosplatform.infrastructure.core.exception.InvalidJsonException;
|
||||
import org.mifosplatform.infrastructure.core.exception.PlatformApiDataValidationException;
|
||||
import org.mifosplatform.infrastructure.core.serialization.FromJsonHelper;
|
||||
import org.mifosplatform.portfolio.savings.api.SavingsApiConstants;
|
||||
import org.mifosplatform.portfolio.savings.SavingsApiConstants;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.stereotype.Component;
|
||||
|
||||
@@ -56,7 +55,7 @@ public class SavingsAccountDataValidator {
|
||||
this.fromApiJsonHelper = fromApiJsonHelper;
|
||||
}
|
||||
|
||||
public void validateForCreate(final String json) {
|
||||
public void validateForSubmit(final String json) {
|
||||
|
||||
if (StringUtils.isBlank(json)) { throw new InvalidJsonException(); }
|
||||
|
||||
@@ -85,13 +84,9 @@ public class SavingsAccountDataValidator {
|
||||
final Long productId = fromApiJsonHelper.extractLongNamed(productIdParamName, element);
|
||||
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();
|
||||
final LocalDate submittedOnDate = fromApiJsonHelper.extractLocalDateNamed(submittedOnDateParamName, element);
|
||||
if (submittedOnDate == null) {
|
||||
baseDataValidator.reset().parameter(submittedOnDateParamName).value(submittedOnDate).notNull();
|
||||
}
|
||||
|
||||
if (fromApiJsonHelper.parameterExists(accountNoParamName, element)) {
|
||||
@@ -140,32 +135,32 @@ public class SavingsAccountDataValidator {
|
||||
if (this.fromApiJsonHelper.parameterExists(minRequiredOpeningBalanceParamName, element)) {
|
||||
final BigDecimal minOpeningBalance = fromApiJsonHelper.extractBigDecimalWithLocaleNamed(minRequiredOpeningBalanceParamName,
|
||||
element);
|
||||
baseDataValidator.reset().parameter(minRequiredOpeningBalanceParamName).value(minOpeningBalance).positiveAmount();
|
||||
baseDataValidator.reset().parameter(minRequiredOpeningBalanceParamName).value(minOpeningBalance).zeroOrPositiveAmount();
|
||||
}
|
||||
|
||||
if (this.fromApiJsonHelper.parameterExists(lockinPeriodFrequencyParamName, element)) {
|
||||
|
||||
final Integer lockinPeriodFrequency = fromApiJsonHelper.extractIntegerWithLocaleNamed(lockinPeriodFrequencyParamName, element);
|
||||
baseDataValidator.reset().parameter(lockinPeriodFrequencyParamName).value(lockinPeriodFrequency).ignoreIfNull()
|
||||
.positiveAmount();
|
||||
baseDataValidator.reset().parameter(lockinPeriodFrequencyParamName).value(lockinPeriodFrequency).integerZeroOrGreater();
|
||||
|
||||
if (lockinPeriodFrequency != null) {
|
||||
final Integer lockinPeriodFrequencyType = fromApiJsonHelper.extractIntegerSansLocaleNamed(
|
||||
lockinPeriodFrequencyTypeParamName, element);
|
||||
baseDataValidator.reset().parameter(lockinPeriodFrequencyTypeParamName).value(lockinPeriodFrequencyType).notNull()
|
||||
.inMinMaxRange(1, 3);
|
||||
.inMinMaxRange(0, 3);
|
||||
}
|
||||
}
|
||||
|
||||
if (this.fromApiJsonHelper.parameterExists(lockinPeriodFrequencyTypeParamName, element)) {
|
||||
final Integer lockinPeriodFrequencyType = fromApiJsonHelper.extractIntegerSansLocaleNamed(lockinPeriodFrequencyTypeParamName,
|
||||
element);
|
||||
baseDataValidator.reset().parameter(lockinPeriodFrequencyTypeParamName).value(lockinPeriodFrequencyType).inMinMaxRange(1, 3);
|
||||
baseDataValidator.reset().parameter(lockinPeriodFrequencyTypeParamName).value(lockinPeriodFrequencyType).inMinMaxRange(0, 3);
|
||||
|
||||
if (lockinPeriodFrequencyType != null) {
|
||||
final Integer lockinPeriodFrequency = fromApiJsonHelper.extractIntegerWithLocaleNamed(lockinPeriodFrequencyParamName,
|
||||
element);
|
||||
baseDataValidator.reset().parameter(lockinPeriodFrequencyParamName).value(lockinPeriodFrequency).notNull().positiveAmount();
|
||||
baseDataValidator.reset().parameter(lockinPeriodFrequencyParamName).value(lockinPeriodFrequency).notNull()
|
||||
.integerZeroOrGreater();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -173,17 +168,30 @@ public class SavingsAccountDataValidator {
|
||||
|
||||
final BigDecimal withdrawalFeeAmount = fromApiJsonHelper
|
||||
.extractBigDecimalWithLocaleNamed(withdrawalFeeAmountParamName, element);
|
||||
baseDataValidator.reset().parameter(withdrawalFeeAmountParamName).value(withdrawalFeeAmount).positiveAmount();
|
||||
baseDataValidator.reset().parameter(withdrawalFeeAmountParamName).value(withdrawalFeeAmount).zeroOrPositiveAmount();
|
||||
|
||||
if (withdrawalFeeAmount != null) {
|
||||
final Integer withdrawalFeeType = fromApiJsonHelper.extractIntegerSansLocaleNamed(withdrawalFeeTypeParamName, element);
|
||||
baseDataValidator.reset().parameter(withdrawalFeeTypeParamName).value(withdrawalFeeType).isOneOfTheseValues(1, 2);
|
||||
}
|
||||
}
|
||||
|
||||
if (this.fromApiJsonHelper.parameterExists(withdrawalFeeTypeParamName, element)) {
|
||||
final Integer withdrawalFeeType = fromApiJsonHelper.extractIntegerSansLocaleNamed(withdrawalFeeTypeParamName, element);
|
||||
baseDataValidator.reset().parameter(withdrawalFeeTypeParamName).value(withdrawalFeeType).isOneOfTheseValues(1, 2);
|
||||
baseDataValidator.reset().parameter(withdrawalFeeTypeParamName).value(withdrawalFeeType).ignoreIfNull()
|
||||
.isOneOfTheseValues(1, 2);
|
||||
|
||||
if (withdrawalFeeType != null) {
|
||||
final BigDecimal withdrawalFeeAmount = fromApiJsonHelper.extractBigDecimalWithLocaleNamed(withdrawalFeeAmountParamName,
|
||||
element);
|
||||
baseDataValidator.reset().parameter(withdrawalFeeAmountParamName).value(withdrawalFeeAmount).notNull()
|
||||
.zeroOrPositiveAmount();
|
||||
}
|
||||
}
|
||||
|
||||
if (this.fromApiJsonHelper.parameterExists(annualFeeAmountParamName, element)) {
|
||||
final BigDecimal annualFeeAmount = fromApiJsonHelper.extractBigDecimalWithLocaleNamed(annualFeeAmountParamName, element);
|
||||
baseDataValidator.reset().parameter(annualFeeAmountParamName).value(annualFeeAmount).positiveAmount();
|
||||
baseDataValidator.reset().parameter(annualFeeAmountParamName).value(annualFeeAmount).zeroOrPositiveAmount();
|
||||
|
||||
if (annualFeeAmount != null) {
|
||||
MonthDay monthDayOfAnnualFee = fromApiJsonHelper.extractMonthDayNamed(annualFeeOnMonthDayParamName, element);
|
||||
@@ -191,6 +199,15 @@ public class SavingsAccountDataValidator {
|
||||
}
|
||||
}
|
||||
|
||||
if (this.fromApiJsonHelper.parameterExists(annualFeeOnMonthDayParamName, element)) {
|
||||
|
||||
MonthDay monthDayOfAnnualFee = fromApiJsonHelper.extractMonthDayNamed(annualFeeOnMonthDayParamName, element);
|
||||
if (monthDayOfAnnualFee != null) {
|
||||
final BigDecimal annualFeeAmount = fromApiJsonHelper.extractBigDecimalWithLocaleNamed(annualFeeAmountParamName, element);
|
||||
baseDataValidator.reset().parameter(annualFeeAmountParamName).value(annualFeeAmount).notNull().zeroOrPositiveAmount();
|
||||
}
|
||||
}
|
||||
|
||||
throwExceptionIfValidationWarningsExist(dataValidationErrors);
|
||||
}
|
||||
|
||||
@@ -293,50 +310,38 @@ public class SavingsAccountDataValidator {
|
||||
if (this.fromApiJsonHelper.parameterExists(minRequiredOpeningBalanceParamName, element)) {
|
||||
final BigDecimal minOpeningBalance = fromApiJsonHelper.extractBigDecimalWithLocaleNamed(minRequiredOpeningBalanceParamName,
|
||||
element);
|
||||
baseDataValidator.reset().parameter(minRequiredOpeningBalanceParamName).value(minOpeningBalance).positiveAmount();
|
||||
baseDataValidator.reset().parameter(minRequiredOpeningBalanceParamName).value(minOpeningBalance).ignoreIfNull()
|
||||
.zeroOrPositiveAmount();
|
||||
}
|
||||
|
||||
if (this.fromApiJsonHelper.parameterExists(lockinPeriodFrequencyParamName, element)) {
|
||||
|
||||
final Integer lockinPeriodFrequency = fromApiJsonHelper.extractIntegerWithLocaleNamed(lockinPeriodFrequencyParamName, element);
|
||||
baseDataValidator.reset().parameter(lockinPeriodFrequencyParamName).value(lockinPeriodFrequency).ignoreIfNull()
|
||||
.positiveAmount();
|
||||
|
||||
if (lockinPeriodFrequency != null) {
|
||||
final Integer lockinPeriodFrequencyType = fromApiJsonHelper.extractIntegerSansLocaleNamed(
|
||||
lockinPeriodFrequencyTypeParamName, element);
|
||||
baseDataValidator.reset().parameter(lockinPeriodFrequencyTypeParamName).value(lockinPeriodFrequencyType).notNull()
|
||||
.inMinMaxRange(1, 3);
|
||||
}
|
||||
.integerZeroOrGreater();
|
||||
}
|
||||
|
||||
if (this.fromApiJsonHelper.parameterExists(lockinPeriodFrequencyTypeParamName, element)) {
|
||||
final Integer lockinPeriodFrequencyType = fromApiJsonHelper.extractIntegerSansLocaleNamed(lockinPeriodFrequencyTypeParamName,
|
||||
element);
|
||||
baseDataValidator.reset().parameter(lockinPeriodFrequencyTypeParamName).value(lockinPeriodFrequencyType).inMinMaxRange(1, 3);
|
||||
|
||||
if (lockinPeriodFrequencyType != null) {
|
||||
final Integer lockinPeriodFrequency = fromApiJsonHelper.extractIntegerWithLocaleNamed(lockinPeriodFrequencyParamName,
|
||||
element);
|
||||
baseDataValidator.reset().parameter(lockinPeriodFrequencyParamName).value(lockinPeriodFrequency).notNull().positiveAmount();
|
||||
}
|
||||
baseDataValidator.reset().parameter(lockinPeriodFrequencyTypeParamName).value(lockinPeriodFrequencyType).inMinMaxRange(0, 3);
|
||||
}
|
||||
|
||||
if (this.fromApiJsonHelper.parameterExists(withdrawalFeeAmountParamName, element)) {
|
||||
|
||||
final BigDecimal withdrawalFeeAmount = fromApiJsonHelper
|
||||
.extractBigDecimalWithLocaleNamed(withdrawalFeeAmountParamName, element);
|
||||
baseDataValidator.reset().parameter(withdrawalFeeAmountParamName).value(withdrawalFeeAmount).notNull().positiveAmount();
|
||||
baseDataValidator.reset().parameter(withdrawalFeeAmountParamName).value(withdrawalFeeAmount).ignoreIfNull()
|
||||
.zeroOrPositiveAmount();
|
||||
}
|
||||
|
||||
if (this.fromApiJsonHelper.parameterExists(withdrawalFeeTypeParamName, element)) {
|
||||
final Integer withdrawalFeeType = fromApiJsonHelper.extractIntegerSansLocaleNamed(withdrawalFeeTypeParamName, element);
|
||||
baseDataValidator.reset().parameter(withdrawalFeeTypeParamName).value(withdrawalFeeType).isOneOfTheseValues(1, 2);
|
||||
baseDataValidator.reset().parameter(withdrawalFeeTypeParamName).value(withdrawalFeeType).ignoreIfNull()
|
||||
.isOneOfTheseValues(1, 2);
|
||||
}
|
||||
|
||||
if (this.fromApiJsonHelper.parameterExists(annualFeeAmountParamName, element)) {
|
||||
final BigDecimal annualFeeAmount = fromApiJsonHelper.extractBigDecimalWithLocaleNamed(annualFeeAmountParamName, element);
|
||||
baseDataValidator.reset().parameter(annualFeeAmountParamName).value(annualFeeAmount).ignoreIfNull().positiveAmount();
|
||||
baseDataValidator.reset().parameter(annualFeeAmountParamName).value(annualFeeAmount).ignoreIfNull().zeroOrPositiveAmount();
|
||||
}
|
||||
|
||||
if (this.fromApiJsonHelper.parameterExists(annualFeeOnMonthDayParamName, element)) {
|
||||
|
||||
+14
-5
@@ -16,22 +16,31 @@ public class SavingsAccountStatusEnumData {
|
||||
@SuppressWarnings("unused")
|
||||
private final String value;
|
||||
@SuppressWarnings("unused")
|
||||
private final boolean unactivated;
|
||||
private final boolean submittedAndPendingApproval;
|
||||
@SuppressWarnings("unused")
|
||||
private final boolean approved;
|
||||
@SuppressWarnings("unused")
|
||||
private final boolean rejected;
|
||||
@SuppressWarnings("unused")
|
||||
private final boolean withdrawnByApplicant;
|
||||
@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) {
|
||||
public SavingsAccountStatusEnumData(final Long id, final String code, final String value, final boolean submittedAndPendingApproval,
|
||||
final boolean approved, final boolean rejected, final boolean withdrawnByApplicant, final boolean active, final boolean closed) {
|
||||
this.id = id;
|
||||
this.code = code;
|
||||
this.value = value;
|
||||
this.unactivated = unactivated;
|
||||
this.submittedAndPendingApproval = submittedAndPendingApproval;
|
||||
this.approved = approved;
|
||||
this.rejected = rejected;
|
||||
this.withdrawnByApplicant = withdrawnByApplicant;
|
||||
this.active = active;
|
||||
this.closed = closed;
|
||||
}
|
||||
|
||||
|
||||
public Long id() {
|
||||
return this.id;
|
||||
}
|
||||
|
||||
+11
-11
@@ -5,15 +5,15 @@
|
||||
*/
|
||||
package org.mifosplatform.portfolio.savings.data;
|
||||
|
||||
import static org.mifosplatform.portfolio.savings.api.SavingsApiConstants.accountNumberParamName;
|
||||
import static org.mifosplatform.portfolio.savings.api.SavingsApiConstants.activationDateParamName;
|
||||
import static org.mifosplatform.portfolio.savings.api.SavingsApiConstants.bankNumberParamName;
|
||||
import static org.mifosplatform.portfolio.savings.api.SavingsApiConstants.checkNumberParamName;
|
||||
import static org.mifosplatform.portfolio.savings.api.SavingsApiConstants.paymentTypeIdParamName;
|
||||
import static org.mifosplatform.portfolio.savings.api.SavingsApiConstants.receiptNumberParamName;
|
||||
import static org.mifosplatform.portfolio.savings.api.SavingsApiConstants.routingCodeParamName;
|
||||
import static org.mifosplatform.portfolio.savings.api.SavingsApiConstants.transactionAmountParamName;
|
||||
import static org.mifosplatform.portfolio.savings.api.SavingsApiConstants.transactionDateParamName;
|
||||
import static org.mifosplatform.portfolio.savings.SavingsApiConstants.activationDateParamName;
|
||||
import static org.mifosplatform.portfolio.savings.SavingsApiConstants.bankNumberParamName;
|
||||
import static org.mifosplatform.portfolio.savings.SavingsApiConstants.checkNumberParamName;
|
||||
import static org.mifosplatform.portfolio.savings.SavingsApiConstants.paymentTypeIdParamName;
|
||||
import static org.mifosplatform.portfolio.savings.SavingsApiConstants.receiptNumberParamName;
|
||||
import static org.mifosplatform.portfolio.savings.SavingsApiConstants.routingCodeParamName;
|
||||
import static org.mifosplatform.portfolio.savings.SavingsApiConstants.transactionAccountNumberParamName;
|
||||
import static org.mifosplatform.portfolio.savings.SavingsApiConstants.transactionAmountParamName;
|
||||
import static org.mifosplatform.portfolio.savings.SavingsApiConstants.transactionDateParamName;
|
||||
|
||||
import java.lang.reflect.Type;
|
||||
import java.math.BigDecimal;
|
||||
@@ -32,7 +32,7 @@ import org.mifosplatform.infrastructure.core.data.DataValidatorBuilder;
|
||||
import org.mifosplatform.infrastructure.core.exception.InvalidJsonException;
|
||||
import org.mifosplatform.infrastructure.core.exception.PlatformApiDataValidationException;
|
||||
import org.mifosplatform.infrastructure.core.serialization.FromJsonHelper;
|
||||
import org.mifosplatform.portfolio.savings.api.SavingsApiConstants;
|
||||
import org.mifosplatform.portfolio.savings.SavingsApiConstants;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.stereotype.Component;
|
||||
|
||||
@@ -74,7 +74,7 @@ public class SavingsAccountTransactionDataValidator {
|
||||
// Validate all string payment detail fields for max length
|
||||
final Integer paymentTypeId = fromApiJsonHelper.extractIntegerWithLocaleNamed(paymentTypeIdParamName, element);
|
||||
baseDataValidator.reset().parameter(paymentTypeIdParamName).value(paymentTypeId).ignoreIfNull().integerGreaterThanZero();
|
||||
final Set<String> paymentDetailParameters = new HashSet<String>(Arrays.asList(accountNumberParamName, checkNumberParamName,
|
||||
final Set<String> paymentDetailParameters = new HashSet<String>(Arrays.asList(transactionAccountNumberParamName, checkNumberParamName,
|
||||
routingCodeParamName, receiptNumberParamName, bankNumberParamName));
|
||||
for (String paymentDetailParameterName : paymentDetailParameters) {
|
||||
final String paymentDetailParameterValue = fromApiJsonHelper.extractStringNamed(paymentDetailParameterName, element);
|
||||
|
||||
+1
-1
@@ -5,7 +5,7 @@
|
||||
*/
|
||||
package org.mifosplatform.portfolio.savings.data;
|
||||
|
||||
import org.mifosplatform.portfolio.savings.domain.SavingsAccountTransactionType;
|
||||
import org.mifosplatform.portfolio.savings.SavingsAccountTransactionType;
|
||||
|
||||
/**
|
||||
* Immutable data object represent savings account transaction type
|
||||
|
||||
+62
-34
@@ -5,24 +5,24 @@
|
||||
*/
|
||||
package org.mifosplatform.portfolio.savings.data;
|
||||
|
||||
import static org.mifosplatform.portfolio.savings.api.SavingsApiConstants.SAVINGS_PRODUCT_REQUEST_DATA_PARAMETERS;
|
||||
import static org.mifosplatform.portfolio.savings.api.SavingsApiConstants.SAVINGS_PRODUCT_RESOURCE_NAME;
|
||||
import static org.mifosplatform.portfolio.savings.api.SavingsApiConstants.annualFeeAmountParamName;
|
||||
import static org.mifosplatform.portfolio.savings.api.SavingsApiConstants.annualFeeOnMonthDayParamName;
|
||||
import static org.mifosplatform.portfolio.savings.api.SavingsApiConstants.currencyCodeParamName;
|
||||
import static org.mifosplatform.portfolio.savings.api.SavingsApiConstants.descriptionParamName;
|
||||
import static org.mifosplatform.portfolio.savings.api.SavingsApiConstants.digitsAfterDecimalParamName;
|
||||
import static org.mifosplatform.portfolio.savings.api.SavingsApiConstants.interestCalculationDaysInYearTypeParamName;
|
||||
import static org.mifosplatform.portfolio.savings.api.SavingsApiConstants.interestCalculationTypeParamName;
|
||||
import static org.mifosplatform.portfolio.savings.api.SavingsApiConstants.interestCompoundingPeriodTypeParamName;
|
||||
import static org.mifosplatform.portfolio.savings.api.SavingsApiConstants.interestPostingPeriodTypeParamName;
|
||||
import static org.mifosplatform.portfolio.savings.api.SavingsApiConstants.lockinPeriodFrequencyParamName;
|
||||
import static org.mifosplatform.portfolio.savings.api.SavingsApiConstants.lockinPeriodFrequencyTypeParamName;
|
||||
import static org.mifosplatform.portfolio.savings.api.SavingsApiConstants.minRequiredOpeningBalanceParamName;
|
||||
import static org.mifosplatform.portfolio.savings.api.SavingsApiConstants.nameParamName;
|
||||
import static org.mifosplatform.portfolio.savings.api.SavingsApiConstants.nominalAnnualInterestRateParamName;
|
||||
import static org.mifosplatform.portfolio.savings.api.SavingsApiConstants.withdrawalFeeAmountParamName;
|
||||
import static org.mifosplatform.portfolio.savings.api.SavingsApiConstants.withdrawalFeeTypeParamName;
|
||||
import static org.mifosplatform.portfolio.savings.SavingsApiConstants.SAVINGS_PRODUCT_REQUEST_DATA_PARAMETERS;
|
||||
import static org.mifosplatform.portfolio.savings.SavingsApiConstants.SAVINGS_PRODUCT_RESOURCE_NAME;
|
||||
import static org.mifosplatform.portfolio.savings.SavingsApiConstants.annualFeeAmountParamName;
|
||||
import static org.mifosplatform.portfolio.savings.SavingsApiConstants.annualFeeOnMonthDayParamName;
|
||||
import static org.mifosplatform.portfolio.savings.SavingsApiConstants.currencyCodeParamName;
|
||||
import static org.mifosplatform.portfolio.savings.SavingsApiConstants.descriptionParamName;
|
||||
import static org.mifosplatform.portfolio.savings.SavingsApiConstants.digitsAfterDecimalParamName;
|
||||
import static org.mifosplatform.portfolio.savings.SavingsApiConstants.interestCalculationDaysInYearTypeParamName;
|
||||
import static org.mifosplatform.portfolio.savings.SavingsApiConstants.interestCalculationTypeParamName;
|
||||
import static org.mifosplatform.portfolio.savings.SavingsApiConstants.interestCompoundingPeriodTypeParamName;
|
||||
import static org.mifosplatform.portfolio.savings.SavingsApiConstants.interestPostingPeriodTypeParamName;
|
||||
import static org.mifosplatform.portfolio.savings.SavingsApiConstants.lockinPeriodFrequencyParamName;
|
||||
import static org.mifosplatform.portfolio.savings.SavingsApiConstants.lockinPeriodFrequencyTypeParamName;
|
||||
import static org.mifosplatform.portfolio.savings.SavingsApiConstants.minRequiredOpeningBalanceParamName;
|
||||
import static org.mifosplatform.portfolio.savings.SavingsApiConstants.nameParamName;
|
||||
import static org.mifosplatform.portfolio.savings.SavingsApiConstants.nominalAnnualInterestRateParamName;
|
||||
import static org.mifosplatform.portfolio.savings.SavingsApiConstants.withdrawalFeeAmountParamName;
|
||||
import static org.mifosplatform.portfolio.savings.SavingsApiConstants.withdrawalFeeTypeParamName;
|
||||
|
||||
import java.lang.reflect.Type;
|
||||
import java.math.BigDecimal;
|
||||
@@ -40,6 +40,7 @@ import org.mifosplatform.infrastructure.core.data.DataValidatorBuilder;
|
||||
import org.mifosplatform.infrastructure.core.exception.InvalidJsonException;
|
||||
import org.mifosplatform.infrastructure.core.exception.PlatformApiDataValidationException;
|
||||
import org.mifosplatform.infrastructure.core.serialization.FromJsonHelper;
|
||||
import org.mifosplatform.portfolio.savings.SavingsCompoundingInterestPeriodType;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.stereotype.Component;
|
||||
|
||||
@@ -90,7 +91,7 @@ public class SavingsProductDataValidator {
|
||||
final Integer interestCompoundingPeriodType = fromApiJsonHelper.extractIntegerSansLocaleNamed(
|
||||
interestCompoundingPeriodTypeParamName, element);
|
||||
baseDataValidator.reset().parameter(interestCompoundingPeriodTypeParamName).value(interestCompoundingPeriodType).notNull()
|
||||
.isOneOfTheseValues(new Object[] { 1, 2, 3, 4, 5, 6, 7, 8 });
|
||||
.isOneOfTheseValues(SavingsCompoundingInterestPeriodType.integerValues());
|
||||
|
||||
final Integer interestPostingPeriodType = fromApiJsonHelper.extractIntegerSansLocaleNamed(interestPostingPeriodTypeParamName,
|
||||
element);
|
||||
@@ -109,14 +110,13 @@ public class SavingsProductDataValidator {
|
||||
if (this.fromApiJsonHelper.parameterExists(minRequiredOpeningBalanceParamName, element)) {
|
||||
final BigDecimal minOpeningBalance = fromApiJsonHelper.extractBigDecimalWithLocaleNamed(minRequiredOpeningBalanceParamName,
|
||||
element);
|
||||
baseDataValidator.reset().parameter(minRequiredOpeningBalanceParamName).value(minOpeningBalance).positiveAmount();
|
||||
baseDataValidator.reset().parameter(minRequiredOpeningBalanceParamName).value(minOpeningBalance).zeroOrPositiveAmount();
|
||||
}
|
||||
|
||||
if (this.fromApiJsonHelper.parameterExists(lockinPeriodFrequencyParamName, element)) {
|
||||
|
||||
final Integer lockinPeriodFrequency = fromApiJsonHelper.extractIntegerWithLocaleNamed(lockinPeriodFrequencyParamName, element);
|
||||
baseDataValidator.reset().parameter(lockinPeriodFrequencyParamName).value(lockinPeriodFrequency).ignoreIfNull()
|
||||
.positiveAmount();
|
||||
baseDataValidator.reset().parameter(lockinPeriodFrequencyParamName).value(lockinPeriodFrequency).integerZeroOrGreater();
|
||||
|
||||
if (lockinPeriodFrequency != null) {
|
||||
final Integer lockinPeriodFrequencyType = fromApiJsonHelper.extractIntegerSansLocaleNamed(
|
||||
@@ -134,24 +134,39 @@ public class SavingsProductDataValidator {
|
||||
if (lockinPeriodFrequencyType != null) {
|
||||
final Integer lockinPeriodFrequency = fromApiJsonHelper.extractIntegerWithLocaleNamed(lockinPeriodFrequencyParamName,
|
||||
element);
|
||||
baseDataValidator.reset().parameter(lockinPeriodFrequencyParamName).value(lockinPeriodFrequency).notNull().positiveAmount();
|
||||
baseDataValidator.reset().parameter(lockinPeriodFrequencyParamName).value(lockinPeriodFrequency).notNull()
|
||||
.integerZeroOrGreater();
|
||||
}
|
||||
}
|
||||
|
||||
if (this.fromApiJsonHelper.parameterExists(withdrawalFeeAmountParamName, element)) {
|
||||
|
||||
final BigDecimal withdrawalFeeAmount = fromApiJsonHelper
|
||||
.extractBigDecimalWithLocaleNamed(withdrawalFeeAmountParamName, element);
|
||||
baseDataValidator.reset().parameter(withdrawalFeeAmountParamName).value(withdrawalFeeAmount).zeroOrPositiveAmount();
|
||||
|
||||
if (withdrawalFeeAmount != null) {
|
||||
final Integer withdrawalFeeType = fromApiJsonHelper.extractIntegerSansLocaleNamed(withdrawalFeeTypeParamName, element);
|
||||
baseDataValidator.reset().parameter(withdrawalFeeTypeParamName).value(withdrawalFeeType).isOneOfTheseValues(1, 2);
|
||||
}
|
||||
}
|
||||
|
||||
if (this.fromApiJsonHelper.parameterExists(withdrawalFeeTypeParamName, element)) {
|
||||
final Integer withdrawalFeeType = fromApiJsonHelper.extractIntegerSansLocaleNamed(withdrawalFeeTypeParamName, element);
|
||||
baseDataValidator.reset().parameter(withdrawalFeeTypeParamName).value(withdrawalFeeType).isOneOfTheseValues(1, 2);
|
||||
baseDataValidator.reset().parameter(withdrawalFeeTypeParamName).value(withdrawalFeeType).ignoreIfNull()
|
||||
.isOneOfTheseValues(1, 2);
|
||||
|
||||
if (withdrawalFeeType != null) {
|
||||
final BigDecimal withdrawalFeeAmount = fromApiJsonHelper.extractBigDecimalWithLocaleNamed(withdrawalFeeAmountParamName,
|
||||
element);
|
||||
baseDataValidator.reset().parameter(withdrawalFeeAmountParamName).value(withdrawalFeeAmount).notNull().positiveAmount();
|
||||
baseDataValidator.reset().parameter(withdrawalFeeAmountParamName).value(withdrawalFeeAmount).notNull()
|
||||
.zeroOrPositiveAmount();
|
||||
}
|
||||
}
|
||||
|
||||
if (this.fromApiJsonHelper.parameterExists(annualFeeAmountParamName, element)) {
|
||||
final BigDecimal annualFeeAmount = fromApiJsonHelper.extractBigDecimalWithLocaleNamed(annualFeeAmountParamName, element);
|
||||
baseDataValidator.reset().parameter(annualFeeAmountParamName).value(annualFeeAmount).ignoreIfNull().positiveAmount();
|
||||
baseDataValidator.reset().parameter(annualFeeAmountParamName).value(annualFeeAmount).zeroOrPositiveAmount();
|
||||
|
||||
if (annualFeeAmount != null) {
|
||||
MonthDay monthDayOfAnnualFee = fromApiJsonHelper.extractMonthDayNamed(annualFeeOnMonthDayParamName, element);
|
||||
@@ -159,6 +174,15 @@ public class SavingsProductDataValidator {
|
||||
}
|
||||
}
|
||||
|
||||
if (this.fromApiJsonHelper.parameterExists(annualFeeOnMonthDayParamName, element)) {
|
||||
|
||||
MonthDay monthDayOfAnnualFee = fromApiJsonHelper.extractMonthDayNamed(annualFeeOnMonthDayParamName, element);
|
||||
if (monthDayOfAnnualFee != null) {
|
||||
final BigDecimal annualFeeAmount = fromApiJsonHelper.extractBigDecimalWithLocaleNamed(annualFeeAmountParamName, element);
|
||||
baseDataValidator.reset().parameter(annualFeeAmountParamName).value(annualFeeAmount).notNull().zeroOrPositiveAmount();
|
||||
}
|
||||
}
|
||||
|
||||
// accounting related data validation
|
||||
final Integer accountingRuleType = fromApiJsonHelper.extractIntegerNamed("accountingRule", element, Locale.getDefault());
|
||||
baseDataValidator.reset().parameter("accountingRule").value(accountingRuleType).notNull().inMinMaxRange(1, 3);
|
||||
@@ -232,7 +256,7 @@ public class SavingsProductDataValidator {
|
||||
final Integer interestCompoundingPeriodType = fromApiJsonHelper.extractIntegerSansLocaleNamed(
|
||||
interestCompoundingPeriodTypeParamName, element);
|
||||
baseDataValidator.reset().parameter(interestCompoundingPeriodTypeParamName).value(interestCompoundingPeriodType).notNull()
|
||||
.inMinMaxRange(1, 8);
|
||||
.isOneOfTheseValues(SavingsCompoundingInterestPeriodType.integerValues());
|
||||
}
|
||||
|
||||
if (this.fromApiJsonHelper.parameterExists(interestCalculationTypeParamName, element)) {
|
||||
@@ -249,11 +273,17 @@ public class SavingsProductDataValidator {
|
||||
.notNull().isOneOfTheseValues(360, 365);
|
||||
}
|
||||
|
||||
if (this.fromApiJsonHelper.parameterExists(lockinPeriodFrequencyParamName, element)) {
|
||||
if (this.fromApiJsonHelper.parameterExists(minRequiredOpeningBalanceParamName, element)) {
|
||||
final BigDecimal minOpeningBalance = fromApiJsonHelper.extractBigDecimalWithLocaleNamed(minRequiredOpeningBalanceParamName,
|
||||
element);
|
||||
baseDataValidator.reset().parameter(minRequiredOpeningBalanceParamName).value(minOpeningBalance).ignoreIfNull()
|
||||
.zeroOrPositiveAmount();
|
||||
}
|
||||
|
||||
if (this.fromApiJsonHelper.parameterExists(lockinPeriodFrequencyParamName, element)) {
|
||||
final Integer lockinPeriodFrequency = fromApiJsonHelper.extractIntegerWithLocaleNamed(lockinPeriodFrequencyParamName, element);
|
||||
baseDataValidator.reset().parameter(lockinPeriodFrequencyParamName).value(lockinPeriodFrequency).ignoreIfNull()
|
||||
.positiveAmount();
|
||||
.integerZeroOrGreater();
|
||||
}
|
||||
|
||||
if (this.fromApiJsonHelper.parameterExists(lockinPeriodFrequencyTypeParamName, element)) {
|
||||
@@ -265,7 +295,8 @@ public class SavingsProductDataValidator {
|
||||
if (this.fromApiJsonHelper.parameterExists(withdrawalFeeAmountParamName, element)) {
|
||||
final BigDecimal withdrawalFeeAmount = fromApiJsonHelper
|
||||
.extractBigDecimalWithLocaleNamed(withdrawalFeeAmountParamName, element);
|
||||
baseDataValidator.reset().parameter(withdrawalFeeAmountParamName).value(withdrawalFeeAmount).ignoreIfNull().positiveAmount();
|
||||
baseDataValidator.reset().parameter(withdrawalFeeAmountParamName).value(withdrawalFeeAmount).ignoreIfNull()
|
||||
.zeroOrPositiveAmount();
|
||||
}
|
||||
|
||||
if (this.fromApiJsonHelper.parameterExists(withdrawalFeeTypeParamName, element)) {
|
||||
@@ -276,7 +307,7 @@ public class SavingsProductDataValidator {
|
||||
|
||||
if (this.fromApiJsonHelper.parameterExists(annualFeeAmountParamName, element)) {
|
||||
final BigDecimal annualFeeAmount = fromApiJsonHelper.extractBigDecimalWithLocaleNamed(annualFeeAmountParamName, element);
|
||||
baseDataValidator.reset().parameter(annualFeeAmountParamName).value(annualFeeAmount).ignoreIfNull().positiveAmount();
|
||||
baseDataValidator.reset().parameter(annualFeeAmountParamName).value(annualFeeAmount).ignoreIfNull().zeroOrPositiveAmount();
|
||||
}
|
||||
|
||||
if (this.fromApiJsonHelper.parameterExists(annualFeeOnMonthDayParamName, element)) {
|
||||
@@ -319,9 +350,6 @@ public class SavingsProductDataValidator {
|
||||
|
||||
/**
|
||||
* Validation for advanced accounting options
|
||||
*
|
||||
* @param baseDataValidator
|
||||
* @param element
|
||||
*/
|
||||
private void validatePaymentChannelFundSourceMappings(final DataValidatorBuilder baseDataValidator, final JsonElement element) {
|
||||
if (fromApiJsonHelper.parameterExists(SAVINGS_PRODUCT_ACCOUNTING_PARAMS.PAYMENT_CHANNEL_FUND_SOURCE_MAPPING.getValue(), element)) {
|
||||
|
||||
-63
@@ -1,63 +0,0 @@
|
||||
/**
|
||||
* 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;
|
||||
|
||||
import java.math.BigDecimal;
|
||||
import java.math.MathContext;
|
||||
|
||||
import org.joda.time.LocalDate;
|
||||
import org.mifosplatform.infrastructure.core.domain.LocalDateInterval;
|
||||
import org.mifosplatform.organisation.monetary.domain.MonetaryCurrency;
|
||||
import org.mifosplatform.organisation.monetary.domain.Money;
|
||||
|
||||
public class InterestCompoundingPeriodSummary {
|
||||
|
||||
private final LocalDateInterval periodInterval;
|
||||
@SuppressWarnings("unused")
|
||||
private final BigDecimal openingBalance;
|
||||
private final BigDecimal closingBalance;
|
||||
private final BigDecimal interestEarnedUnrounded;
|
||||
private final BigDecimal cumulativeCompoundedInterestToDate;
|
||||
|
||||
public static InterestCompoundingPeriodSummary create(final LocalDateInterval periodInterval, final BigDecimal openingBalance,
|
||||
final BigDecimal closingBalance, final BigDecimal interestEarnedUnrounded, final BigDecimal cumulativeCompoundedInterestToDate) {
|
||||
return new InterestCompoundingPeriodSummary(periodInterval, openingBalance, closingBalance, interestEarnedUnrounded,
|
||||
cumulativeCompoundedInterestToDate);
|
||||
}
|
||||
|
||||
public InterestCompoundingPeriodSummary(final LocalDateInterval periodInterval, final BigDecimal openingBalance,
|
||||
final BigDecimal closingBalance, final BigDecimal interestEarnedUnrounded, final BigDecimal cumulativeCompoundedInterestToDate) {
|
||||
this.periodInterval = periodInterval;
|
||||
this.openingBalance = openingBalance;
|
||||
this.closingBalance = closingBalance;
|
||||
this.interestEarnedUnrounded = interestEarnedUnrounded;
|
||||
this.cumulativeCompoundedInterestToDate = cumulativeCompoundedInterestToDate;
|
||||
}
|
||||
|
||||
public Money closingBalance(final MonetaryCurrency currency) {
|
||||
return Money.of(currency, this.closingBalance);
|
||||
}
|
||||
|
||||
public BigDecimal closingBalance() {
|
||||
return this.closingBalance;
|
||||
}
|
||||
|
||||
public BigDecimal closingBalanceWithUnroundedInterest(final MathContext mc) {
|
||||
return this.closingBalance.add(interestEarnedUnrounded, mc);
|
||||
}
|
||||
|
||||
public BigDecimal compoundedInterest() {
|
||||
return cumulativeCompoundedInterestToDate;
|
||||
}
|
||||
|
||||
public BigDecimal interestUnrounded() {
|
||||
return this.interestEarnedUnrounded;
|
||||
}
|
||||
|
||||
public boolean fallsBefore(final LocalDate dateToCheck) {
|
||||
return this.periodInterval.fallsBefore(dateToCheck);
|
||||
}
|
||||
}
|
||||
+629
-432
File diff suppressed because it is too large
Load Diff
+68
-50
@@ -5,36 +5,45 @@
|
||||
*/
|
||||
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.annualFeeAmountParamName;
|
||||
import static org.mifosplatform.portfolio.savings.api.SavingsApiConstants.annualFeeOnMonthDayParamName;
|
||||
import static org.mifosplatform.portfolio.savings.api.SavingsApiConstants.interestCalculationDaysInYearTypeParamName;
|
||||
import static org.mifosplatform.portfolio.savings.api.SavingsApiConstants.interestCalculationTypeParamName;
|
||||
import static org.mifosplatform.portfolio.savings.api.SavingsApiConstants.interestCompoundingPeriodTypeParamName;
|
||||
import static org.mifosplatform.portfolio.savings.api.SavingsApiConstants.interestPostingPeriodTypeParamName;
|
||||
import static org.mifosplatform.portfolio.savings.api.SavingsApiConstants.lockinPeriodFrequencyParamName;
|
||||
import static org.mifosplatform.portfolio.savings.api.SavingsApiConstants.lockinPeriodFrequencyTypeParamName;
|
||||
import static org.mifosplatform.portfolio.savings.api.SavingsApiConstants.minRequiredOpeningBalanceParamName;
|
||||
import static org.mifosplatform.portfolio.savings.api.SavingsApiConstants.nominalAnnualInterestRateParamName;
|
||||
import static org.mifosplatform.portfolio.savings.api.SavingsApiConstants.withdrawalFeeAmountParamName;
|
||||
import static org.mifosplatform.portfolio.savings.api.SavingsApiConstants.withdrawalFeeTypeParamName;
|
||||
import static org.mifosplatform.portfolio.savings.SavingsApiConstants.accountNoParamName;
|
||||
import static org.mifosplatform.portfolio.savings.SavingsApiConstants.annualFeeAmountParamName;
|
||||
import static org.mifosplatform.portfolio.savings.SavingsApiConstants.annualFeeOnMonthDayParamName;
|
||||
import static org.mifosplatform.portfolio.savings.SavingsApiConstants.clientIdParamName;
|
||||
import static org.mifosplatform.portfolio.savings.SavingsApiConstants.externalIdParamName;
|
||||
import static org.mifosplatform.portfolio.savings.SavingsApiConstants.fieldOfficerIdParamName;
|
||||
import static org.mifosplatform.portfolio.savings.SavingsApiConstants.groupIdParamName;
|
||||
import static org.mifosplatform.portfolio.savings.SavingsApiConstants.interestCalculationDaysInYearTypeParamName;
|
||||
import static org.mifosplatform.portfolio.savings.SavingsApiConstants.interestCalculationTypeParamName;
|
||||
import static org.mifosplatform.portfolio.savings.SavingsApiConstants.interestCompoundingPeriodTypeParamName;
|
||||
import static org.mifosplatform.portfolio.savings.SavingsApiConstants.interestPostingPeriodTypeParamName;
|
||||
import static org.mifosplatform.portfolio.savings.SavingsApiConstants.lockinPeriodFrequencyParamName;
|
||||
import static org.mifosplatform.portfolio.savings.SavingsApiConstants.lockinPeriodFrequencyTypeParamName;
|
||||
import static org.mifosplatform.portfolio.savings.SavingsApiConstants.minRequiredOpeningBalanceParamName;
|
||||
import static org.mifosplatform.portfolio.savings.SavingsApiConstants.nominalAnnualInterestRateParamName;
|
||||
import static org.mifosplatform.portfolio.savings.SavingsApiConstants.productIdParamName;
|
||||
import static org.mifosplatform.portfolio.savings.SavingsApiConstants.submittedOnDateParamName;
|
||||
import static org.mifosplatform.portfolio.savings.SavingsApiConstants.withdrawalFeeAmountParamName;
|
||||
import static org.mifosplatform.portfolio.savings.SavingsApiConstants.withdrawalFeeTypeParamName;
|
||||
|
||||
import java.math.BigDecimal;
|
||||
import java.util.List;
|
||||
import java.util.Locale;
|
||||
|
||||
import org.joda.time.LocalDate;
|
||||
import org.joda.time.MonthDay;
|
||||
import org.joda.time.format.DateTimeFormat;
|
||||
import org.joda.time.format.DateTimeFormatter;
|
||||
import org.mifosplatform.infrastructure.core.api.JsonCommand;
|
||||
import org.mifosplatform.infrastructure.core.serialization.FromJsonHelper;
|
||||
import org.mifosplatform.infrastructure.core.service.DateUtils;
|
||||
import org.mifosplatform.organisation.staff.domain.Staff;
|
||||
import org.mifosplatform.organisation.staff.domain.StaffRepositoryWrapper;
|
||||
import org.mifosplatform.portfolio.client.domain.Client;
|
||||
import org.mifosplatform.portfolio.client.domain.ClientRepositoryWrapper;
|
||||
import org.mifosplatform.portfolio.group.domain.Group;
|
||||
import org.mifosplatform.portfolio.group.domain.GroupRepository;
|
||||
import org.mifosplatform.portfolio.group.exception.GroupNotFoundException;
|
||||
import org.mifosplatform.portfolio.group.domain.GroupRepositoryWrapper;
|
||||
import org.mifosplatform.portfolio.savings.SavingsCompoundingInterestPeriodType;
|
||||
import org.mifosplatform.portfolio.savings.SavingsInterestCalculationDaysInYearType;
|
||||
import org.mifosplatform.portfolio.savings.SavingsInterestCalculationType;
|
||||
import org.mifosplatform.portfolio.savings.SavingsPeriodFrequencyType;
|
||||
import org.mifosplatform.portfolio.savings.SavingsPostingInterestPeriodType;
|
||||
import org.mifosplatform.portfolio.savings.SavingsWithdrawalFeesType;
|
||||
import org.mifosplatform.portfolio.savings.exception.SavingsProductNotFoundException;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.stereotype.Service;
|
||||
@@ -46,18 +55,24 @@ public class SavingsAccountAssembler {
|
||||
|
||||
private final SavingsAccountTransactionSummaryWrapper savingsAccountTransactionSummaryWrapper;
|
||||
private final ClientRepositoryWrapper clientRepository;
|
||||
private final GroupRepository groupRepository;
|
||||
private final GroupRepositoryWrapper groupRepository;
|
||||
private final StaffRepositoryWrapper staffRepository;
|
||||
private final SavingsProductRepository savingProductRepository;
|
||||
private final SavingsAccountRepositoryWrapper savingsAccountRepository;
|
||||
private final FromJsonHelper fromApiJsonHelper;
|
||||
|
||||
@Autowired
|
||||
public SavingsAccountAssembler(final SavingsAccountTransactionSummaryWrapper savingsAccountTransactionSummaryWrapper,
|
||||
final ClientRepositoryWrapper clientRepository, final GroupRepository groupRepository,
|
||||
final SavingsProductRepository savingProductRepository, final FromJsonHelper fromApiJsonHelper) {
|
||||
final ClientRepositoryWrapper clientRepository, final GroupRepositoryWrapper groupRepository,
|
||||
final StaffRepositoryWrapper staffRepository, final SavingsProductRepository savingProductRepository,
|
||||
final SavingsAccountRepositoryWrapper savingsAccountRepository,
|
||||
final FromJsonHelper fromApiJsonHelper) {
|
||||
this.savingsAccountTransactionSummaryWrapper = savingsAccountTransactionSummaryWrapper;
|
||||
this.clientRepository = clientRepository;
|
||||
this.groupRepository = groupRepository;
|
||||
this.staffRepository = staffRepository;
|
||||
this.savingProductRepository = savingProductRepository;
|
||||
this.savingsAccountRepository = savingsAccountRepository;
|
||||
this.fromApiJsonHelper = fromApiJsonHelper;
|
||||
}
|
||||
|
||||
@@ -65,36 +80,39 @@ public class SavingsAccountAssembler {
|
||||
* Assembles a new {@link SavingsAccount} from JSON details passed in
|
||||
* request inheriting details where relevant from chosen
|
||||
* {@link SavingsProduct}.
|
||||
*
|
||||
* @param existingReversedTransactionIds
|
||||
* @param existingTransactionIds
|
||||
*/
|
||||
public SavingsAccount assembleFrom(final JsonCommand command, List<Long> existingTransactionIds,
|
||||
List<Long> existingReversedTransactionIds) {
|
||||
public SavingsAccount assembleFrom(final JsonCommand command) {
|
||||
|
||||
final JsonElement element = command.parsedJson();
|
||||
|
||||
final String accountNo = fromApiJsonHelper.extractStringNamed("accountNo", element);
|
||||
final String externalId = fromApiJsonHelper.extractStringNamed("externalId", element);
|
||||
final Long productId = fromApiJsonHelper.extractLongNamed("productId", element);
|
||||
final String accountNo = fromApiJsonHelper.extractStringNamed(accountNoParamName, element);
|
||||
final String externalId = fromApiJsonHelper.extractStringNamed(externalIdParamName, element);
|
||||
final Long productId = fromApiJsonHelper.extractLongNamed(productIdParamName, element);
|
||||
|
||||
final SavingsProduct product = this.savingProductRepository.findOne(productId);
|
||||
if (product == null) { throw new SavingsProductNotFoundException(productId); }
|
||||
|
||||
final Long clientId = fromApiJsonHelper.extractLongNamed("clientId", element);
|
||||
final Long groupId = fromApiJsonHelper.extractLongNamed("groupId", element);
|
||||
|
||||
Client client = null;
|
||||
Group group = null;
|
||||
Staff fieldOfficer = null;
|
||||
|
||||
final Long clientId = fromApiJsonHelper.extractLongNamed(clientIdParamName, element);
|
||||
if (clientId != null) {
|
||||
client = this.clientRepository.findOneWithNotFoundDetection(clientId);
|
||||
}
|
||||
|
||||
final Long groupId = fromApiJsonHelper.extractLongNamed(groupIdParamName, element);
|
||||
if (groupId != null) {
|
||||
group = this.groupRepository.findOne(groupId);
|
||||
if (group == null) { throw new GroupNotFoundException(groupId); }
|
||||
group = this.groupRepository.findOneWithNotFoundDetection(groupId);
|
||||
}
|
||||
|
||||
final Long fieldOfficerId = fromApiJsonHelper.extractLongNamed(fieldOfficerIdParamName, element);
|
||||
if (fieldOfficerId != null) {
|
||||
fieldOfficer = this.staffRepository.findOneWithNotFoundDetection(fieldOfficerId);
|
||||
}
|
||||
|
||||
final LocalDate submittedOnDate = fromApiJsonHelper.extractLocalDateNamed(submittedOnDateParamName, element);
|
||||
|
||||
BigDecimal interestRate = null;
|
||||
if (command.parameterExists(nominalAnnualInterestRateParamName)) {
|
||||
interestRate = command.bigDecimalValueOfParameterNamed(nominalAnnualInterestRateParamName);
|
||||
@@ -102,9 +120,6 @@ public class SavingsAccountAssembler {
|
||||
interestRate = product.nominalAnnualInterestRate();
|
||||
}
|
||||
|
||||
final boolean active = fromApiJsonHelper.extractBooleanNamed(activeParamName, element);
|
||||
final LocalDate activationDate = fromApiJsonHelper.extractLocalDateNamed(activationDateParamName, element);
|
||||
|
||||
SavingsCompoundingInterestPeriodType interestCompoundingPeriodType = null;
|
||||
final Integer interestPeriodTypeValue = command.integerValueOfParameterNamed(interestCompoundingPeriodTypeParamName);
|
||||
if (interestPeriodTypeValue != null) {
|
||||
@@ -113,10 +128,10 @@ public class SavingsAccountAssembler {
|
||||
interestCompoundingPeriodType = product.interestCompoundingPeriodType();
|
||||
}
|
||||
|
||||
SavingsInterestPostingPeriodType interestPostingPeriodType = null;
|
||||
SavingsPostingInterestPeriodType interestPostingPeriodType = null;
|
||||
final Integer interestPostingPeriodTypeValue = command.integerValueOfParameterNamed(interestPostingPeriodTypeParamName);
|
||||
if (interestPostingPeriodTypeValue != null) {
|
||||
interestPostingPeriodType = SavingsInterestPostingPeriodType.fromInt(interestPostingPeriodTypeValue);
|
||||
interestPostingPeriodType = SavingsPostingInterestPeriodType.fromInt(interestPostingPeriodTypeValue);
|
||||
} else {
|
||||
interestPostingPeriodType = product.interestPostingPeriodType();
|
||||
}
|
||||
@@ -194,17 +209,20 @@ public class SavingsAccountAssembler {
|
||||
monthDayOfAnnualFee = product.monthDayOfAnnualFee();
|
||||
}
|
||||
|
||||
final SavingsAccount account = SavingsAccount.createNewAccount(client, group, product, accountNo, externalId, interestRate,
|
||||
interestCompoundingPeriodType, interestPostingPeriodType, interestCalculationType, interestCalculationDaysInYearType,
|
||||
minRequiredOpeningBalance, lockinPeriodFrequency, lockinPeriodFrequencyType, withdrawalFeeAmount, withdrawalFeeType,
|
||||
annualFeeAmount, monthDayOfAnnualFee);
|
||||
final SavingsAccount account = SavingsAccount.createNewApplicationForSubmittal(client, group, product, fieldOfficer, accountNo, externalId,
|
||||
submittedOnDate, interestRate, interestCompoundingPeriodType, interestPostingPeriodType, interestCalculationType,
|
||||
interestCalculationDaysInYearType, minRequiredOpeningBalance, lockinPeriodFrequency, lockinPeriodFrequencyType,
|
||||
withdrawalFeeAmount, withdrawalFeeType, annualFeeAmount, monthDayOfAnnualFee);
|
||||
account.setHelpers(this.savingsAccountTransactionSummaryWrapper);
|
||||
|
||||
if (active) {
|
||||
final Locale locale = command.extractLocale();
|
||||
final DateTimeFormatter formatter = DateTimeFormat.forPattern(command.dateFormat()).withLocale(locale);
|
||||
account.activate(formatter, activationDate, existingTransactionIds, existingReversedTransactionIds);
|
||||
}
|
||||
account.validateNewApplicationState(DateUtils.getLocalDateOfTenant());
|
||||
|
||||
return account;
|
||||
}
|
||||
|
||||
public SavingsAccount assembleFrom(final Long savingsId) {
|
||||
SavingsAccount account = this.savingsAccountRepository.findOneWithNotFoundDetection(savingsId);
|
||||
account.setHelpers(this.savingsAccountTransactionSummaryWrapper);
|
||||
|
||||
return account;
|
||||
}
|
||||
|
||||
-65
@@ -1,65 +0,0 @@
|
||||
/**
|
||||
* 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;
|
||||
|
||||
import java.math.BigDecimal;
|
||||
import java.math.MathContext;
|
||||
import java.math.RoundingMode;
|
||||
|
||||
import org.mifosplatform.infrastructure.core.domain.LocalDateInterval;
|
||||
import org.mifosplatform.organisation.monetary.domain.MonetaryCurrency;
|
||||
import org.mifosplatform.organisation.monetary.domain.Money;
|
||||
|
||||
public class SavingsAccountDailyBalance {
|
||||
|
||||
private final LocalDateInterval interestPeriodInterval;
|
||||
private final BigDecimal endOfDayBalance;
|
||||
private final BigDecimal cumulativeBalance;
|
||||
private final BigDecimal compoundedInterestToDate;
|
||||
|
||||
public static SavingsAccountDailyBalance createFrom(final LocalDateInterval interestPeriodInterval, final BigDecimal endOfDayBalance,
|
||||
final BigDecimal compoundedInterestToDate) {
|
||||
return new SavingsAccountDailyBalance(interestPeriodInterval, endOfDayBalance, compoundedInterestToDate);
|
||||
}
|
||||
|
||||
private SavingsAccountDailyBalance(final LocalDateInterval interestPeriodInterval, final BigDecimal endOfDayBalance,
|
||||
final BigDecimal compoundedInterestToDate) {
|
||||
this.interestPeriodInterval = interestPeriodInterval;
|
||||
this.endOfDayBalance = endOfDayBalance;
|
||||
this.compoundedInterestToDate = compoundedInterestToDate;
|
||||
final MathContext mc = new MathContext(10, RoundingMode.HALF_EVEN);
|
||||
final BigDecimal numberOfDaysBigDecimal = BigDecimal.valueOf(interestPeriodInterval.daysInPeriodInclusiveOfEndDate());
|
||||
this.cumulativeBalance = endOfDayBalance.multiply(numberOfDaysBigDecimal, mc);
|
||||
}
|
||||
|
||||
public Money dailyRunningBalance(final MonetaryCurrency currency) {
|
||||
return Money.of(currency, endOfDayBalance);
|
||||
}
|
||||
|
||||
public BigDecimal endOfDayBalance() {
|
||||
return this.endOfDayBalance;
|
||||
}
|
||||
|
||||
public BigDecimal cumulativeBalance() {
|
||||
return this.cumulativeBalance;
|
||||
}
|
||||
|
||||
public Integer numberOfDays() {
|
||||
return interestPeriodInterval.daysInPeriodInclusiveOfEndDate();
|
||||
}
|
||||
|
||||
public boolean isGreaterThanZero() {
|
||||
return this.endOfDayBalance.compareTo(BigDecimal.ZERO) > 0;
|
||||
}
|
||||
|
||||
public BigDecimal interestUsingDailyBalanceMethod(final BigDecimal dailyInterestRate, final Integer numberOfDays) {
|
||||
final MathContext mc = new MathContext(10, RoundingMode.HALF_EVEN);
|
||||
final BigDecimal numberOfDaysBigDecimal = BigDecimal.valueOf(numberOfDays.longValue());
|
||||
|
||||
final BigDecimal compoundedEndOfDayBalance = this.endOfDayBalance.add(this.compoundedInterestToDate, mc);
|
||||
return compoundedEndOfDayBalance.multiply(dailyInterestRate, mc).multiply(numberOfDaysBigDecimal, mc);
|
||||
}
|
||||
}
|
||||
+28
-4
@@ -11,8 +11,11 @@ package org.mifosplatform.portfolio.savings.domain;
|
||||
public enum SavingsAccountStatusType {
|
||||
|
||||
INVALID(0, "savingsAccountStatusType.invalid"), //
|
||||
UNACTIVATED(100, "savingsAccountStatusType.unactivated"), //
|
||||
SUBMITTED_AND_PENDING_APPROVAL(100, "savingsAccountStatusType.submitted.and.pending.approval"), //
|
||||
APPROVED(200, "savingsAccountStatusType.approved"), //
|
||||
ACTIVE(300, "savingsAccountStatusType.active"), //
|
||||
WITHDRAWN_BY_APPLICANT(400, "savingsAccountStatusType.withdrawn.by.applicant"), //
|
||||
REJECTED(500, "savingsAccountStatusType.rejected"), //
|
||||
CLOSED(600, "savingsAccountStatusType.closed");
|
||||
|
||||
private final Integer value;
|
||||
@@ -23,11 +26,20 @@ public enum SavingsAccountStatusType {
|
||||
SavingsAccountStatusType enumeration = SavingsAccountStatusType.INVALID;
|
||||
switch (type) {
|
||||
case 100:
|
||||
enumeration = SavingsAccountStatusType.UNACTIVATED;
|
||||
enumeration = SavingsAccountStatusType.SUBMITTED_AND_PENDING_APPROVAL;
|
||||
break;
|
||||
case 200:
|
||||
enumeration = SavingsAccountStatusType.APPROVED;
|
||||
break;
|
||||
case 300:
|
||||
enumeration = SavingsAccountStatusType.ACTIVE;
|
||||
break;
|
||||
case 400:
|
||||
enumeration = SavingsAccountStatusType.WITHDRAWN_BY_APPLICANT;
|
||||
break;
|
||||
case 500:
|
||||
enumeration = SavingsAccountStatusType.REJECTED;
|
||||
break;
|
||||
case 600:
|
||||
enumeration = SavingsAccountStatusType.CLOSED;
|
||||
break;
|
||||
@@ -52,8 +64,20 @@ public enum SavingsAccountStatusType {
|
||||
return code;
|
||||
}
|
||||
|
||||
public boolean isUnactivated() {
|
||||
return this.value.equals(SavingsAccountStatusType.UNACTIVATED.getValue());
|
||||
public boolean isSubmittedAndPendingApproval() {
|
||||
return this.value.equals(SavingsAccountStatusType.SUBMITTED_AND_PENDING_APPROVAL.getValue());
|
||||
}
|
||||
|
||||
public boolean isApproved() {
|
||||
return this.value.equals(SavingsAccountStatusType.APPROVED.getValue());
|
||||
}
|
||||
|
||||
public boolean isRejected() {
|
||||
return this.value.equals(SavingsAccountStatusType.REJECTED.getValue());
|
||||
}
|
||||
|
||||
public boolean isApplicationWithdrawnByApplicant() {
|
||||
return this.value.equals(SavingsAccountStatusType.WITHDRAWN_BY_APPLICANT.getValue());
|
||||
}
|
||||
|
||||
public boolean isActive() {
|
||||
|
||||
+6
-9
@@ -13,6 +13,7 @@ import javax.persistence.Embeddable;
|
||||
|
||||
import org.mifosplatform.organisation.monetary.domain.MonetaryCurrency;
|
||||
import org.mifosplatform.organisation.monetary.domain.Money;
|
||||
import org.mifosplatform.portfolio.savings.domain.interest.PostingPeriod;
|
||||
|
||||
/**
|
||||
* {@link SavingsAccountSummary} encapsulates all the summary details of a
|
||||
@@ -60,19 +61,15 @@ public final class SavingsAccountSummary {
|
||||
.minus(this.totalWithdrawalFees).minus(this.totalAnnualFees).getAmount();
|
||||
}
|
||||
|
||||
public void updateFromInterestPeriodSummaries(final MonetaryCurrency currency,
|
||||
final List<InterestCompoundingPeriodSummary> compoundingPeriods) {
|
||||
public void updateFromInterestPeriodSummaries(final MonetaryCurrency currency, final List<PostingPeriod> allPostingPeriods) {
|
||||
|
||||
// get the max compounded interest
|
||||
final BigDecimal compoundedInterestToDate = compoundingPeriods.get(compoundingPeriods.size() - 1).compoundedInterest();
|
||||
final Money maxIntrestCompoundedToDate = Money.of(currency, compoundedInterestToDate);
|
||||
Money totalEarned = Money.zero(currency);
|
||||
|
||||
BigDecimal totalInterestUnrounded = BigDecimal.ZERO;
|
||||
for (InterestCompoundingPeriodSummary interestPeriodSummary : compoundingPeriods) {
|
||||
totalInterestUnrounded = totalInterestUnrounded.add(interestPeriodSummary.interestUnrounded());
|
||||
for (PostingPeriod period : allPostingPeriods) {
|
||||
totalEarned = totalEarned.plus(period.interest());
|
||||
}
|
||||
|
||||
this.totalInterestEarned = maxIntrestCompoundedToDate.getAmountDefaultedToNullIfZero();
|
||||
this.totalInterestEarned = totalEarned.getAmount();
|
||||
}
|
||||
|
||||
public boolean isLessThanOrEqualToAccountBalance(final Money amount) {
|
||||
|
||||
+97
-21
@@ -24,7 +24,9 @@ import org.mifosplatform.organisation.monetary.data.CurrencyData;
|
||||
import org.mifosplatform.organisation.monetary.domain.MonetaryCurrency;
|
||||
import org.mifosplatform.organisation.monetary.domain.Money;
|
||||
import org.mifosplatform.portfolio.paymentdetail.domain.PaymentDetail;
|
||||
import org.mifosplatform.portfolio.savings.SavingsAccountTransactionType;
|
||||
import org.mifosplatform.portfolio.savings.data.SavingsAccountTransactionEnumData;
|
||||
import org.mifosplatform.portfolio.savings.domain.interest.EndOfDayBalance;
|
||||
import org.mifosplatform.portfolio.savings.service.SavingsEnumerations;
|
||||
import org.springframework.data.jpa.domain.AbstractPersistable;
|
||||
|
||||
@@ -205,27 +207,6 @@ public final class SavingsAccountTransaction extends AbstractPersistable<Long> {
|
||||
return this.balanceNumberOfDays != null && this.balanceNumberOfDays > 0;
|
||||
}
|
||||
|
||||
public SavingsAccountDailyBalance toDailyBalance(final LocalDate periodEnd) {
|
||||
|
||||
LocalDate balanceValidTo = getEndOfBalanceLocalDate();
|
||||
if (periodEnd.isBefore(getEndOfBalanceLocalDate())) {
|
||||
balanceValidTo = periodEnd;
|
||||
}
|
||||
|
||||
final LocalDateInterval interestPeriodInterval = LocalDateInterval.create(getTransactionLocalDate(), balanceValidTo);
|
||||
return SavingsAccountDailyBalance.createFrom(interestPeriodInterval, this.runningBalance, BigDecimal.ZERO);
|
||||
}
|
||||
|
||||
public SavingsAccountDailyBalance toCompoundedDailyBalance(final LocalDate periodEnd, final BigDecimal compoundedInterestToDate) {
|
||||
LocalDate balanceValidTo = getEndOfBalanceLocalDate();
|
||||
if (periodEnd.isBefore(getEndOfBalanceLocalDate())) {
|
||||
balanceValidTo = periodEnd;
|
||||
}
|
||||
|
||||
final LocalDateInterval interestPeriodInterval = LocalDateInterval.create(getTransactionLocalDate(), balanceValidTo);
|
||||
return SavingsAccountDailyBalance.createFrom(interestPeriodInterval, this.runningBalance, compoundedInterestToDate);
|
||||
}
|
||||
|
||||
public boolean hasNotAmount(final Money amountToCheck) {
|
||||
final Money transactionAmount = getAmount(amountToCheck.getCurrency());
|
||||
return transactionAmount.isNotEqualTo(amountToCheck);
|
||||
@@ -249,4 +230,99 @@ public final class SavingsAccountTransaction extends AbstractPersistable<Long> {
|
||||
|
||||
return thisTransactionData;
|
||||
}
|
||||
|
||||
public boolean isAfter(final LocalDate transactionDate) {
|
||||
return this.getTransactionLocalDate().isAfter(transactionDate);
|
||||
}
|
||||
|
||||
public EndOfDayBalance toEndOfDayBalance(final LocalDateInterval periodInterval, final MonetaryCurrency currency) {
|
||||
|
||||
Money endOfDayBalance = Money.of(currency, this.runningBalance);
|
||||
Money openingBalance = endOfDayBalance;
|
||||
|
||||
LocalDate balanceDate = periodInterval.startDate();
|
||||
|
||||
int numberOfDays = periodInterval.daysInPeriodInclusiveOfEndDate();
|
||||
if (periodInterval.contains(getTransactionLocalDate())) {
|
||||
balanceDate = getTransactionLocalDate();
|
||||
LocalDateInterval newInterval = LocalDateInterval.create(getTransactionLocalDate(), periodInterval.endDate());
|
||||
numberOfDays = newInterval.daysInPeriodInclusiveOfEndDate();
|
||||
}
|
||||
|
||||
return EndOfDayBalance.from(balanceDate, openingBalance, endOfDayBalance, numberOfDays);
|
||||
}
|
||||
|
||||
public EndOfDayBalance toEndOfDayBalance(final Money openingBalance, final LocalDate nextTransactionDate) {
|
||||
|
||||
MonetaryCurrency currency = openingBalance.getCurrency();
|
||||
Money endOfDayBalance = openingBalance.copy();
|
||||
if (isDeposit()) {
|
||||
endOfDayBalance = openingBalance.plus(getAmount(currency));
|
||||
} else if (isWithdrawal() || isWithdrawalFee()) {
|
||||
endOfDayBalance = openingBalance.minus(getAmount(currency));
|
||||
}
|
||||
|
||||
int numberOfDays = LocalDateInterval.create(getTransactionLocalDate(), nextTransactionDate).daysInPeriodInclusiveOfEndDate();
|
||||
if (!openingBalance.isEqualTo(endOfDayBalance) && numberOfDays > 1) {
|
||||
numberOfDays = numberOfDays - 1;
|
||||
}
|
||||
return EndOfDayBalance.from(getTransactionLocalDate(), openingBalance, endOfDayBalance, numberOfDays);
|
||||
}
|
||||
|
||||
public EndOfDayBalance toEndOfDayBalance(final Money openingBalance) {
|
||||
MonetaryCurrency currency = openingBalance.getCurrency();
|
||||
Money endOfDayBalance = openingBalance.copy();
|
||||
if (isDeposit()) {
|
||||
endOfDayBalance = openingBalance.plus(getAmount(currency));
|
||||
} else if (isWithdrawal() || isWithdrawalFee()) {
|
||||
endOfDayBalance = openingBalance.minus(getAmount(currency));
|
||||
}
|
||||
|
||||
return EndOfDayBalance.from(getTransactionLocalDate(), openingBalance, endOfDayBalance, this.balanceNumberOfDays);
|
||||
}
|
||||
|
||||
public EndOfDayBalance toEndOfDayBalanceBoundedBy(final Money openingBalance, final LocalDateInterval boundedBy) {
|
||||
|
||||
MonetaryCurrency currency = openingBalance.getCurrency();
|
||||
Money endOfDayBalance = openingBalance.copy();
|
||||
|
||||
int numberOfDaysOfBalance = this.balanceNumberOfDays;
|
||||
|
||||
LocalDate balanceStartDate = getTransactionLocalDate();
|
||||
LocalDate balanceEndDate = getEndOfBalanceLocalDate();
|
||||
|
||||
if (boundedBy.startDate().isAfter(balanceStartDate)) {
|
||||
balanceStartDate = boundedBy.startDate();
|
||||
LocalDateInterval spanOfBalance = LocalDateInterval.create(balanceStartDate, balanceEndDate);
|
||||
numberOfDaysOfBalance = spanOfBalance.daysInPeriodInclusiveOfEndDate();
|
||||
} else {
|
||||
if (isDeposit()) {
|
||||
endOfDayBalance = openingBalance.plus(getAmount(currency));
|
||||
} else if (isWithdrawal() || isWithdrawalFee()) {
|
||||
endOfDayBalance = openingBalance.minus(getAmount(currency));
|
||||
}
|
||||
}
|
||||
|
||||
if (balanceEndDate.isAfter(boundedBy.endDate())) {
|
||||
balanceEndDate = boundedBy.endDate();
|
||||
LocalDateInterval spanOfBalance = LocalDateInterval.create(balanceStartDate, balanceEndDate);
|
||||
numberOfDaysOfBalance = spanOfBalance.daysInPeriodInclusiveOfEndDate();
|
||||
}
|
||||
|
||||
return EndOfDayBalance.from(balanceStartDate, openingBalance, endOfDayBalance, numberOfDaysOfBalance);
|
||||
}
|
||||
|
||||
public boolean isBalanceInExistencesForOneDayOrMore() {
|
||||
return this.balanceNumberOfDays != null && this.balanceNumberOfDays.intValue() >= 1;
|
||||
}
|
||||
|
||||
public boolean fallsWithin(final LocalDateInterval periodInterval) {
|
||||
LocalDateInterval balanceInterval = LocalDateInterval.create(getTransactionLocalDate(), getEndOfBalanceLocalDate());
|
||||
return periodInterval.contains(balanceInterval);
|
||||
}
|
||||
|
||||
public boolean spansAnyPortionOf(final LocalDateInterval periodInterval) {
|
||||
LocalDateInterval balanceInterval = LocalDateInterval.create(getTransactionLocalDate(), getEndOfBalanceLocalDate());
|
||||
return balanceInterval.containsPortionOf(periodInterval);
|
||||
}
|
||||
}
|
||||
-15
@@ -1,15 +0,0 @@
|
||||
/**
|
||||
* 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;
|
||||
|
||||
import java.math.BigDecimal;
|
||||
import java.util.List;
|
||||
|
||||
public interface SavingsCompoundInterestCalculator {
|
||||
|
||||
BigDecimal calculate(List<SavingsAccountDailyBalance> dailyBalances, Integer numberOfDays);
|
||||
|
||||
}
|
||||
-49
@@ -1,49 +0,0 @@
|
||||
/**
|
||||
* 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;
|
||||
|
||||
import java.math.BigDecimal;
|
||||
import java.math.MathContext;
|
||||
import java.math.RoundingMode;
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
* Calculates interest on a savings account using the <b>Average Balance</b>
|
||||
* method.
|
||||
*/
|
||||
public class SavingsCompoundInterestCalculatorForAverageBalance implements SavingsCompoundInterestCalculator {
|
||||
|
||||
private final BigDecimal periodsInOneYearAsFraction;
|
||||
private final BigDecimal annualInterestRateAsFraction;
|
||||
|
||||
public SavingsCompoundInterestCalculatorForAverageBalance(final BigDecimal periodsInOneYearAsFraction,
|
||||
final BigDecimal annualInterestRateAsFraction) {
|
||||
this.periodsInOneYearAsFraction = periodsInOneYearAsFraction;
|
||||
this.annualInterestRateAsFraction = annualInterestRateAsFraction;
|
||||
}
|
||||
|
||||
@Override
|
||||
public BigDecimal calculate(final List<SavingsAccountDailyBalance> dailyBalances, final Integer numberOfDays) {
|
||||
|
||||
final MathContext mc = new MathContext(10, RoundingMode.HALF_EVEN);
|
||||
final BigDecimal dailyInterestRate = annualInterestRateAsFraction.multiply(periodsInOneYearAsFraction, mc);
|
||||
final BigDecimal periodicInterestRate = dailyInterestRate.multiply(BigDecimal.valueOf(numberOfDays.longValue()));
|
||||
|
||||
final BigDecimal numberOfDaysBigDecimal = BigDecimal.valueOf(numberOfDays.longValue());
|
||||
|
||||
BigDecimal totalCumulativeBalanceForPeriod = BigDecimal.ZERO;
|
||||
for (SavingsAccountDailyBalance balance : dailyBalances) {
|
||||
if (balance.isGreaterThanZero()) {
|
||||
final BigDecimal cumulativeBalance = balance.cumulativeBalance();
|
||||
totalCumulativeBalanceForPeriod = totalCumulativeBalanceForPeriod.add(cumulativeBalance);
|
||||
}
|
||||
}
|
||||
|
||||
final BigDecimal averageDailyBalance = totalCumulativeBalanceForPeriod.divide(numberOfDaysBigDecimal, mc);
|
||||
|
||||
return averageDailyBalance.multiply(periodicInterestRate, mc);
|
||||
}
|
||||
}
|
||||
-44
@@ -1,44 +0,0 @@
|
||||
/**
|
||||
* 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;
|
||||
|
||||
import java.math.BigDecimal;
|
||||
import java.math.MathContext;
|
||||
import java.math.RoundingMode;
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
* Calculates interest on a savings account using the <b>Daily Balance</b>
|
||||
* method.
|
||||
*/
|
||||
public class SavingsCompoundInterestCalculatorForDailyBalance implements SavingsCompoundInterestCalculator {
|
||||
|
||||
private final BigDecimal periodsInOneYearAsFraction;
|
||||
private final BigDecimal annualInterestRateAsFraction;
|
||||
|
||||
public SavingsCompoundInterestCalculatorForDailyBalance(final BigDecimal periodsInOneYearAsFraction,
|
||||
final BigDecimal annualInterestRateAsFraction) {
|
||||
this.periodsInOneYearAsFraction = periodsInOneYearAsFraction;
|
||||
this.annualInterestRateAsFraction = annualInterestRateAsFraction;
|
||||
}
|
||||
|
||||
@Override
|
||||
public BigDecimal calculate(final List<SavingsAccountDailyBalance> dailyBalances, final Integer numberOfDays) {
|
||||
final MathContext mc = new MathContext(10, RoundingMode.HALF_EVEN);
|
||||
final BigDecimal dailyInterestRate = annualInterestRateAsFraction.multiply(periodsInOneYearAsFraction, mc);
|
||||
|
||||
BigDecimal interestCalculated = BigDecimal.ZERO;
|
||||
|
||||
for (SavingsAccountDailyBalance balance : dailyBalances) {
|
||||
if (balance.isGreaterThanZero()) {
|
||||
final BigDecimal interestForBalance = balance.interestUsingDailyBalanceMethod(dailyInterestRate, balance.numberOfDays());
|
||||
interestCalculated = interestCalculated.add(interestForBalance, mc);
|
||||
}
|
||||
}
|
||||
|
||||
return interestCalculated;
|
||||
}
|
||||
}
|
||||
+88
@@ -0,0 +1,88 @@
|
||||
package org.mifosplatform.portfolio.savings.domain;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
|
||||
import org.joda.time.DateTime;
|
||||
import org.joda.time.LocalDate;
|
||||
import org.mifosplatform.infrastructure.core.domain.LocalDateInterval;
|
||||
import org.mifosplatform.infrastructure.core.service.DateUtils;
|
||||
import org.mifosplatform.organisation.monetary.domain.MonetaryCurrency;
|
||||
import org.mifosplatform.organisation.monetary.domain.Money;
|
||||
import org.mifosplatform.portfolio.savings.SavingsPostingInterestPeriodType;
|
||||
import org.mifosplatform.portfolio.savings.domain.interest.CompoundInterestHelper;
|
||||
import org.mifosplatform.portfolio.savings.domain.interest.PostingPeriod;
|
||||
|
||||
public final class SavingsHelper {
|
||||
|
||||
private final CompoundInterestHelper compoundInterestHelper = new CompoundInterestHelper();
|
||||
|
||||
public List<LocalDateInterval> determineInterestPostingPeriods(final LocalDate activationLocalDate,
|
||||
final LocalDate interestPostingUpToDate, final SavingsPostingInterestPeriodType postingPeriodType) {
|
||||
|
||||
List<LocalDateInterval> postingPeriods = new ArrayList<LocalDateInterval>();
|
||||
|
||||
LocalDate periodStartDate = activationLocalDate;
|
||||
LocalDate periodEndDate = periodStartDate;
|
||||
|
||||
while (!periodStartDate.isAfter(interestPostingUpToDate) && !periodEndDate.isAfter(interestPostingUpToDate)) {
|
||||
|
||||
final LocalDate interestPostingLocalDate = determineInterestPostingPeriodEndDateFrom(periodStartDate, postingPeriodType);
|
||||
periodEndDate = interestPostingLocalDate.minusDays(1);
|
||||
|
||||
if (!interestPostingLocalDate.isAfter(DateUtils.getLocalDateOfTenant())) {
|
||||
postingPeriods.add(LocalDateInterval.create(periodStartDate, periodEndDate));
|
||||
} else {
|
||||
postingPeriods.add(LocalDateInterval.create(periodStartDate, periodEndDate));
|
||||
}
|
||||
|
||||
periodEndDate = interestPostingLocalDate;
|
||||
periodStartDate = interestPostingLocalDate;
|
||||
}
|
||||
|
||||
return postingPeriods;
|
||||
}
|
||||
|
||||
private LocalDate determineInterestPostingPeriodEndDateFrom(final LocalDate periodStartDate,
|
||||
final SavingsPostingInterestPeriodType interestPostingPeriodType) {
|
||||
|
||||
LocalDate periodEndDate = DateUtils.getLocalDateOfTenant();
|
||||
|
||||
switch (interestPostingPeriodType) {
|
||||
case INVALID:
|
||||
break;
|
||||
case MONTHLY:
|
||||
// produce period end date on last day of current month
|
||||
periodEndDate = periodStartDate.dayOfMonth().withMaximumValue();
|
||||
break;
|
||||
case QUATERLY:
|
||||
// jan 1st to mar 31st, 1st apr to jun 30, jul 1st to sept 30,
|
||||
// oct 1st to dec 31
|
||||
int year = periodStartDate.getYearOfEra();
|
||||
int monthofYear = periodStartDate.getMonthOfYear();
|
||||
if (monthofYear <= 3) {
|
||||
periodEndDate = new DateTime().withDate(year, 3, 31).toLocalDate();
|
||||
} else if (monthofYear <= 6) {
|
||||
periodEndDate = new DateTime().withDate(year, 6, 30).toLocalDate();
|
||||
} else if (monthofYear <= 9) {
|
||||
periodEndDate = new DateTime().withDate(year, 9, 30).toLocalDate();
|
||||
} else if (monthofYear <= 12) {
|
||||
periodEndDate = new DateTime().withDate(year, 12, 31).toLocalDate();
|
||||
}
|
||||
break;
|
||||
case ANNUAL:
|
||||
periodEndDate = periodStartDate.monthOfYear().withMaximumValue();
|
||||
periodEndDate = periodEndDate.dayOfMonth().withMaximumValue();
|
||||
break;
|
||||
}
|
||||
|
||||
// interest posting always occurs on next day after the period end date.
|
||||
periodEndDate = periodEndDate.plusDays(1);
|
||||
|
||||
return periodEndDate;
|
||||
}
|
||||
|
||||
public Money calculateInterestForAllPostingPeriods(final MonetaryCurrency currency, final List<PostingPeriod> allPeriods) {
|
||||
return this.compoundInterestHelper.calculateInterestForAllPostingPeriods(currency, allPeriods);
|
||||
}
|
||||
}
|
||||
-32
@@ -1,32 +0,0 @@
|
||||
/**
|
||||
* 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;
|
||||
|
||||
import java.math.BigDecimal;
|
||||
|
||||
public class SavingsInterestCalculatorFactory {
|
||||
|
||||
public SavingsCompoundInterestCalculator createFrom(final SavingsInterestCalculationType interestCalculationType,
|
||||
final BigDecimal periodsInOneYearAsFraction, final BigDecimal annualInterestRateAsFraction) {
|
||||
|
||||
SavingsCompoundInterestCalculator savingsInterestCalculator = new SavingsCompoundInterestCalculatorForDailyBalance(periodsInOneYearAsFraction,
|
||||
annualInterestRateAsFraction);
|
||||
switch (interestCalculationType) {
|
||||
case AVERAGE_DAILY_BALANCE:
|
||||
savingsInterestCalculator = new SavingsCompoundInterestCalculatorForAverageBalance(periodsInOneYearAsFraction,
|
||||
annualInterestRateAsFraction);
|
||||
break;
|
||||
case DAILY_BALANCE:
|
||||
savingsInterestCalculator = new SavingsCompoundInterestCalculatorForDailyBalance(periodsInOneYearAsFraction,
|
||||
annualInterestRateAsFraction);
|
||||
break;
|
||||
case INVALID:
|
||||
break;
|
||||
}
|
||||
|
||||
return savingsInterestCalculator;
|
||||
}
|
||||
}
|
||||
-56
@@ -1,56 +0,0 @@
|
||||
/**
|
||||
* 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;
|
||||
|
||||
/**
|
||||
* The interest posting period is the span of time at the end of which savings
|
||||
* earned but not yet credited/posted in a client's account is credited/posted.
|
||||
*/
|
||||
public enum SavingsInterestPostingPeriodType {
|
||||
|
||||
INVALID(0, "savingsInterestPostingPeriodType.invalid"), //
|
||||
MONTHLY(4, "savingsInterestPostingPeriodType.monthly"), //
|
||||
QUATERLY(5, "savingsInterestPostingPeriodType.quarterly"), //
|
||||
BI_ANNUAL(6, "savingsInterestPostingPeriodType.biannual"), //
|
||||
ANNUAL(7, "savingsInterestPostingPeriodType.annual");
|
||||
|
||||
private final Integer value;
|
||||
private final String code;
|
||||
|
||||
private SavingsInterestPostingPeriodType(final Integer value, final String code) {
|
||||
this.value = value;
|
||||
this.code = code;
|
||||
}
|
||||
|
||||
public Integer getValue() {
|
||||
return this.value;
|
||||
}
|
||||
|
||||
public String getCode() {
|
||||
return code;
|
||||
}
|
||||
|
||||
public static SavingsInterestPostingPeriodType fromInt(final Integer type) {
|
||||
SavingsInterestPostingPeriodType repaymentFrequencyType = SavingsInterestPostingPeriodType.INVALID;
|
||||
if (type != null) {
|
||||
switch (type) {
|
||||
case 4:
|
||||
repaymentFrequencyType = SavingsInterestPostingPeriodType.MONTHLY;
|
||||
break;
|
||||
case 5:
|
||||
repaymentFrequencyType = SavingsInterestPostingPeriodType.QUATERLY;
|
||||
break;
|
||||
case 6:
|
||||
repaymentFrequencyType = SavingsInterestPostingPeriodType.BI_ANNUAL;
|
||||
break;
|
||||
case 7:
|
||||
repaymentFrequencyType = SavingsInterestPostingPeriodType.ANNUAL;
|
||||
break;
|
||||
}
|
||||
}
|
||||
return repaymentFrequencyType;
|
||||
}
|
||||
}
|
||||
+129
-71
@@ -5,27 +5,30 @@
|
||||
*/
|
||||
package org.mifosplatform.portfolio.savings.domain;
|
||||
|
||||
import static org.mifosplatform.portfolio.savings.api.SavingsApiConstants.annualFeeAmountParamName;
|
||||
import static org.mifosplatform.portfolio.savings.api.SavingsApiConstants.annualFeeOnMonthDayParamName;
|
||||
import static org.mifosplatform.portfolio.savings.api.SavingsApiConstants.currencyCodeParamName;
|
||||
import static org.mifosplatform.portfolio.savings.api.SavingsApiConstants.descriptionParamName;
|
||||
import static org.mifosplatform.portfolio.savings.api.SavingsApiConstants.digitsAfterDecimalParamName;
|
||||
import static org.mifosplatform.portfolio.savings.api.SavingsApiConstants.interestCalculationDaysInYearTypeParamName;
|
||||
import static org.mifosplatform.portfolio.savings.api.SavingsApiConstants.interestCalculationTypeParamName;
|
||||
import static org.mifosplatform.portfolio.savings.api.SavingsApiConstants.interestCompoundingPeriodTypeParamName;
|
||||
import static org.mifosplatform.portfolio.savings.api.SavingsApiConstants.interestPostingPeriodTypeParamName;
|
||||
import static org.mifosplatform.portfolio.savings.api.SavingsApiConstants.localeParamName;
|
||||
import static org.mifosplatform.portfolio.savings.api.SavingsApiConstants.lockinPeriodFrequencyParamName;
|
||||
import static org.mifosplatform.portfolio.savings.api.SavingsApiConstants.lockinPeriodFrequencyTypeParamName;
|
||||
import static org.mifosplatform.portfolio.savings.api.SavingsApiConstants.minRequiredOpeningBalanceParamName;
|
||||
import static org.mifosplatform.portfolio.savings.api.SavingsApiConstants.nameParamName;
|
||||
import static org.mifosplatform.portfolio.savings.api.SavingsApiConstants.nominalAnnualInterestRateParamName;
|
||||
import static org.mifosplatform.portfolio.savings.api.SavingsApiConstants.withdrawalFeeAmountParamName;
|
||||
import static org.mifosplatform.portfolio.savings.api.SavingsApiConstants.withdrawalFeeTypeParamName;
|
||||
import static org.mifosplatform.portfolio.savings.api.SavingsApiConstants.accountingRuleParamName;
|
||||
import static org.mifosplatform.portfolio.savings.SavingsApiConstants.SAVINGS_PRODUCT_RESOURCE_NAME;
|
||||
import static org.mifosplatform.portfolio.savings.SavingsApiConstants.accountingRuleParamName;
|
||||
import static org.mifosplatform.portfolio.savings.SavingsApiConstants.annualFeeAmountParamName;
|
||||
import static org.mifosplatform.portfolio.savings.SavingsApiConstants.annualFeeOnMonthDayParamName;
|
||||
import static org.mifosplatform.portfolio.savings.SavingsApiConstants.currencyCodeParamName;
|
||||
import static org.mifosplatform.portfolio.savings.SavingsApiConstants.descriptionParamName;
|
||||
import static org.mifosplatform.portfolio.savings.SavingsApiConstants.digitsAfterDecimalParamName;
|
||||
import static org.mifosplatform.portfolio.savings.SavingsApiConstants.interestCalculationDaysInYearTypeParamName;
|
||||
import static org.mifosplatform.portfolio.savings.SavingsApiConstants.interestCalculationTypeParamName;
|
||||
import static org.mifosplatform.portfolio.savings.SavingsApiConstants.interestCompoundingPeriodTypeParamName;
|
||||
import static org.mifosplatform.portfolio.savings.SavingsApiConstants.interestPostingPeriodTypeParamName;
|
||||
import static org.mifosplatform.portfolio.savings.SavingsApiConstants.localeParamName;
|
||||
import static org.mifosplatform.portfolio.savings.SavingsApiConstants.lockinPeriodFrequencyParamName;
|
||||
import static org.mifosplatform.portfolio.savings.SavingsApiConstants.lockinPeriodFrequencyTypeParamName;
|
||||
import static org.mifosplatform.portfolio.savings.SavingsApiConstants.minRequiredOpeningBalanceParamName;
|
||||
import static org.mifosplatform.portfolio.savings.SavingsApiConstants.nameParamName;
|
||||
import static org.mifosplatform.portfolio.savings.SavingsApiConstants.nominalAnnualInterestRateParamName;
|
||||
import static org.mifosplatform.portfolio.savings.SavingsApiConstants.withdrawalFeeAmountParamName;
|
||||
import static org.mifosplatform.portfolio.savings.SavingsApiConstants.withdrawalFeeTypeParamName;
|
||||
|
||||
import java.math.BigDecimal;
|
||||
import java.util.ArrayList;
|
||||
import java.util.LinkedHashMap;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
|
||||
import javax.persistence.Column;
|
||||
@@ -36,9 +39,17 @@ import javax.persistence.Table;
|
||||
import org.joda.time.MonthDay;
|
||||
import org.mifosplatform.accounting.common.AccountingRuleType;
|
||||
import org.mifosplatform.infrastructure.core.api.JsonCommand;
|
||||
import org.mifosplatform.infrastructure.core.exception.GeneralPlatformDomainRuleException;
|
||||
import org.mifosplatform.infrastructure.core.data.ApiParameterError;
|
||||
import org.mifosplatform.infrastructure.core.data.DataValidatorBuilder;
|
||||
import org.mifosplatform.infrastructure.core.exception.PlatformApiDataValidationException;
|
||||
import org.mifosplatform.organisation.monetary.domain.MonetaryCurrency;
|
||||
import org.mifosplatform.organisation.monetary.domain.Money;
|
||||
import org.mifosplatform.portfolio.savings.SavingsCompoundingInterestPeriodType;
|
||||
import org.mifosplatform.portfolio.savings.SavingsInterestCalculationDaysInYearType;
|
||||
import org.mifosplatform.portfolio.savings.SavingsInterestCalculationType;
|
||||
import org.mifosplatform.portfolio.savings.SavingsPeriodFrequencyType;
|
||||
import org.mifosplatform.portfolio.savings.SavingsPostingInterestPeriodType;
|
||||
import org.mifosplatform.portfolio.savings.SavingsWithdrawalFeesType;
|
||||
import org.springframework.data.jpa.domain.AbstractPersistable;
|
||||
|
||||
@Entity
|
||||
@@ -68,7 +79,7 @@ public class SavingsProduct extends AbstractPersistable<Long> {
|
||||
private Integer interestCompoundingPeriodType;
|
||||
|
||||
/**
|
||||
* A value from the {@link SavingsInterestPostingPeriodType} enumeration.
|
||||
* A value from the {@link SavingsPostingInterestPeriodType} enumeration.
|
||||
*/
|
||||
@Column(name = "interest_posting_period_enum", nullable = false)
|
||||
private Integer interestPostingPeriodType;
|
||||
@@ -118,7 +129,7 @@ public class SavingsProduct extends AbstractPersistable<Long> {
|
||||
|
||||
public static SavingsProduct createNew(final String name, final String description, final MonetaryCurrency currency,
|
||||
final BigDecimal interestRate, final SavingsCompoundingInterestPeriodType interestCompoundingPeriodType,
|
||||
final SavingsInterestPostingPeriodType interestPostingPeriodType, final SavingsInterestCalculationType interestCalculationType,
|
||||
final SavingsPostingInterestPeriodType interestPostingPeriodType, final SavingsInterestCalculationType interestCalculationType,
|
||||
final SavingsInterestCalculationDaysInYearType interestCalculationDaysInYearType, final BigDecimal minRequiredOpeningBalance,
|
||||
final Integer lockinPeriodFrequency, final SavingsPeriodFrequencyType lockinPeriodFrequencyType,
|
||||
final BigDecimal withdrawalFeeAmount, final SavingsWithdrawalFeesType withdrawalFeeType, final BigDecimal annualFeeAmount,
|
||||
@@ -136,7 +147,7 @@ public class SavingsProduct extends AbstractPersistable<Long> {
|
||||
|
||||
private SavingsProduct(final String name, final String description, final MonetaryCurrency currency, final BigDecimal interestRate,
|
||||
final SavingsCompoundingInterestPeriodType interestCompoundingPeriodType,
|
||||
final SavingsInterestPostingPeriodType interestPostingPeriodType, final SavingsInterestCalculationType interestCalculationType,
|
||||
final SavingsPostingInterestPeriodType interestPostingPeriodType, final SavingsInterestCalculationType interestCalculationType,
|
||||
final SavingsInterestCalculationDaysInYearType interestCalculationDaysInYearType, final BigDecimal minRequiredOpeningBalance,
|
||||
final Integer lockinPeriodFrequency, final SavingsPeriodFrequencyType lockinPeriodFrequencyType,
|
||||
final BigDecimal withdrawalFeeAmount, final SavingsWithdrawalFeesType withdrawalFeeType, final BigDecimal annualFeeAmount,
|
||||
@@ -157,16 +168,16 @@ public class SavingsProduct extends AbstractPersistable<Long> {
|
||||
}
|
||||
|
||||
this.lockinPeriodFrequency = lockinPeriodFrequency;
|
||||
if (lockinPeriodFrequencyType != null) {
|
||||
if (lockinPeriodFrequency != null && lockinPeriodFrequencyType != null) {
|
||||
this.lockinPeriodFrequencyType = lockinPeriodFrequencyType.getValue();
|
||||
}
|
||||
|
||||
this.withdrawalFeeAmount = withdrawalFeeAmount;
|
||||
if (withdrawalFeeType != null) {
|
||||
if (withdrawalFeeAmount != null && withdrawalFeeType != null) {
|
||||
this.withdrawalFeeType = withdrawalFeeType.getValue();
|
||||
}
|
||||
this.annualFeeAmount = annualFeeAmount;
|
||||
if (annualFeeOnMonthDay != null) {
|
||||
if (annualFeeAmount != null && annualFeeOnMonthDay != null) {
|
||||
this.annualFeeOnMonth = annualFeeOnMonthDay.getMonthOfYear();
|
||||
this.annualFeeOnDay = annualFeeOnMonthDay.getDayOfMonth();
|
||||
}
|
||||
@@ -192,8 +203,8 @@ public class SavingsProduct extends AbstractPersistable<Long> {
|
||||
return SavingsCompoundingInterestPeriodType.fromInt(this.interestCompoundingPeriodType);
|
||||
}
|
||||
|
||||
public SavingsInterestPostingPeriodType interestPostingPeriodType() {
|
||||
return SavingsInterestPostingPeriodType.fromInt(this.interestPostingPeriodType);
|
||||
public SavingsPostingInterestPeriodType interestPostingPeriodType() {
|
||||
return SavingsPostingInterestPeriodType.fromInt(this.interestPostingPeriodType);
|
||||
}
|
||||
|
||||
public SavingsInterestCalculationType interestCalculationType() {
|
||||
@@ -295,7 +306,7 @@ public class SavingsProduct extends AbstractPersistable<Long> {
|
||||
if (command.isChangeInIntegerParameterNamed(interestPostingPeriodTypeParamName, this.interestPostingPeriodType)) {
|
||||
final Integer newValue = command.integerValueOfParameterNamed(interestPostingPeriodTypeParamName);
|
||||
actualChanges.put(interestPostingPeriodTypeParamName, newValue);
|
||||
this.interestPostingPeriodType = SavingsInterestPostingPeriodType.fromInt(newValue).getValue();
|
||||
this.interestPostingPeriodType = SavingsPostingInterestPeriodType.fromInt(newValue).getValue();
|
||||
}
|
||||
|
||||
if (command.isChangeInIntegerParameterNamed(interestCalculationTypeParamName, this.interestCalculationType)) {
|
||||
@@ -310,15 +321,16 @@ public class SavingsProduct extends AbstractPersistable<Long> {
|
||||
this.interestCalculationDaysInYearType = SavingsInterestCalculationDaysInYearType.fromInt(newValue).getValue();
|
||||
}
|
||||
|
||||
if (command.isChangeInBigDecimalParameterNamed(minRequiredOpeningBalanceParamName, this.minRequiredOpeningBalance)) {
|
||||
final BigDecimal newValue = command.bigDecimalValueOfParameterNamed(minRequiredOpeningBalanceParamName);
|
||||
if (command.isChangeInBigDecimalParameterNamedDefaultingZeroToNull(minRequiredOpeningBalanceParamName,
|
||||
this.minRequiredOpeningBalance)) {
|
||||
final BigDecimal newValue = command.bigDecimalValueOfParameterNamedDefaultToNullIfZero(minRequiredOpeningBalanceParamName);
|
||||
actualChanges.put(minRequiredOpeningBalanceParamName, newValue);
|
||||
actualChanges.put(localeParamName, localeAsInput);
|
||||
this.minRequiredOpeningBalance = newValue;
|
||||
}
|
||||
|
||||
if (command.isChangeInIntegerParameterNamed(lockinPeriodFrequencyParamName, this.lockinPeriodFrequency)) {
|
||||
final Integer newValue = command.integerValueOfParameterNamed(lockinPeriodFrequencyParamName);
|
||||
if (command.isChangeInIntegerParameterNamedDefaultingZeroToNull(lockinPeriodFrequencyParamName, this.lockinPeriodFrequency)) {
|
||||
final Integer newValue = command.integerValueOfParameterNamedDefaultToNullIfZero(lockinPeriodFrequencyParamName);
|
||||
actualChanges.put(lockinPeriodFrequencyParamName, newValue);
|
||||
actualChanges.put(localeParamName, localeAsInput);
|
||||
this.lockinPeriodFrequency = newValue;
|
||||
@@ -327,47 +339,63 @@ public class SavingsProduct extends AbstractPersistable<Long> {
|
||||
if (command.isChangeInIntegerParameterNamed(lockinPeriodFrequencyTypeParamName, this.lockinPeriodFrequencyType)) {
|
||||
final Integer newValue = command.integerValueOfParameterNamed(lockinPeriodFrequencyTypeParamName);
|
||||
actualChanges.put(lockinPeriodFrequencyTypeParamName, newValue);
|
||||
this.lockinPeriodFrequencyType = SavingsPeriodFrequencyType.fromInt(newValue).getValue();
|
||||
this.lockinPeriodFrequencyType = newValue != null ? SavingsPeriodFrequencyType.fromInt(newValue).getValue() : newValue;
|
||||
}
|
||||
|
||||
if (command.isChangeInBigDecimalParameterNamed(withdrawalFeeAmountParamName, this.withdrawalFeeAmount)) {
|
||||
final BigDecimal newValue = command.bigDecimalValueOfParameterNamed(withdrawalFeeAmountParamName);
|
||||
// set period type to null if frequency is null
|
||||
if (this.lockinPeriodFrequency == null) {
|
||||
this.lockinPeriodFrequencyType = null;
|
||||
}
|
||||
|
||||
if (command.isChangeInBigDecimalParameterNamedDefaultingZeroToNull(withdrawalFeeAmountParamName, this.withdrawalFeeAmount)) {
|
||||
final BigDecimal newValue = command.bigDecimalValueOfParameterNamedDefaultToNullIfZero(withdrawalFeeAmountParamName);
|
||||
actualChanges.put(withdrawalFeeAmountParamName, newValue);
|
||||
actualChanges.put(localeParamName, localeAsInput);
|
||||
this.withdrawalFeeAmount = newValue;
|
||||
}
|
||||
|
||||
if (command.isChangeInIntegerParameterNamed(withdrawalFeeTypeParamName, this.withdrawalFeeType)) {
|
||||
final Integer newValue = command.integerValueOfParameterNamed(withdrawalFeeTypeParamName);
|
||||
if (command.isChangeInIntegerParameterNamedDefaultingZeroToNull(withdrawalFeeTypeParamName, this.withdrawalFeeType)) {
|
||||
final Integer newValue = command.integerValueOfParameterNamedDefaultToNullIfZero(withdrawalFeeTypeParamName);
|
||||
actualChanges.put(withdrawalFeeTypeParamName, newValue);
|
||||
this.withdrawalFeeType = newValue != null? SavingsWithdrawalFeesType.fromInt(newValue).getValue(): newValue;
|
||||
this.withdrawalFeeType = newValue != null ? SavingsWithdrawalFeesType.fromInt(newValue).getValue() : newValue;
|
||||
}
|
||||
|
||||
if (command.isChangeInBigDecimalParameterNamed(annualFeeAmountParamName, this.annualFeeAmount)) {
|
||||
final BigDecimal newValue = command.bigDecimalValueOfParameterNamed(annualFeeAmountParamName);
|
||||
// set period type to null if frequency is null
|
||||
if (this.withdrawalFeeAmount == null) {
|
||||
this.withdrawalFeeType = null;
|
||||
}
|
||||
|
||||
if (command.isChangeInBigDecimalParameterNamedDefaultingZeroToNull(annualFeeAmountParamName, this.annualFeeAmount)) {
|
||||
final BigDecimal newValue = command.bigDecimalValueOfParameterNamedDefaultToNullIfZero(annualFeeAmountParamName);
|
||||
actualChanges.put(annualFeeAmountParamName, newValue);
|
||||
actualChanges.put(localeParamName, localeAsInput);
|
||||
this.annualFeeAmount = newValue;
|
||||
}
|
||||
|
||||
if (command.isChangeInIntegerParameterNamed(annualFeeOnMonthDayParamName, this.annualFeeOnDay)) {
|
||||
if (command.isChangeInIntegerParameterNamedDefaultingZeroToNull(annualFeeOnMonthDayParamName, this.annualFeeOnDay)) {
|
||||
final MonthDay monthDay = command.extractMonthDayNamed(annualFeeOnMonthDayParamName);
|
||||
final String actualValueEntered = command.stringValueOfParameterNamed(annualFeeOnMonthDayParamName);
|
||||
final Integer newValue = monthDay != null? monthDay.getDayOfMonth(): null;
|
||||
final Integer newValue = monthDay != null ? monthDay.getDayOfMonth() : null;
|
||||
actualChanges.put(annualFeeOnMonthDayParamName, actualValueEntered);
|
||||
actualChanges.put(localeParamName, localeAsInput);
|
||||
this.annualFeeOnDay = newValue;
|
||||
}
|
||||
|
||||
if (command.isChangeInIntegerParameterNamed(annualFeeOnMonthDayParamName, this.annualFeeOnMonth)) {
|
||||
if (command.isChangeInIntegerParameterNamedDefaultingZeroToNull(annualFeeOnMonthDayParamName, this.annualFeeOnMonth)) {
|
||||
final MonthDay monthDay = command.extractMonthDayNamed(annualFeeOnMonthDayParamName);
|
||||
final String actualValueEntered = command.stringValueOfParameterNamed(annualFeeOnMonthDayParamName);
|
||||
final Integer newValue = monthDay != null? monthDay.getMonthOfYear(): null;
|
||||
final Integer newValue = monthDay != null ? monthDay.getMonthOfYear() : null;
|
||||
actualChanges.put(annualFeeOnMonthDayParamName, actualValueEntered);
|
||||
actualChanges.put(localeParamName, localeAsInput);
|
||||
this.annualFeeOnMonth = newValue;
|
||||
}
|
||||
|
||||
// set period type to null if frequency is null
|
||||
if (this.annualFeeAmount == null) {
|
||||
this.annualFeeOnDay = null;
|
||||
this.annualFeeOnMonth = null;
|
||||
}
|
||||
|
||||
if (command.isChangeInIntegerParameterNamed(accountingRuleParamName, this.accountingRule)) {
|
||||
final Integer newValue = command.integerValueOfParameterNamed(accountingRuleParamName);
|
||||
actualChanges.put(accountingRuleParamName, newValue);
|
||||
@@ -382,42 +410,72 @@ public class SavingsProduct extends AbstractPersistable<Long> {
|
||||
}
|
||||
|
||||
private void validateAnnualFeeDetails() {
|
||||
if (isInvalidConfigurationOfAnnualFeeSettings()) {
|
||||
Object[] defaultUserMessageArgs = new Object[] { annualFeeAmountParamName };
|
||||
throw new GeneralPlatformDomainRuleException("error.msg.product.savings.invalid.annualfee.settings",
|
||||
"Invalid configuration of annual fee settings.", defaultUserMessageArgs);
|
||||
}
|
||||
}
|
||||
|
||||
private boolean isInvalidConfigurationOfAnnualFeeSettings() {
|
||||
return (this.annualFeeAmount == null && (this.annualFeeOnDay != null || this.annualFeeOnMonth != null))
|
||||
|| ((this.annualFeeOnDay == null || this.annualFeeOnMonth == null) && this.annualFeeAmount != null);
|
||||
final List<ApiParameterError> dataValidationErrors = new ArrayList<ApiParameterError>();
|
||||
final DataValidatorBuilder baseDataValidator = new DataValidatorBuilder(dataValidationErrors)
|
||||
.resource(SAVINGS_PRODUCT_RESOURCE_NAME);
|
||||
|
||||
if (this.annualFeeAmount == null) {
|
||||
|
||||
if (this.annualFeeOnMonth != null || this.annualFeeOnDay != null) {
|
||||
baseDataValidator.reset().parameter(annualFeeAmountParamName).value(this.annualFeeAmount).notNull();
|
||||
}
|
||||
} else {
|
||||
|
||||
if (this.annualFeeOnMonth == null || this.annualFeeOnDay == null) {
|
||||
baseDataValidator.reset().parameter(annualFeeOnMonthDayParamName).value(this.annualFeeOnMonth).notNull();
|
||||
}
|
||||
|
||||
baseDataValidator.reset().parameter(annualFeeAmountParamName).value(this.annualFeeAmount).zeroOrPositiveAmount();
|
||||
}
|
||||
|
||||
if (!dataValidationErrors.isEmpty()) { throw new PlatformApiDataValidationException(dataValidationErrors); }
|
||||
}
|
||||
|
||||
private void validateWithdrawalFeeDetails() {
|
||||
if (isInvalidConfigurationOfWithdrawalFeeSettings()) {
|
||||
Object[] defaultUserMessageArgs = new Object[] { withdrawalFeeAmountParamName };
|
||||
throw new GeneralPlatformDomainRuleException("error.msg.product.savings.invalid.withdrawalfee.settings",
|
||||
"Invalid configuration of withdrawal fee settings.", defaultUserMessageArgs);
|
||||
}
|
||||
}
|
||||
|
||||
private boolean isInvalidConfigurationOfWithdrawalFeeSettings() {
|
||||
return (this.withdrawalFeeAmount == null && this.withdrawalFeeType != null)
|
||||
|| (this.withdrawalFeeType == null && this.withdrawalFeeAmount != null);
|
||||
final List<ApiParameterError> dataValidationErrors = new ArrayList<ApiParameterError>();
|
||||
final DataValidatorBuilder baseDataValidator = new DataValidatorBuilder(dataValidationErrors)
|
||||
.resource(SAVINGS_PRODUCT_RESOURCE_NAME);
|
||||
|
||||
if (this.withdrawalFeeAmount == null) {
|
||||
baseDataValidator.reset().parameter(withdrawalFeeTypeParamName).value(this.withdrawalFeeType).ignoreIfNull()
|
||||
.isOneOfTheseValues(1, 2);
|
||||
|
||||
if (this.withdrawalFeeType != null) {
|
||||
baseDataValidator.reset().parameter(withdrawalFeeAmountParamName).value(this.withdrawalFeeAmount).notNull();
|
||||
}
|
||||
} else {
|
||||
baseDataValidator.reset().parameter(withdrawalFeeAmountParamName).value(this.withdrawalFeeAmount).zeroOrPositiveAmount();
|
||||
baseDataValidator.reset().parameter(withdrawalFeeTypeParamName).value(this.withdrawalFeeType).notNull()
|
||||
.isOneOfTheseValues(1, 2);
|
||||
}
|
||||
|
||||
if (!dataValidationErrors.isEmpty()) { throw new PlatformApiDataValidationException(dataValidationErrors); }
|
||||
}
|
||||
|
||||
private void validateLockinDetails() {
|
||||
if (isInvalidConfigurationOfLockinSettings()) {
|
||||
Object[] defaultUserMessageArgs = new Object[] { lockinPeriodFrequencyParamName };
|
||||
throw new GeneralPlatformDomainRuleException("error.msg.product.savings.invalid.lockin.settings",
|
||||
"Invalid configuration of lock in settings.", defaultUserMessageArgs);
|
||||
}
|
||||
}
|
||||
|
||||
private boolean isInvalidConfigurationOfLockinSettings() {
|
||||
return (this.lockinPeriodFrequency == null && this.lockinPeriodFrequencyType != null)
|
||||
|| (this.lockinPeriodFrequencyType == null && this.lockinPeriodFrequency != null);
|
||||
final List<ApiParameterError> dataValidationErrors = new ArrayList<ApiParameterError>();
|
||||
final DataValidatorBuilder baseDataValidator = new DataValidatorBuilder(dataValidationErrors)
|
||||
.resource(SAVINGS_PRODUCT_RESOURCE_NAME);
|
||||
|
||||
if (this.lockinPeriodFrequency == null) {
|
||||
baseDataValidator.reset().parameter(lockinPeriodFrequencyTypeParamName).value(lockinPeriodFrequencyType).ignoreIfNull()
|
||||
.inMinMaxRange(0, 3);
|
||||
|
||||
if (this.lockinPeriodFrequencyType != null) {
|
||||
baseDataValidator.reset().parameter(lockinPeriodFrequencyParamName).value(lockinPeriodFrequency).notNull()
|
||||
.integerZeroOrGreater();
|
||||
}
|
||||
} else {
|
||||
baseDataValidator.reset().parameter(lockinPeriodFrequencyParamName).value(lockinPeriodFrequencyType).integerZeroOrGreater();
|
||||
baseDataValidator.reset().parameter(lockinPeriodFrequencyTypeParamName).value(lockinPeriodFrequencyType).notNull()
|
||||
.inMinMaxRange(0, 3);
|
||||
}
|
||||
|
||||
|
||||
if (!dataValidationErrors.isEmpty()) { throw new PlatformApiDataValidationException(dataValidationErrors); }
|
||||
}
|
||||
|
||||
public boolean isCashBasedAccountingEnabled() {
|
||||
|
||||
+29
-22
@@ -5,22 +5,22 @@
|
||||
*/
|
||||
package org.mifosplatform.portfolio.savings.domain;
|
||||
|
||||
import static org.mifosplatform.portfolio.savings.api.SavingsApiConstants.annualFeeAmountParamName;
|
||||
import static org.mifosplatform.portfolio.savings.api.SavingsApiConstants.annualFeeOnMonthDayParamName;
|
||||
import static org.mifosplatform.portfolio.savings.api.SavingsApiConstants.currencyCodeParamName;
|
||||
import static org.mifosplatform.portfolio.savings.api.SavingsApiConstants.descriptionParamName;
|
||||
import static org.mifosplatform.portfolio.savings.api.SavingsApiConstants.digitsAfterDecimalParamName;
|
||||
import static org.mifosplatform.portfolio.savings.api.SavingsApiConstants.interestCalculationDaysInYearTypeParamName;
|
||||
import static org.mifosplatform.portfolio.savings.api.SavingsApiConstants.interestCalculationTypeParamName;
|
||||
import static org.mifosplatform.portfolio.savings.api.SavingsApiConstants.interestCompoundingPeriodTypeParamName;
|
||||
import static org.mifosplatform.portfolio.savings.api.SavingsApiConstants.interestPostingPeriodTypeParamName;
|
||||
import static org.mifosplatform.portfolio.savings.api.SavingsApiConstants.lockinPeriodFrequencyParamName;
|
||||
import static org.mifosplatform.portfolio.savings.api.SavingsApiConstants.lockinPeriodFrequencyTypeParamName;
|
||||
import static org.mifosplatform.portfolio.savings.api.SavingsApiConstants.minRequiredOpeningBalanceParamName;
|
||||
import static org.mifosplatform.portfolio.savings.api.SavingsApiConstants.nameParamName;
|
||||
import static org.mifosplatform.portfolio.savings.api.SavingsApiConstants.nominalAnnualInterestRateParamName;
|
||||
import static org.mifosplatform.portfolio.savings.api.SavingsApiConstants.withdrawalFeeAmountParamName;
|
||||
import static org.mifosplatform.portfolio.savings.api.SavingsApiConstants.withdrawalFeeTypeParamName;
|
||||
import static org.mifosplatform.portfolio.savings.SavingsApiConstants.annualFeeAmountParamName;
|
||||
import static org.mifosplatform.portfolio.savings.SavingsApiConstants.annualFeeOnMonthDayParamName;
|
||||
import static org.mifosplatform.portfolio.savings.SavingsApiConstants.currencyCodeParamName;
|
||||
import static org.mifosplatform.portfolio.savings.SavingsApiConstants.descriptionParamName;
|
||||
import static org.mifosplatform.portfolio.savings.SavingsApiConstants.digitsAfterDecimalParamName;
|
||||
import static org.mifosplatform.portfolio.savings.SavingsApiConstants.interestCalculationDaysInYearTypeParamName;
|
||||
import static org.mifosplatform.portfolio.savings.SavingsApiConstants.interestCalculationTypeParamName;
|
||||
import static org.mifosplatform.portfolio.savings.SavingsApiConstants.interestCompoundingPeriodTypeParamName;
|
||||
import static org.mifosplatform.portfolio.savings.SavingsApiConstants.interestPostingPeriodTypeParamName;
|
||||
import static org.mifosplatform.portfolio.savings.SavingsApiConstants.lockinPeriodFrequencyParamName;
|
||||
import static org.mifosplatform.portfolio.savings.SavingsApiConstants.lockinPeriodFrequencyTypeParamName;
|
||||
import static org.mifosplatform.portfolio.savings.SavingsApiConstants.minRequiredOpeningBalanceParamName;
|
||||
import static org.mifosplatform.portfolio.savings.SavingsApiConstants.nameParamName;
|
||||
import static org.mifosplatform.portfolio.savings.SavingsApiConstants.nominalAnnualInterestRateParamName;
|
||||
import static org.mifosplatform.portfolio.savings.SavingsApiConstants.withdrawalFeeAmountParamName;
|
||||
import static org.mifosplatform.portfolio.savings.SavingsApiConstants.withdrawalFeeTypeParamName;
|
||||
|
||||
import java.math.BigDecimal;
|
||||
|
||||
@@ -28,6 +28,12 @@ import org.joda.time.MonthDay;
|
||||
import org.mifosplatform.accounting.common.AccountingRuleType;
|
||||
import org.mifosplatform.infrastructure.core.api.JsonCommand;
|
||||
import org.mifosplatform.organisation.monetary.domain.MonetaryCurrency;
|
||||
import org.mifosplatform.portfolio.savings.SavingsCompoundingInterestPeriodType;
|
||||
import org.mifosplatform.portfolio.savings.SavingsInterestCalculationDaysInYearType;
|
||||
import org.mifosplatform.portfolio.savings.SavingsInterestCalculationType;
|
||||
import org.mifosplatform.portfolio.savings.SavingsPeriodFrequencyType;
|
||||
import org.mifosplatform.portfolio.savings.SavingsPostingInterestPeriodType;
|
||||
import org.mifosplatform.portfolio.savings.SavingsWithdrawalFeesType;
|
||||
import org.springframework.stereotype.Component;
|
||||
|
||||
@Component
|
||||
@@ -50,10 +56,10 @@ public class SavingsProductAssembler {
|
||||
interestCompoundingPeriodType = SavingsCompoundingInterestPeriodType.fromInt(interestPeriodTypeValue);
|
||||
}
|
||||
|
||||
SavingsInterestPostingPeriodType interestPostingPeriodType = null;
|
||||
SavingsPostingInterestPeriodType interestPostingPeriodType = null;
|
||||
final Integer interestPostingPeriodTypeValue = command.integerValueOfParameterNamed(interestPostingPeriodTypeParamName);
|
||||
if (interestPostingPeriodTypeValue != null) {
|
||||
interestPostingPeriodType = SavingsInterestPostingPeriodType.fromInt(interestPostingPeriodTypeValue);
|
||||
interestPostingPeriodType = SavingsPostingInterestPeriodType.fromInt(interestPostingPeriodTypeValue);
|
||||
}
|
||||
|
||||
SavingsInterestCalculationType interestCalculationType = null;
|
||||
@@ -69,23 +75,24 @@ public class SavingsProductAssembler {
|
||||
interestCalculationDaysInYearType = SavingsInterestCalculationDaysInYearType.fromInt(interestCalculationDaysInYearTypeValue);
|
||||
}
|
||||
|
||||
final BigDecimal minRequiredOpeningBalance = command.bigDecimalValueOfParameterNamed(minRequiredOpeningBalanceParamName);
|
||||
final BigDecimal minRequiredOpeningBalance = command
|
||||
.bigDecimalValueOfParameterNamedDefaultToNullIfZero(minRequiredOpeningBalanceParamName);
|
||||
|
||||
final Integer lockinPeriodFrequency = command.integerValueOfParameterNamed(lockinPeriodFrequencyParamName);
|
||||
final Integer lockinPeriodFrequency = command.integerValueOfParameterNamedDefaultToNullIfZero(lockinPeriodFrequencyParamName);
|
||||
SavingsPeriodFrequencyType lockinPeriodFrequencyType = null;
|
||||
final Integer lockinPeriodFrequencyTypeValue = command.integerValueOfParameterNamed(lockinPeriodFrequencyTypeParamName);
|
||||
if (lockinPeriodFrequencyTypeValue != null) {
|
||||
lockinPeriodFrequencyType = SavingsPeriodFrequencyType.fromInt(lockinPeriodFrequencyTypeValue);
|
||||
}
|
||||
|
||||
final BigDecimal withdrawalFeeAmount = command.bigDecimalValueOfParameterNamed(withdrawalFeeAmountParamName);
|
||||
final BigDecimal withdrawalFeeAmount = command.bigDecimalValueOfParameterNamedDefaultToNullIfZero(withdrawalFeeAmountParamName);
|
||||
SavingsWithdrawalFeesType withdrawalFeeType = null;
|
||||
final Integer withdrawalFeeTypeValue = command.integerValueOfParameterNamed(withdrawalFeeTypeParamName);
|
||||
if (withdrawalFeeTypeValue != null) {
|
||||
withdrawalFeeType = SavingsWithdrawalFeesType.fromInt(withdrawalFeeTypeValue);
|
||||
}
|
||||
|
||||
final BigDecimal annualFeeAmount = command.bigDecimalValueOfParameterNamed(annualFeeAmountParamName);
|
||||
final BigDecimal annualFeeAmount = command.bigDecimalValueOfParameterNamedDefaultToNullIfZero(annualFeeAmountParamName);
|
||||
final MonthDay monthDayOfAnnualFee = command.extractMonthDayNamed(annualFeeOnMonthDayParamName);
|
||||
final AccountingRuleType accountingRuleType = AccountingRuleType.fromInt(command.integerValueOfParameterNamed("accountingRule"));
|
||||
|
||||
|
||||
+31
@@ -0,0 +1,31 @@
|
||||
package org.mifosplatform.portfolio.savings.domain.interest;
|
||||
|
||||
import java.math.BigDecimal;
|
||||
import java.util.List;
|
||||
|
||||
import org.mifosplatform.organisation.monetary.domain.MonetaryCurrency;
|
||||
import org.mifosplatform.organisation.monetary.domain.Money;
|
||||
|
||||
public class CompoundInterestHelper {
|
||||
|
||||
public Money calculateInterestForAllPostingPeriods(final MonetaryCurrency currency, final List<PostingPeriod> allPeriods) {
|
||||
|
||||
// sum up the 'rounded' values that are posted each posting period
|
||||
Money interestEarned = Money.zero(currency);
|
||||
|
||||
// total interest earned in previous periods but not yet recognised
|
||||
BigDecimal interestEarnedButNotPosted = BigDecimal.ZERO;
|
||||
for (PostingPeriod postingPeriod : allPeriods) {
|
||||
|
||||
final BigDecimal interestEarnedThisPeriod = postingPeriod.calculateInterest(interestEarnedButNotPosted);
|
||||
|
||||
Money moneyToBePostedForPeriod = Money.of(currency, interestEarnedThisPeriod);
|
||||
|
||||
interestEarned = interestEarned.plus(moneyToBePostedForPeriod);
|
||||
|
||||
interestEarnedButNotPosted = interestEarnedButNotPosted.add(moneyToBePostedForPeriod.getAmount());
|
||||
}
|
||||
|
||||
return interestEarned;
|
||||
}
|
||||
}
|
||||
+15
@@ -0,0 +1,15 @@
|
||||
package org.mifosplatform.portfolio.savings.domain.interest;
|
||||
|
||||
import java.math.BigDecimal;
|
||||
|
||||
import org.mifosplatform.portfolio.savings.SavingsCompoundingInterestPeriodType;
|
||||
import org.mifosplatform.portfolio.savings.SavingsInterestCalculationType;
|
||||
|
||||
public interface CompoundingPeriod {
|
||||
|
||||
BigDecimal calculateInterest(BigDecimal interestRateAsFraction, long daysInYear);
|
||||
|
||||
BigDecimal calculateInterest(SavingsCompoundingInterestPeriodType compoundingInterestPeriodType,
|
||||
SavingsInterestCalculationType interestCalculationType, BigDecimal interestFromPreviousPostingPeriod,
|
||||
BigDecimal interestRateAsFraction, long daysInYear);
|
||||
}
|
||||
+90
@@ -0,0 +1,90 @@
|
||||
package org.mifosplatform.portfolio.savings.domain.interest;
|
||||
|
||||
import java.math.BigDecimal;
|
||||
import java.math.MathContext;
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
|
||||
import org.mifosplatform.infrastructure.core.domain.LocalDateInterval;
|
||||
import org.mifosplatform.infrastructure.core.service.DateUtils;
|
||||
import org.mifosplatform.portfolio.savings.SavingsCompoundingInterestPeriodType;
|
||||
import org.mifosplatform.portfolio.savings.SavingsInterestCalculationType;
|
||||
|
||||
public class DailyCompoundingPeriod implements CompoundingPeriod {
|
||||
|
||||
@SuppressWarnings("unused")
|
||||
private final LocalDateInterval periodInterval;
|
||||
private final List<EndOfDayBalance> endOfDayBalances;
|
||||
|
||||
public static DailyCompoundingPeriod create(final LocalDateInterval periodInterval, final List<EndOfDayBalance> allEndOfDayBalances) {
|
||||
|
||||
final List<EndOfDayBalance> endOfDayBalancesWithinPeriod = endOfDayBalancesWithinPeriodInterval(periodInterval, allEndOfDayBalances);
|
||||
|
||||
return new DailyCompoundingPeriod(periodInterval, endOfDayBalancesWithinPeriod);
|
||||
}
|
||||
|
||||
private static List<EndOfDayBalance> endOfDayBalancesWithinPeriodInterval(final LocalDateInterval compoundingPeriodInterval,
|
||||
final List<EndOfDayBalance> allEndOfDayBalances) {
|
||||
|
||||
List<EndOfDayBalance> endOfDayBalancesForPeriodInterval = new ArrayList<EndOfDayBalance>();
|
||||
|
||||
EndOfDayBalance cappedToPeriodEndDate = null;
|
||||
|
||||
for (EndOfDayBalance endOfDayBalance : allEndOfDayBalances) {
|
||||
|
||||
if (compoundingPeriodInterval.contains(endOfDayBalance.date())) {
|
||||
cappedToPeriodEndDate = endOfDayBalance.upTo(compoundingPeriodInterval);
|
||||
} else if (endOfDayBalance.contains(compoundingPeriodInterval)) {
|
||||
cappedToPeriodEndDate = endOfDayBalance.upTo(compoundingPeriodInterval);
|
||||
} else {
|
||||
LocalDateInterval latestPeriod = LocalDateInterval.create(compoundingPeriodInterval.startDate(),
|
||||
DateUtils.getLocalDateOfTenant());
|
||||
cappedToPeriodEndDate = endOfDayBalance.upTo(latestPeriod);
|
||||
}
|
||||
|
||||
if (cappedToPeriodEndDate != null) {
|
||||
endOfDayBalancesForPeriodInterval.add(cappedToPeriodEndDate);
|
||||
}
|
||||
}
|
||||
|
||||
return endOfDayBalancesForPeriodInterval;
|
||||
}
|
||||
|
||||
private DailyCompoundingPeriod(final LocalDateInterval periodInterval, final List<EndOfDayBalance> endOfDayBalances) {
|
||||
this.periodInterval = periodInterval;
|
||||
this.endOfDayBalances = endOfDayBalances;
|
||||
}
|
||||
|
||||
@Override
|
||||
public BigDecimal calculateInterest(final BigDecimal interestRateAsFraction, final long daysInYear) {
|
||||
|
||||
BigDecimal interestEarned = BigDecimal.ZERO;
|
||||
|
||||
for (EndOfDayBalance balance : this.endOfDayBalances) {
|
||||
BigDecimal interestOnBalanceUnrounded = balance.calculateInterestOnBalance(BigDecimal.ZERO, interestRateAsFraction, daysInYear);
|
||||
interestEarned = interestEarned.add(interestOnBalanceUnrounded);
|
||||
}
|
||||
|
||||
return interestEarned;
|
||||
}
|
||||
|
||||
@Override
|
||||
public BigDecimal calculateInterest(
|
||||
@SuppressWarnings("unused") final SavingsCompoundingInterestPeriodType compoundingInterestPeriodType,
|
||||
@SuppressWarnings("unused") final SavingsInterestCalculationType interestCalculationType,
|
||||
final BigDecimal interestFromPreviousPostingPeriod, final BigDecimal interestRateAsFraction, final long daysInYear) {
|
||||
BigDecimal interestEarned = BigDecimal.ZERO;
|
||||
|
||||
// for daily compounding - each interest calculated from previous daily
|
||||
// calculations is 'compounded'
|
||||
BigDecimal interestToCompound = interestFromPreviousPostingPeriod;
|
||||
for (EndOfDayBalance balance : this.endOfDayBalances) {
|
||||
BigDecimal interestOnBalanceUnrounded = balance.calculateInterestOnBalanceAndInterest(interestToCompound,
|
||||
interestRateAsFraction, daysInYear);
|
||||
interestToCompound = interestToCompound.add(interestOnBalanceUnrounded, MathContext.DECIMAL64).setScale(9);
|
||||
interestEarned = interestEarned.add(interestOnBalanceUnrounded);
|
||||
}
|
||||
|
||||
return interestEarned;
|
||||
}
|
||||
}
|
||||
+118
@@ -0,0 +1,118 @@
|
||||
package org.mifosplatform.portfolio.savings.domain.interest;
|
||||
|
||||
import java.math.BigDecimal;
|
||||
import java.math.MathContext;
|
||||
import java.math.RoundingMode;
|
||||
|
||||
import org.joda.time.LocalDate;
|
||||
import org.mifosplatform.infrastructure.core.domain.LocalDateInterval;
|
||||
import org.mifosplatform.infrastructure.core.service.DateUtils;
|
||||
import org.mifosplatform.organisation.monetary.domain.Money;
|
||||
|
||||
public class EndOfDayBalance {
|
||||
|
||||
private final LocalDate date;
|
||||
private final Money openingBalance;
|
||||
private final Money endOfDayBalance;
|
||||
private final int numberOfDays;
|
||||
|
||||
public static EndOfDayBalance from(final LocalDate date, final Money openingBalance, final Money endOfDayBalance, final int numberOfDays) {
|
||||
return new EndOfDayBalance(date, openingBalance, endOfDayBalance, numberOfDays);
|
||||
}
|
||||
|
||||
public EndOfDayBalance(final LocalDate date, final Money openingBalance, final Money endOfDayBalance, final int numberOfDays) {
|
||||
this.date = date;
|
||||
this.openingBalance = openingBalance;
|
||||
this.endOfDayBalance = endOfDayBalance;
|
||||
this.numberOfDays = numberOfDays;
|
||||
}
|
||||
|
||||
public LocalDate date() {
|
||||
return this.date;
|
||||
}
|
||||
|
||||
public Money closingBalance() {
|
||||
return this.endOfDayBalance;
|
||||
}
|
||||
|
||||
public BigDecimal cumulativeBalance(final BigDecimal interestToCompound) {
|
||||
final BigDecimal daysAsBigDecimal = BigDecimal.valueOf(this.numberOfDays);
|
||||
final BigDecimal realBalanceForInterestCalculation = this.endOfDayBalance.getAmount().add(interestToCompound);
|
||||
return realBalanceForInterestCalculation.multiply(daysAsBigDecimal, MathContext.DECIMAL64).setScale(9, RoundingMode.HALF_EVEN);
|
||||
}
|
||||
|
||||
public BigDecimal calculateInterestOnBalance(final BigDecimal interestToCompound, final BigDecimal interestRateAsFraction,
|
||||
final long daysInYear) {
|
||||
|
||||
BigDecimal multiplicand = BigDecimal.ONE.divide(BigDecimal.valueOf(daysInYear), MathContext.DECIMAL64);
|
||||
BigDecimal dailyInterestRate = interestRateAsFraction.multiply(multiplicand, MathContext.DECIMAL64);
|
||||
BigDecimal periodicInterestRate = dailyInterestRate.multiply(BigDecimal.valueOf(this.numberOfDays), MathContext.DECIMAL64);
|
||||
|
||||
BigDecimal realBalanceForInterestCalculation = this.endOfDayBalance.getAmount().add(interestToCompound);
|
||||
|
||||
return realBalanceForInterestCalculation.multiply(periodicInterestRate, MathContext.DECIMAL64).setScale(9, RoundingMode.HALF_EVEN);
|
||||
}
|
||||
|
||||
/**
|
||||
* Future Value (FV) = PV x (1+r)^n
|
||||
*
|
||||
* Interest = FV - PV PV = Principal or the Account Balance r = rate per
|
||||
* compounding period (so for daily, r = nominalInterestRateAsFraction x
|
||||
* 1/365 n = number of periods rate is compounded
|
||||
*/
|
||||
public BigDecimal calculateInterestOnBalanceAndInterest(final BigDecimal interestToCompound, final BigDecimal interestRateAsFraction,
|
||||
final long daysInYear) {
|
||||
BigDecimal multiplicand = BigDecimal.ONE.divide(BigDecimal.valueOf(daysInYear), MathContext.DECIMAL64);
|
||||
|
||||
BigDecimal presentValue = endOfDayBalance.getAmount().add(interestToCompound);
|
||||
|
||||
BigDecimal r = interestRateAsFraction.multiply(multiplicand);
|
||||
|
||||
BigDecimal interestRateForCompoundingPeriodPlusOne = BigDecimal.ONE.add(r);
|
||||
|
||||
double interestRateForCompoundingPeriodPowered = Math.pow(interestRateForCompoundingPeriodPlusOne.doubleValue(),
|
||||
Integer.valueOf(this.numberOfDays).doubleValue());
|
||||
|
||||
BigDecimal futureValue = presentValue.multiply(BigDecimal.valueOf(interestRateForCompoundingPeriodPowered), MathContext.DECIMAL64)
|
||||
.setScale(9, RoundingMode.HALF_EVEN);
|
||||
return futureValue.subtract(presentValue);
|
||||
}
|
||||
|
||||
public EndOfDayBalance upTo(final LocalDateInterval compoundingPeriodInterval) {
|
||||
|
||||
Money startingBalance = openingBalance;
|
||||
LocalDate balanceStartDate = this.date;
|
||||
|
||||
if (this.date.isBefore(compoundingPeriodInterval.startDate())) {
|
||||
balanceStartDate = compoundingPeriodInterval.startDate();
|
||||
startingBalance = endOfDayBalance;
|
||||
}
|
||||
|
||||
int daysOfBalance = this.numberOfDays;
|
||||
LocalDate balanceEndDate = balanceStartDate.plusDays(this.numberOfDays);
|
||||
if (balanceEndDate.isAfter(compoundingPeriodInterval.endDate())) {
|
||||
balanceEndDate = compoundingPeriodInterval.endDate();
|
||||
LocalDateInterval balancePeriodInterval = LocalDateInterval.create(balanceStartDate, balanceEndDate);
|
||||
daysOfBalance = balancePeriodInterval.daysInPeriodInclusiveOfEndDate();
|
||||
}
|
||||
if (balanceEndDate.isAfter(DateUtils.getLocalDateOfTenant())) {
|
||||
balanceEndDate = DateUtils.getLocalDateOfTenant();
|
||||
LocalDateInterval balancePeriodInterval = LocalDateInterval.create(balanceStartDate, balanceEndDate);
|
||||
daysOfBalance = balancePeriodInterval.daysInPeriodInclusiveOfEndDate();
|
||||
}
|
||||
|
||||
return new EndOfDayBalance(balanceStartDate, startingBalance, this.endOfDayBalance, daysOfBalance);
|
||||
}
|
||||
|
||||
public boolean contains(final LocalDateInterval compoundingPeriodInterval) {
|
||||
|
||||
final LocalDate balanceUpToDate = this.date.plusDays(this.numberOfDays);
|
||||
|
||||
final LocalDateInterval balanceInterval = LocalDateInterval.create(this.date, balanceUpToDate);
|
||||
return balanceInterval.containsPortionOf(compoundingPeriodInterval);
|
||||
}
|
||||
|
||||
public Integer getNumberOfDays() {
|
||||
return Integer.valueOf(this.numberOfDays);
|
||||
}
|
||||
}
|
||||
+149
@@ -0,0 +1,149 @@
|
||||
package org.mifosplatform.portfolio.savings.domain.interest;
|
||||
|
||||
import java.math.BigDecimal;
|
||||
import java.math.MathContext;
|
||||
import java.math.RoundingMode;
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
|
||||
import org.mifosplatform.infrastructure.core.domain.LocalDateInterval;
|
||||
import org.mifosplatform.portfolio.savings.SavingsCompoundingInterestPeriodType;
|
||||
import org.mifosplatform.portfolio.savings.SavingsInterestCalculationType;
|
||||
|
||||
public class MonthlyCompoundingPeriod implements CompoundingPeriod {
|
||||
|
||||
@SuppressWarnings("unused")
|
||||
private final LocalDateInterval periodInterval;
|
||||
private final List<EndOfDayBalance> endOfDayBalances;
|
||||
|
||||
public static MonthlyCompoundingPeriod create(final LocalDateInterval periodInterval, final List<EndOfDayBalance> allEndOfDayBalances) {
|
||||
|
||||
final List<EndOfDayBalance> endOfDayBalancesWithinPeriod = endOfDayBalancesWithinPeriodInterval(periodInterval, allEndOfDayBalances);
|
||||
|
||||
return new MonthlyCompoundingPeriod(periodInterval, endOfDayBalancesWithinPeriod);
|
||||
}
|
||||
|
||||
@Override
|
||||
public BigDecimal calculateInterest(final BigDecimal interestRateAsFraction, final long daysInYear) {
|
||||
|
||||
BigDecimal interestEarned = BigDecimal.ZERO;
|
||||
|
||||
for (EndOfDayBalance balance : endOfDayBalances) {
|
||||
BigDecimal interestOnBalanceUnrounded = balance.calculateInterestOnBalance(BigDecimal.ZERO, interestRateAsFraction, daysInYear);
|
||||
interestEarned = interestEarned.add(interestOnBalanceUnrounded);
|
||||
}
|
||||
|
||||
return interestEarned;
|
||||
}
|
||||
|
||||
@Override
|
||||
public BigDecimal calculateInterest(final SavingsCompoundingInterestPeriodType compoundingInterestPeriodType,
|
||||
final SavingsInterestCalculationType interestCalculationType, final BigDecimal interestToCompound,
|
||||
final BigDecimal interestRateAsFraction, final long daysInYear) {
|
||||
|
||||
BigDecimal interestEarned = BigDecimal.ZERO;
|
||||
|
||||
switch (interestCalculationType) {
|
||||
case DAILY_BALANCE:
|
||||
interestEarned = calculateUsingDailyBalanceMethod(compoundingInterestPeriodType, interestToCompound,
|
||||
interestRateAsFraction, daysInYear);
|
||||
break;
|
||||
case AVERAGE_DAILY_BALANCE:
|
||||
interestEarned = calculateUsingAverageDailyBalanceMethod(interestToCompound, interestRateAsFraction, daysInYear);
|
||||
break;
|
||||
case INVALID:
|
||||
break;
|
||||
}
|
||||
|
||||
return interestEarned;
|
||||
}
|
||||
|
||||
private BigDecimal calculateUsingAverageDailyBalanceMethod(final BigDecimal interestToCompound,
|
||||
final BigDecimal interestRateAsFraction, final long daysInYear) {
|
||||
|
||||
BigDecimal cumulativeBalance = BigDecimal.ZERO;
|
||||
Integer numberOfDays = Integer.valueOf(0);
|
||||
|
||||
for (EndOfDayBalance balance : endOfDayBalances) {
|
||||
BigDecimal endOfDayCumulativeBalance = balance.cumulativeBalance(interestToCompound);
|
||||
cumulativeBalance = cumulativeBalance.add(endOfDayCumulativeBalance);
|
||||
|
||||
Integer balanceExistsForNumberOfDays = balance.getNumberOfDays();
|
||||
numberOfDays = numberOfDays + balanceExistsForNumberOfDays;
|
||||
}
|
||||
|
||||
BigDecimal interestEarned = BigDecimal.ZERO;
|
||||
if (cumulativeBalance.compareTo(BigDecimal.ZERO) != 0 && numberOfDays > 0) {
|
||||
BigDecimal averageDailyBalance = cumulativeBalance.divide(BigDecimal.valueOf(numberOfDays), MathContext.DECIMAL64).setScale(9,
|
||||
RoundingMode.HALF_EVEN);
|
||||
|
||||
BigDecimal multiplicand = BigDecimal.ONE.divide(BigDecimal.valueOf(daysInYear), MathContext.DECIMAL64);
|
||||
BigDecimal dailyInterestRate = interestRateAsFraction.multiply(multiplicand, MathContext.DECIMAL64);
|
||||
BigDecimal periodicInterestRate = dailyInterestRate.multiply(BigDecimal.valueOf(numberOfDays), MathContext.DECIMAL64);
|
||||
|
||||
interestEarned = averageDailyBalance.multiply(periodicInterestRate, MathContext.DECIMAL64).setScale(9, RoundingMode.HALF_EVEN);
|
||||
}
|
||||
|
||||
return interestEarned;
|
||||
}
|
||||
|
||||
private BigDecimal calculateUsingDailyBalanceMethod(final SavingsCompoundingInterestPeriodType compoundingInterestPeriodType,
|
||||
final BigDecimal interestToCompound, final BigDecimal interestRateAsFraction, final long daysInYear) {
|
||||
|
||||
BigDecimal interestEarned = BigDecimal.ZERO;
|
||||
BigDecimal interestOnBalanceUnrounded = BigDecimal.ZERO;
|
||||
for (EndOfDayBalance balance : endOfDayBalances) {
|
||||
|
||||
switch (compoundingInterestPeriodType) {
|
||||
case DAILY:
|
||||
interestOnBalanceUnrounded = balance.calculateInterestOnBalanceAndInterest(interestToCompound, interestRateAsFraction,
|
||||
daysInYear);
|
||||
break;
|
||||
case MONTHLY:
|
||||
interestOnBalanceUnrounded = balance.calculateInterestOnBalance(interestToCompound, interestRateAsFraction, daysInYear);
|
||||
break;
|
||||
// case QUATERLY:
|
||||
// break;
|
||||
// case WEEKLY:
|
||||
// break;
|
||||
// case BIWEEKLY:
|
||||
// break;
|
||||
// case BI_ANNUAL:
|
||||
// break;
|
||||
// case ANNUAL:
|
||||
// break;
|
||||
// case NO_COMPOUNDING_SIMPLE_INTEREST:
|
||||
// break;
|
||||
case INVALID:
|
||||
break;
|
||||
}
|
||||
|
||||
interestEarned = interestEarned.add(interestOnBalanceUnrounded);
|
||||
}
|
||||
return interestEarned;
|
||||
}
|
||||
|
||||
private static List<EndOfDayBalance> endOfDayBalancesWithinPeriodInterval(final LocalDateInterval compoundingPeriodInterval,
|
||||
final List<EndOfDayBalance> allEndOfDayBalances) {
|
||||
|
||||
List<EndOfDayBalance> endOfDayBalancesForPeriodInterval = new ArrayList<EndOfDayBalance>();
|
||||
|
||||
for (EndOfDayBalance endOfDayBalance : allEndOfDayBalances) {
|
||||
|
||||
if (compoundingPeriodInterval.contains(endOfDayBalance.date())) {
|
||||
final EndOfDayBalance cappedToPeriodEndDate = endOfDayBalance.upTo(compoundingPeriodInterval);
|
||||
endOfDayBalancesForPeriodInterval.add(cappedToPeriodEndDate);
|
||||
} else if (endOfDayBalance.contains(compoundingPeriodInterval)) {
|
||||
final EndOfDayBalance cappedToPeriodEndDate = endOfDayBalance.upTo(compoundingPeriodInterval);
|
||||
endOfDayBalancesForPeriodInterval.add(cappedToPeriodEndDate);
|
||||
}
|
||||
}
|
||||
|
||||
return endOfDayBalancesForPeriodInterval;
|
||||
}
|
||||
|
||||
private MonthlyCompoundingPeriod(final LocalDateInterval periodInterval, final List<EndOfDayBalance> endOfDayBalances) {
|
||||
this.periodInterval = periodInterval;
|
||||
this.endOfDayBalances = endOfDayBalances;
|
||||
}
|
||||
}
|
||||
+248
@@ -0,0 +1,248 @@
|
||||
package org.mifosplatform.portfolio.savings.domain.interest;
|
||||
|
||||
import java.math.BigDecimal;
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
|
||||
import org.joda.time.LocalDate;
|
||||
import org.mifosplatform.infrastructure.core.domain.LocalDateInterval;
|
||||
import org.mifosplatform.infrastructure.core.service.DateUtils;
|
||||
import org.mifosplatform.organisation.monetary.domain.MonetaryCurrency;
|
||||
import org.mifosplatform.organisation.monetary.domain.Money;
|
||||
import org.mifosplatform.portfolio.savings.SavingsCompoundingInterestPeriodType;
|
||||
import org.mifosplatform.portfolio.savings.SavingsInterestCalculationType;
|
||||
import org.mifosplatform.portfolio.savings.domain.SavingsAccountTransaction;
|
||||
|
||||
public class PostingPeriod {
|
||||
|
||||
@SuppressWarnings("unused")
|
||||
private final LocalDateInterval periodInterval;
|
||||
private final MonetaryCurrency currency;
|
||||
private final SavingsCompoundingInterestPeriodType interestCompoundingType;
|
||||
private final BigDecimal interestRateAsFraction;
|
||||
private final long daysInYear;
|
||||
private final List<CompoundingPeriod> compoundingPeriods;
|
||||
|
||||
// interest posting details
|
||||
private final LocalDate dateOfPostingTransaction;
|
||||
private BigDecimal interestEarnedUnrounded;
|
||||
private Money interestEarnedRounded;
|
||||
|
||||
// opening/closing details
|
||||
@SuppressWarnings("unused")
|
||||
private final Money openingBalance;
|
||||
private final Money closingBalance;
|
||||
private final SavingsInterestCalculationType interestCalculationType;
|
||||
|
||||
public static PostingPeriod createFrom(final LocalDateInterval periodInterval, final Money periodStartingBalance,
|
||||
final List<SavingsAccountTransaction> orderedListOfTransactions, final MonetaryCurrency currency,
|
||||
final SavingsCompoundingInterestPeriodType interestCompoundingPeriodType,
|
||||
final SavingsInterestCalculationType interestCalculationType, final BigDecimal interestRateAsFraction, final long daysInYear) {
|
||||
|
||||
List<EndOfDayBalance> accountEndOfDayBalances = new ArrayList<EndOfDayBalance>();
|
||||
|
||||
Money openingDayBalance = periodStartingBalance;
|
||||
Money closeOfDayBalance = openingDayBalance;
|
||||
for (SavingsAccountTransaction transaction : orderedListOfTransactions) {
|
||||
|
||||
if (transaction.fallsWithin(periodInterval)) {
|
||||
// the balance of the transaction falls entirely within this
|
||||
// period so no need to do any cropping/bounding
|
||||
EndOfDayBalance endOfDayBalance = transaction.toEndOfDayBalance(openingDayBalance);
|
||||
accountEndOfDayBalances.add(endOfDayBalance);
|
||||
|
||||
openingDayBalance = endOfDayBalance.closingBalance();
|
||||
} else if (transaction.spansAnyPortionOf(periodInterval)) {
|
||||
EndOfDayBalance endOfDayBalance = transaction.toEndOfDayBalanceBoundedBy(openingDayBalance, periodInterval);
|
||||
accountEndOfDayBalances.add(endOfDayBalance);
|
||||
|
||||
closeOfDayBalance = endOfDayBalance.closingBalance();
|
||||
openingDayBalance = closeOfDayBalance;
|
||||
}
|
||||
}
|
||||
|
||||
if (accountEndOfDayBalances.isEmpty()) {
|
||||
EndOfDayBalance endOfDayBalance = EndOfDayBalance.from(periodInterval.startDate(), openingDayBalance, closeOfDayBalance,
|
||||
periodInterval.daysInPeriodInclusiveOfEndDate());
|
||||
accountEndOfDayBalances.add(endOfDayBalance);
|
||||
|
||||
closeOfDayBalance = endOfDayBalance.closingBalance();
|
||||
openingDayBalance = closeOfDayBalance;
|
||||
}
|
||||
|
||||
final List<CompoundingPeriod> compoundingPeriods = compoundingPeriodsInPostingPeriod(periodInterval, interestCompoundingPeriodType,
|
||||
accountEndOfDayBalances);
|
||||
|
||||
return new PostingPeriod(periodInterval, currency, periodStartingBalance, openingDayBalance, interestCompoundingPeriodType,
|
||||
interestCalculationType, interestRateAsFraction, daysInYear, compoundingPeriods);
|
||||
}
|
||||
|
||||
private PostingPeriod(final LocalDateInterval periodInterval, final MonetaryCurrency currency, final Money openingBalance,
|
||||
final Money closingBalance, final SavingsCompoundingInterestPeriodType interestCompoundingType,
|
||||
final SavingsInterestCalculationType interestCalculationType, final BigDecimal interestRateAsFraction, final long daysInYear,
|
||||
final List<CompoundingPeriod> compoundingPeriods) {
|
||||
this.periodInterval = periodInterval;
|
||||
this.currency = currency;
|
||||
this.openingBalance = openingBalance;
|
||||
this.closingBalance = closingBalance;
|
||||
this.interestCompoundingType = interestCompoundingType;
|
||||
this.interestCalculationType = interestCalculationType;
|
||||
this.interestRateAsFraction = interestRateAsFraction;
|
||||
this.daysInYear = daysInYear;
|
||||
this.compoundingPeriods = compoundingPeriods;
|
||||
|
||||
this.dateOfPostingTransaction = periodInterval.endDate().plusDays(1);
|
||||
}
|
||||
|
||||
public Money interest() {
|
||||
return this.interestEarnedRounded;
|
||||
}
|
||||
|
||||
public LocalDate dateOfPostingTransaction() {
|
||||
return this.dateOfPostingTransaction;
|
||||
}
|
||||
|
||||
public Money closingBalance() {
|
||||
return this.closingBalance;
|
||||
}
|
||||
|
||||
public BigDecimal calculateInterest(final BigDecimal interestFromPreviousPostingPeriod) {
|
||||
BigDecimal interestEarned = BigDecimal.ZERO;
|
||||
|
||||
// for each compounding period accumulate the amount of interest
|
||||
// to be applied to the balanced for interest calculation
|
||||
BigDecimal interestCompounded = interestFromPreviousPostingPeriod;
|
||||
for (CompoundingPeriod compoundingPeriod : this.compoundingPeriods) {
|
||||
|
||||
BigDecimal interestUnrounded = compoundingPeriod.calculateInterest(this.interestCompoundingType, this.interestCalculationType,
|
||||
interestCompounded, this.interestRateAsFraction, this.daysInYear);
|
||||
interestCompounded = interestCompounded.add(interestUnrounded);
|
||||
interestEarned = interestEarned.add(interestUnrounded);
|
||||
}
|
||||
|
||||
this.interestEarnedUnrounded = interestEarned;
|
||||
this.interestEarnedRounded = Money.of(this.currency, this.interestEarnedUnrounded);
|
||||
|
||||
return interestEarned;
|
||||
}
|
||||
|
||||
public Money getInterestEarned() {
|
||||
return this.interestEarnedRounded;
|
||||
}
|
||||
|
||||
private static List<CompoundingPeriod> compoundingPeriodsInPostingPeriod(final LocalDateInterval postingPeriodInterval,
|
||||
final SavingsCompoundingInterestPeriodType interestPeriodType, final List<EndOfDayBalance> allEndOfDayBalances) {
|
||||
|
||||
List<CompoundingPeriod> compoundingPeriods = new ArrayList<CompoundingPeriod>();
|
||||
|
||||
CompoundingPeriod compoundingPeriod = null;
|
||||
switch (interestPeriodType) {
|
||||
case INVALID:
|
||||
break;
|
||||
case DAILY:
|
||||
compoundingPeriod = DailyCompoundingPeriod.create(postingPeriodInterval, allEndOfDayBalances);
|
||||
compoundingPeriods.add(compoundingPeriod);
|
||||
break;
|
||||
case MONTHLY:
|
||||
|
||||
final LocalDate postingPeriodEndDate = postingPeriodInterval.endDate();
|
||||
|
||||
LocalDate periodStartDate = postingPeriodInterval.startDate();
|
||||
LocalDate periodEndDate = periodStartDate;
|
||||
|
||||
while (!periodStartDate.isAfter(postingPeriodEndDate) && !periodEndDate.isAfter(postingPeriodEndDate)) {
|
||||
|
||||
periodEndDate = determineInterestPeriodEndDateFrom(periodStartDate, interestPeriodType);
|
||||
if (periodEndDate.isAfter(postingPeriodEndDate)) {
|
||||
periodEndDate = postingPeriodEndDate;
|
||||
}
|
||||
|
||||
final LocalDateInterval compoundingPeriodInterval = LocalDateInterval.create(periodStartDate, periodEndDate);
|
||||
if (postingPeriodInterval.contains(compoundingPeriodInterval)) {
|
||||
|
||||
compoundingPeriod = MonthlyCompoundingPeriod.create(compoundingPeriodInterval, allEndOfDayBalances);
|
||||
compoundingPeriods.add(compoundingPeriod);
|
||||
}
|
||||
|
||||
// move periodStartDate forward to day after this period
|
||||
periodStartDate = periodEndDate.plusDays(1);
|
||||
}
|
||||
break;
|
||||
// case WEEKLY:
|
||||
// break;
|
||||
// case BIWEEKLY:
|
||||
// break;
|
||||
// case QUATERLY:
|
||||
// break;
|
||||
// case BI_ANNUAL:
|
||||
// break;
|
||||
// case ANNUAL:
|
||||
// break;
|
||||
// case NO_COMPOUNDING_SIMPLE_INTEREST:
|
||||
// break;
|
||||
}
|
||||
|
||||
return compoundingPeriods;
|
||||
}
|
||||
|
||||
private static LocalDate determineInterestPeriodEndDateFrom(final LocalDate periodStartDate,
|
||||
final SavingsCompoundingInterestPeriodType interestPeriodType) {
|
||||
|
||||
LocalDate periodEndDate = DateUtils.getLocalDateOfTenant();
|
||||
|
||||
switch (interestPeriodType) {
|
||||
case INVALID:
|
||||
break;
|
||||
case DAILY:
|
||||
periodEndDate = periodStartDate;
|
||||
break;
|
||||
// case WEEKLY:
|
||||
// periodEndDate = periodStartDate.dayOfWeek().withMaximumValue();
|
||||
// break;
|
||||
// case BIWEEKLY:
|
||||
// final LocalDate closestEndOfWeek =
|
||||
// periodStartDate.dayOfWeek().withMaximumValue();
|
||||
// periodEndDate = closestEndOfWeek.plusWeeks(1);
|
||||
// break;
|
||||
case MONTHLY:
|
||||
// produce period end date on last day of current month
|
||||
periodEndDate = periodStartDate.dayOfMonth().withMaximumValue();
|
||||
break;
|
||||
// case QUATERLY:
|
||||
// // jan 1st to mar 31st, 1st apr to jun 30, jul 1st to sept 30,
|
||||
// // oct 1st to dec 31
|
||||
// int year = periodStartDate.getYearOfEra();
|
||||
// int monthofYear = periodStartDate.getMonthOfYear();
|
||||
// if (monthofYear <= 3) {
|
||||
// periodEndDate = new DateTime().withDate(year, 3, 31).toLocalDate();
|
||||
// } else if (monthofYear <= 6) {
|
||||
// periodEndDate = new DateTime().withDate(year, 6, 30).toLocalDate();
|
||||
// } else if (monthofYear <= 9) {
|
||||
// periodEndDate = new DateTime().withDate(year, 9, 30).toLocalDate();
|
||||
// } else if (monthofYear <= 12) {
|
||||
// periodEndDate = new DateTime().withDate(year, 12, 31).toLocalDate();
|
||||
// }
|
||||
// break;
|
||||
// case BI_ANNUAL:
|
||||
// // jan 1st to 30, jul 1st to dec 31
|
||||
// year = periodStartDate.getYearOfEra();
|
||||
// monthofYear = periodStartDate.getMonthOfYear();
|
||||
// if (monthofYear <= 6) {
|
||||
// periodEndDate = new DateTime().withDate(year, 6, 30).toLocalDate();
|
||||
// } else if (monthofYear <= 12) {
|
||||
// periodEndDate = new DateTime().withDate(year, 12, 31).toLocalDate();
|
||||
// }
|
||||
// break;
|
||||
// case ANNUAL:
|
||||
// periodEndDate = periodStartDate.monthOfYear().withMaximumValue();
|
||||
// periodEndDate = periodEndDate.dayOfMonth().withMaximumValue();
|
||||
// break;
|
||||
// case NO_COMPOUNDING_SIMPLE_INTEREST:
|
||||
// periodEndDate = periodStartDate.monthOfYear().withMaximumValue();
|
||||
// periodEndDate = periodEndDate.dayOfMonth().withMaximumValue();
|
||||
// break;
|
||||
}
|
||||
|
||||
return periodEndDate;
|
||||
}
|
||||
}
|
||||
+5
-3
@@ -15,8 +15,10 @@ import org.mifosplatform.infrastructure.core.exception.AbstractPlatformDomainRul
|
||||
*/
|
||||
public class InsufficientAccountBalanceException extends AbstractPlatformDomainRuleException {
|
||||
|
||||
public InsufficientAccountBalanceException(final String paramName, final BigDecimal accountBalance, final BigDecimal withdrawalFee, final BigDecimal transactionAmount) {
|
||||
super(withdrawalFee != null? "error.msg.savingsaccount.transaction.insufficient.account.balance.withdraw" : "error.msg.savingsaccount.transaction.insufficient.account.balance",
|
||||
"Insufficient account balance.", paramName, accountBalance, withdrawalFee, transactionAmount);
|
||||
public InsufficientAccountBalanceException(final String paramName, final BigDecimal accountBalance, final BigDecimal withdrawalFee,
|
||||
final BigDecimal transactionAmount) {
|
||||
super(withdrawalFee != null ? "error.msg.savingsaccount.transaction.insufficient.account.balance.withdraw"
|
||||
: "error.msg.savingsaccount.transaction.insufficient.account.balance", "Insufficient account balance.", paramName,
|
||||
accountBalance, withdrawalFee, transactionAmount);
|
||||
}
|
||||
}
|
||||
+3
-3
@@ -16,16 +16,16 @@ import org.springframework.transaction.annotation.Transactional;
|
||||
@Service
|
||||
public class ActivateSavingsAccountCommandHandler implements NewCommandSourceHandler {
|
||||
|
||||
private final SavingsAccountWritePlatformService savingAccountWritePlatformService;
|
||||
private final SavingsAccountWritePlatformService writePlatformService;
|
||||
|
||||
@Autowired
|
||||
public ActivateSavingsAccountCommandHandler(final SavingsAccountWritePlatformService savingAccountWritePlatformService) {
|
||||
this.savingAccountWritePlatformService = savingAccountWritePlatformService;
|
||||
this.writePlatformService = savingAccountWritePlatformService;
|
||||
}
|
||||
|
||||
@Transactional
|
||||
@Override
|
||||
public CommandProcessingResult processCommand(final JsonCommand command) {
|
||||
return this.savingAccountWritePlatformService.activate(command.getSavingsId(), command);
|
||||
return this.writePlatformService.activate(command.getSavingsId(), command);
|
||||
}
|
||||
}
|
||||
+5
-4
@@ -16,16 +16,17 @@ import org.springframework.transaction.annotation.Transactional;
|
||||
@Service
|
||||
public class CalculateInterestSavingsAccountCommandHandler implements NewCommandSourceHandler {
|
||||
|
||||
private final SavingsAccountWritePlatformService savingAccountWritePlatformService;
|
||||
private final SavingsAccountWritePlatformService writePlatformService;
|
||||
|
||||
@Autowired
|
||||
public CalculateInterestSavingsAccountCommandHandler(final SavingsAccountWritePlatformService savingAccountWritePlatformService) {
|
||||
this.savingAccountWritePlatformService = savingAccountWritePlatformService;
|
||||
public CalculateInterestSavingsAccountCommandHandler(
|
||||
final SavingsAccountWritePlatformService writePlatformService) {
|
||||
this.writePlatformService = writePlatformService;
|
||||
}
|
||||
|
||||
@Transactional
|
||||
@Override
|
||||
public CommandProcessingResult processCommand(final JsonCommand command) {
|
||||
return this.savingAccountWritePlatformService.calculateInterest(command.getSavingsId(), command);
|
||||
return this.writePlatformService.calculateInterest(command.getSavingsId());
|
||||
}
|
||||
}
|
||||
+4
-4
@@ -16,16 +16,16 @@ import org.springframework.transaction.annotation.Transactional;
|
||||
@Service
|
||||
public class DepositSavingsAccountCommandHandler implements NewCommandSourceHandler {
|
||||
|
||||
private final SavingsAccountWritePlatformService savingAccountWritePlatformService;
|
||||
private final SavingsAccountWritePlatformService writePlatformService;
|
||||
|
||||
@Autowired
|
||||
public DepositSavingsAccountCommandHandler(final SavingsAccountWritePlatformService savingAccountWritePlatformService) {
|
||||
this.savingAccountWritePlatformService = savingAccountWritePlatformService;
|
||||
public DepositSavingsAccountCommandHandler(final SavingsAccountWritePlatformService writePlatformService) {
|
||||
this.writePlatformService = writePlatformService;
|
||||
}
|
||||
|
||||
@Transactional
|
||||
@Override
|
||||
public CommandProcessingResult processCommand(final JsonCommand command) {
|
||||
return this.savingAccountWritePlatformService.deposit(command.getSavingsId(), command);
|
||||
return this.writePlatformService.deposit(command.getSavingsId(), command);
|
||||
}
|
||||
}
|
||||
+4
-4
@@ -16,16 +16,16 @@ import org.springframework.transaction.annotation.Transactional;
|
||||
@Service
|
||||
public class PostInterestSavingsAccountCommandHandler implements NewCommandSourceHandler {
|
||||
|
||||
private final SavingsAccountWritePlatformService savingAccountWritePlatformService;
|
||||
private final SavingsAccountWritePlatformService writePlatformService;
|
||||
|
||||
@Autowired
|
||||
public PostInterestSavingsAccountCommandHandler(final SavingsAccountWritePlatformService savingAccountWritePlatformService) {
|
||||
this.savingAccountWritePlatformService = savingAccountWritePlatformService;
|
||||
public PostInterestSavingsAccountCommandHandler(final SavingsAccountWritePlatformService writePlatformService) {
|
||||
this.writePlatformService = writePlatformService;
|
||||
}
|
||||
|
||||
@Transactional
|
||||
@Override
|
||||
public CommandProcessingResult processCommand(final JsonCommand command) {
|
||||
return this.savingAccountWritePlatformService.postInterest(command.getSavingsId(), command);
|
||||
return this.writePlatformService.postInterest(command.getSavingsId());
|
||||
}
|
||||
}
|
||||
+32
@@ -0,0 +1,32 @@
|
||||
/**
|
||||
* 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.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.SavingsApplicationProcessWritePlatformService;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.stereotype.Service;
|
||||
import org.springframework.transaction.annotation.Transactional;
|
||||
|
||||
@Service
|
||||
public class SavingsAccountApplicationApprovalCommandHandler implements NewCommandSourceHandler {
|
||||
|
||||
private final SavingsApplicationProcessWritePlatformService writePlatformService;
|
||||
|
||||
@Autowired
|
||||
public SavingsAccountApplicationApprovalCommandHandler(final SavingsApplicationProcessWritePlatformService writePlatformService) {
|
||||
this.writePlatformService = writePlatformService;
|
||||
}
|
||||
|
||||
@Transactional
|
||||
@Override
|
||||
public CommandProcessingResult processCommand(final JsonCommand command) {
|
||||
|
||||
return this.writePlatformService.approveApplication(command.entityId(), command);
|
||||
}
|
||||
}
|
||||
+32
@@ -0,0 +1,32 @@
|
||||
/**
|
||||
* 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.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.SavingsApplicationProcessWritePlatformService;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.stereotype.Service;
|
||||
import org.springframework.transaction.annotation.Transactional;
|
||||
|
||||
@Service
|
||||
public class SavingsAccountApplicationApprovalUndoCommandHandler implements NewCommandSourceHandler {
|
||||
|
||||
private final SavingsApplicationProcessWritePlatformService writePlatformService;
|
||||
|
||||
@Autowired
|
||||
public SavingsAccountApplicationApprovalUndoCommandHandler(final SavingsApplicationProcessWritePlatformService writePlatformService) {
|
||||
this.writePlatformService = writePlatformService;
|
||||
}
|
||||
|
||||
@Transactional
|
||||
@Override
|
||||
public CommandProcessingResult processCommand(final JsonCommand command) {
|
||||
|
||||
return this.writePlatformService.undoApplicationApproval(command.entityId(), command);
|
||||
}
|
||||
}
|
||||
+5
-5
@@ -8,25 +8,25 @@ 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.mifosplatform.portfolio.savings.service.SavingsApplicationProcessWritePlatformService;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.stereotype.Service;
|
||||
import org.springframework.transaction.annotation.Transactional;
|
||||
|
||||
@Service
|
||||
public class DeleteSavingsAccountCommandHandler implements NewCommandSourceHandler {
|
||||
public class SavingsAccountApplicationDeletionCommandHandler implements NewCommandSourceHandler {
|
||||
|
||||
private final SavingsAccountWritePlatformService savingAccountWritePlatformService;
|
||||
private final SavingsApplicationProcessWritePlatformService savingAccountWritePlatformService;
|
||||
|
||||
@Autowired
|
||||
public DeleteSavingsAccountCommandHandler(final SavingsAccountWritePlatformService savingAccountWritePlatformService) {
|
||||
public SavingsAccountApplicationDeletionCommandHandler(final SavingsApplicationProcessWritePlatformService savingAccountWritePlatformService) {
|
||||
this.savingAccountWritePlatformService = savingAccountWritePlatformService;
|
||||
}
|
||||
|
||||
@Transactional
|
||||
@Override
|
||||
public CommandProcessingResult processCommand(final JsonCommand command) {
|
||||
return this.savingAccountWritePlatformService.deleteSavingAccount(command.entityId());
|
||||
return this.savingAccountWritePlatformService.deleteApplication(command.entityId());
|
||||
}
|
||||
|
||||
}
|
||||
+6
-7
@@ -8,25 +8,24 @@ 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.mifosplatform.portfolio.savings.service.SavingsApplicationProcessWritePlatformService;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.stereotype.Service;
|
||||
import org.springframework.transaction.annotation.Transactional;
|
||||
|
||||
@Service
|
||||
public class UpdateSavingsAccountCommandHandler implements NewCommandSourceHandler {
|
||||
public class SavingsAccountApplicationModificationCommandHandler implements NewCommandSourceHandler {
|
||||
|
||||
private final SavingsAccountWritePlatformService savingAccountWritePlatformService;
|
||||
private final SavingsApplicationProcessWritePlatformService savingAccountWritePlatformService;
|
||||
|
||||
@Autowired
|
||||
public UpdateSavingsAccountCommandHandler(final SavingsAccountWritePlatformService savingAccountWritePlatformService) {
|
||||
public SavingsAccountApplicationModificationCommandHandler(final SavingsApplicationProcessWritePlatformService savingAccountWritePlatformService) {
|
||||
this.savingAccountWritePlatformService = savingAccountWritePlatformService;
|
||||
}
|
||||
|
||||
@Transactional
|
||||
@Override
|
||||
public CommandProcessingResult processCommand(final JsonCommand command) {
|
||||
return this.savingAccountWritePlatformService.updateSavingAccount(command.entityId(), command);
|
||||
return this.savingAccountWritePlatformService.modifyApplication(command.entityId(), command);
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
+32
@@ -0,0 +1,32 @@
|
||||
/**
|
||||
* 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.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.SavingsApplicationProcessWritePlatformService;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.stereotype.Service;
|
||||
import org.springframework.transaction.annotation.Transactional;
|
||||
|
||||
@Service
|
||||
public class SavingsAccountApplicationRejectedCommandHandler implements NewCommandSourceHandler {
|
||||
|
||||
private final SavingsApplicationProcessWritePlatformService writePlatformService;
|
||||
|
||||
@Autowired
|
||||
public SavingsAccountApplicationRejectedCommandHandler(final SavingsApplicationProcessWritePlatformService writePlatformService) {
|
||||
this.writePlatformService = writePlatformService;
|
||||
}
|
||||
|
||||
@Transactional
|
||||
@Override
|
||||
public CommandProcessingResult processCommand(final JsonCommand command) {
|
||||
|
||||
return this.writePlatformService.rejectApplication(command.entityId(), command);
|
||||
}
|
||||
}
|
||||
+5
-5
@@ -8,24 +8,24 @@ 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.mifosplatform.portfolio.savings.service.SavingsApplicationProcessWritePlatformService;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.stereotype.Service;
|
||||
import org.springframework.transaction.annotation.Transactional;
|
||||
|
||||
@Service
|
||||
public class CreateSavingsAccountCommandHandler implements NewCommandSourceHandler {
|
||||
public class SavingsAccountApplicationSubmittalCommandHandler implements NewCommandSourceHandler {
|
||||
|
||||
private final SavingsAccountWritePlatformService savingAccountWritePlatformService;
|
||||
private final SavingsApplicationProcessWritePlatformService savingAccountWritePlatformService;
|
||||
|
||||
@Autowired
|
||||
public CreateSavingsAccountCommandHandler(final SavingsAccountWritePlatformService savingAccountWritePlatformService) {
|
||||
public SavingsAccountApplicationSubmittalCommandHandler(final SavingsApplicationProcessWritePlatformService savingAccountWritePlatformService) {
|
||||
this.savingAccountWritePlatformService = savingAccountWritePlatformService;
|
||||
}
|
||||
|
||||
@Transactional
|
||||
@Override
|
||||
public CommandProcessingResult processCommand(final JsonCommand command) {
|
||||
return this.savingAccountWritePlatformService.createSavingAccount(command);
|
||||
return this.savingAccountWritePlatformService.submitApplication(command);
|
||||
}
|
||||
}
|
||||
+33
@@ -0,0 +1,33 @@
|
||||
/**
|
||||
* 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.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.SavingsApplicationProcessWritePlatformService;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.stereotype.Service;
|
||||
import org.springframework.transaction.annotation.Transactional;
|
||||
|
||||
@Service
|
||||
public class SavingsAccountApplicationWithdrawnByApplicantCommandHandler implements NewCommandSourceHandler {
|
||||
|
||||
private final SavingsApplicationProcessWritePlatformService writePlatformService;
|
||||
|
||||
@Autowired
|
||||
public SavingsAccountApplicationWithdrawnByApplicantCommandHandler(
|
||||
final SavingsApplicationProcessWritePlatformService writePlatformService) {
|
||||
this.writePlatformService = writePlatformService;
|
||||
}
|
||||
|
||||
@Transactional
|
||||
@Override
|
||||
public CommandProcessingResult processCommand(final JsonCommand command) {
|
||||
|
||||
return this.writePlatformService.applicantWithdrawsFromApplication(command.entityId(), command);
|
||||
}
|
||||
}
|
||||
+4
-4
@@ -16,16 +16,16 @@ import org.springframework.transaction.annotation.Transactional;
|
||||
@Service
|
||||
public class WithdrawSavingsAccountCommandHandler implements NewCommandSourceHandler {
|
||||
|
||||
private final SavingsAccountWritePlatformService savingAccountWritePlatformService;
|
||||
private final SavingsAccountWritePlatformService writePlatformService;
|
||||
|
||||
@Autowired
|
||||
public WithdrawSavingsAccountCommandHandler(final SavingsAccountWritePlatformService savingAccountWritePlatformService) {
|
||||
this.savingAccountWritePlatformService = savingAccountWritePlatformService;
|
||||
public WithdrawSavingsAccountCommandHandler(final SavingsAccountWritePlatformService writePlatformService) {
|
||||
this.writePlatformService = writePlatformService;
|
||||
}
|
||||
|
||||
@Transactional
|
||||
@Override
|
||||
public CommandProcessingResult processCommand(final JsonCommand command) {
|
||||
return this.savingAccountWritePlatformService.withdrawal(command.getSavingsId(), command);
|
||||
return this.writePlatformService.withdrawal(command.getSavingsId(), command);
|
||||
}
|
||||
}
|
||||
+129
@@ -0,0 +1,129 @@
|
||||
/**
|
||||
* 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.service;
|
||||
|
||||
import java.lang.reflect.Type;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Arrays;
|
||||
import java.util.HashSet;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.Set;
|
||||
|
||||
import org.apache.commons.lang.StringUtils;
|
||||
import org.joda.time.LocalDate;
|
||||
import org.mifosplatform.infrastructure.core.data.ApiParameterError;
|
||||
import org.mifosplatform.infrastructure.core.data.DataValidatorBuilder;
|
||||
import org.mifosplatform.infrastructure.core.exception.InvalidJsonException;
|
||||
import org.mifosplatform.infrastructure.core.exception.PlatformApiDataValidationException;
|
||||
import org.mifosplatform.infrastructure.core.serialization.FromJsonHelper;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.stereotype.Component;
|
||||
|
||||
import com.google.gson.JsonElement;
|
||||
import com.google.gson.reflect.TypeToken;
|
||||
|
||||
@Component
|
||||
public final class SavingsAccountApplicationTransitionApiJsonValidator {
|
||||
|
||||
private final FromJsonHelper fromApiJsonHelper;
|
||||
|
||||
@Autowired
|
||||
public SavingsAccountApplicationTransitionApiJsonValidator(final FromJsonHelper fromApiJsonHelper) {
|
||||
this.fromApiJsonHelper = fromApiJsonHelper;
|
||||
}
|
||||
|
||||
private void throwExceptionIfValidationWarningsExist(final List<ApiParameterError> dataValidationErrors) {
|
||||
if (!dataValidationErrors.isEmpty()) { throw new PlatformApiDataValidationException(dataValidationErrors); }
|
||||
}
|
||||
|
||||
public void validateApproval(final String json) {
|
||||
|
||||
if (StringUtils.isBlank(json)) { throw new InvalidJsonException(); }
|
||||
|
||||
final Set<String> disbursementParameters = new HashSet<String>(Arrays.asList("approvedOnDate", "note", "locale", "dateFormat"));
|
||||
|
||||
final Type typeOfMap = new TypeToken<Map<String, Object>>() {}.getType();
|
||||
fromApiJsonHelper.checkForUnsupportedParameters(typeOfMap, json, disbursementParameters);
|
||||
|
||||
final List<ApiParameterError> dataValidationErrors = new ArrayList<ApiParameterError>();
|
||||
final DataValidatorBuilder baseDataValidator = new DataValidatorBuilder(dataValidationErrors).resource("savingsaccountapplication");
|
||||
|
||||
final JsonElement element = fromApiJsonHelper.parse(json);
|
||||
final LocalDate approvedOnDate = fromApiJsonHelper.extractLocalDateNamed("approvedOnDate", element);
|
||||
baseDataValidator.reset().parameter("approvedOnDate").value(approvedOnDate).notNull();
|
||||
|
||||
final String note = fromApiJsonHelper.extractStringNamed("note", element);
|
||||
baseDataValidator.reset().parameter("note").value(note).notExceedingLengthOf(1000);
|
||||
|
||||
throwExceptionIfValidationWarningsExist(dataValidationErrors);
|
||||
}
|
||||
|
||||
public void validateRejection(final String json) {
|
||||
|
||||
if (StringUtils.isBlank(json)) { throw new InvalidJsonException(); }
|
||||
|
||||
final Set<String> disbursementParameters = new HashSet<String>(Arrays.asList("rejectedOnDate", "note", "locale", "dateFormat"));
|
||||
|
||||
final Type typeOfMap = new TypeToken<Map<String, Object>>() {}.getType();
|
||||
fromApiJsonHelper.checkForUnsupportedParameters(typeOfMap, json, disbursementParameters);
|
||||
|
||||
final List<ApiParameterError> dataValidationErrors = new ArrayList<ApiParameterError>();
|
||||
final DataValidatorBuilder baseDataValidator = new DataValidatorBuilder(dataValidationErrors).resource("savingsaccountapplication");
|
||||
|
||||
final JsonElement element = fromApiJsonHelper.parse(json);
|
||||
final LocalDate rejectedOnDate = fromApiJsonHelper.extractLocalDateNamed("rejectedOnDate", element);
|
||||
baseDataValidator.reset().parameter("rejectedOnDate").value(rejectedOnDate).notNull();
|
||||
|
||||
final String note = fromApiJsonHelper.extractStringNamed("note", element);
|
||||
baseDataValidator.reset().parameter("note").value(note).notExceedingLengthOf(1000);
|
||||
|
||||
throwExceptionIfValidationWarningsExist(dataValidationErrors);
|
||||
}
|
||||
|
||||
public void validateApplicantWithdrawal(final String json) {
|
||||
|
||||
if (StringUtils.isBlank(json)) { throw new InvalidJsonException(); }
|
||||
|
||||
final Set<String> disbursementParameters = new HashSet<String>(Arrays.asList("withdrawnOnDate", "note", "locale", "dateFormat"));
|
||||
|
||||
final Type typeOfMap = new TypeToken<Map<String, Object>>() {}.getType();
|
||||
fromApiJsonHelper.checkForUnsupportedParameters(typeOfMap, json, disbursementParameters);
|
||||
|
||||
final List<ApiParameterError> dataValidationErrors = new ArrayList<ApiParameterError>();
|
||||
final DataValidatorBuilder baseDataValidator = new DataValidatorBuilder(dataValidationErrors).resource("savingsaccountapplication");
|
||||
|
||||
final JsonElement element = fromApiJsonHelper.parse(json);
|
||||
final LocalDate withdrawnOnDate = fromApiJsonHelper.extractLocalDateNamed("withdrawnOnDate", element);
|
||||
baseDataValidator.reset().parameter("withdrawnOnDate").value(withdrawnOnDate).notNull();
|
||||
|
||||
final String note = fromApiJsonHelper.extractStringNamed("note", element);
|
||||
baseDataValidator.reset().parameter("note").value(note).notExceedingLengthOf(1000);
|
||||
|
||||
throwExceptionIfValidationWarningsExist(dataValidationErrors);
|
||||
}
|
||||
|
||||
public void validateForUndo(final String json) {
|
||||
if (StringUtils.isBlank(json)) { throw new InvalidJsonException(); }
|
||||
|
||||
final Set<String> undoSupportedParameters = new HashSet<String>(Arrays.asList("note"));
|
||||
final Type typeOfMap = new TypeToken<Map<String, Object>>() {}.getType();
|
||||
fromApiJsonHelper.checkForUnsupportedParameters(typeOfMap, json, undoSupportedParameters);
|
||||
|
||||
final List<ApiParameterError> dataValidationErrors = new ArrayList<ApiParameterError>();
|
||||
final DataValidatorBuilder baseDataValidator = new DataValidatorBuilder(dataValidationErrors)
|
||||
.resource("savingsaccountapplication.undo");
|
||||
final JsonElement element = fromApiJsonHelper.parse(json);
|
||||
|
||||
final String note = "note";
|
||||
if (fromApiJsonHelper.parameterExists(note, element)) {
|
||||
final String noteText = fromApiJsonHelper.extractStringNamed(note, element);
|
||||
baseDataValidator.reset().parameter(note).value(noteText).notExceedingLengthOf(1000);
|
||||
}
|
||||
|
||||
if (!dataValidationErrors.isEmpty()) { throw new PlatformApiDataValidationException(dataValidationErrors); }
|
||||
}
|
||||
}
|
||||
+1
-1
@@ -18,7 +18,7 @@ public interface SavingsAccountReadPlatformService {
|
||||
|
||||
SavingsAccountData retrieveOne(Long savingsId);
|
||||
|
||||
SavingsAccountData retrieveTemplate(Long clientId, Long groupId, Long productId);
|
||||
SavingsAccountData retrieveTemplate(Long clientId, Long groupId, Long productId, boolean staffInSelectedOfficeOnly);
|
||||
|
||||
SavingsAccountTransactionData retrieveDepositTransactionTemplate(Long savingsId);
|
||||
|
||||
|
||||
+151
-38
@@ -8,6 +8,7 @@ package org.mifosplatform.portfolio.savings.service;
|
||||
import java.math.BigDecimal;
|
||||
import java.sql.ResultSet;
|
||||
import java.sql.SQLException;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Arrays;
|
||||
import java.util.Collection;
|
||||
|
||||
@@ -23,23 +24,26 @@ import org.mifosplatform.infrastructure.core.service.PaginationHelper;
|
||||
import org.mifosplatform.infrastructure.core.service.RoutingDataSource;
|
||||
import org.mifosplatform.infrastructure.security.service.PlatformSecurityContext;
|
||||
import org.mifosplatform.organisation.monetary.data.CurrencyData;
|
||||
import org.mifosplatform.organisation.staff.data.StaffData;
|
||||
import org.mifosplatform.organisation.staff.service.StaffReadPlatformService;
|
||||
import org.mifosplatform.portfolio.client.data.ClientData;
|
||||
import org.mifosplatform.portfolio.client.service.ClientReadPlatformService;
|
||||
import org.mifosplatform.portfolio.group.data.GroupGeneralData;
|
||||
import org.mifosplatform.portfolio.group.service.GroupReadPlatformService;
|
||||
import org.mifosplatform.portfolio.group.service.SearchParameters;
|
||||
import org.mifosplatform.portfolio.paymentdetail.data.PaymentDetailData;
|
||||
import org.mifosplatform.portfolio.savings.SavingsCompoundingInterestPeriodType;
|
||||
import org.mifosplatform.portfolio.savings.SavingsInterestCalculationDaysInYearType;
|
||||
import org.mifosplatform.portfolio.savings.SavingsInterestCalculationType;
|
||||
import org.mifosplatform.portfolio.savings.SavingsPeriodFrequencyType;
|
||||
import org.mifosplatform.portfolio.savings.SavingsPostingInterestPeriodType;
|
||||
import org.mifosplatform.portfolio.savings.data.SavingsAccountApplicationTimelineData;
|
||||
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.SavingsAccountTransactionData;
|
||||
import org.mifosplatform.portfolio.savings.data.SavingsAccountTransactionEnumData;
|
||||
import org.mifosplatform.portfolio.savings.data.SavingsProductData;
|
||||
import org.mifosplatform.portfolio.savings.domain.SavingsCompoundingInterestPeriodType;
|
||||
import org.mifosplatform.portfolio.savings.domain.SavingsInterestCalculationDaysInYearType;
|
||||
import org.mifosplatform.portfolio.savings.domain.SavingsInterestCalculationType;
|
||||
import org.mifosplatform.portfolio.savings.domain.SavingsInterestPostingPeriodType;
|
||||
import org.mifosplatform.portfolio.savings.domain.SavingsPeriodFrequencyType;
|
||||
import org.mifosplatform.portfolio.savings.exception.SavingsAccountNotFoundException;
|
||||
import org.mifosplatform.useradministration.domain.AppUser;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
@@ -47,6 +51,7 @@ import org.springframework.dao.EmptyResultDataAccessException;
|
||||
import org.springframework.jdbc.core.JdbcTemplate;
|
||||
import org.springframework.jdbc.core.RowMapper;
|
||||
import org.springframework.stereotype.Service;
|
||||
import org.springframework.util.CollectionUtils;
|
||||
|
||||
@Service
|
||||
public class SavingsAccountReadPlatformServiceImpl implements SavingsAccountReadPlatformService {
|
||||
@@ -56,10 +61,11 @@ public class SavingsAccountReadPlatformServiceImpl implements SavingsAccountRead
|
||||
private final ClientReadPlatformService clientReadPlatformService;
|
||||
private final GroupReadPlatformService groupReadPlatformService;
|
||||
private final SavingsProductReadPlatformService savingsProductReadPlatformService;
|
||||
private final StaffReadPlatformService staffReadPlatformService;
|
||||
private final SavingsDropdownReadPlatformService dropdownReadPlatformService;
|
||||
private final SavingsAccountTransactionTemplateMapper transactionTemplateMapper;
|
||||
private final SavingsAccountTransactionsMapper transactionsMapper;
|
||||
|
||||
|
||||
private final PaginationHelper<SavingsAccountData> paginationHelper = new PaginationHelper<SavingsAccountData>();
|
||||
private final SavingAccountMapper savingAccountMapper = new SavingAccountMapper();
|
||||
|
||||
@@ -67,15 +73,16 @@ public class SavingsAccountReadPlatformServiceImpl implements SavingsAccountRead
|
||||
public SavingsAccountReadPlatformServiceImpl(final PlatformSecurityContext context, final RoutingDataSource dataSource,
|
||||
final ClientReadPlatformService clientReadPlatformService, final GroupReadPlatformService groupReadPlatformService,
|
||||
final SavingsProductReadPlatformService savingProductReadPlatformService,
|
||||
final SavingsDropdownReadPlatformService dropdownReadPlatformService) {
|
||||
final StaffReadPlatformService staffReadPlatformService, final SavingsDropdownReadPlatformService dropdownReadPlatformService) {
|
||||
this.context = context;
|
||||
this.jdbcTemplate = new JdbcTemplate(dataSource);
|
||||
this.clientReadPlatformService = clientReadPlatformService;
|
||||
this.groupReadPlatformService = groupReadPlatformService;
|
||||
this.savingsProductReadPlatformService = savingProductReadPlatformService;
|
||||
this.staffReadPlatformService = staffReadPlatformService;
|
||||
this.dropdownReadPlatformService = dropdownReadPlatformService;
|
||||
transactionTemplateMapper = new SavingsAccountTransactionTemplateMapper();
|
||||
transactionsMapper = new SavingsAccountTransactionsMapper();
|
||||
this.transactionTemplateMapper = new SavingsAccountTransactionTemplateMapper();
|
||||
this.transactionsMapper = new SavingsAccountTransactionsMapper();
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -151,13 +158,40 @@ public class SavingsAccountReadPlatformServiceImpl implements SavingsAccountRead
|
||||
public SavingAccountMapper() {
|
||||
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.status_enum as statusEnum, sa.activation_date as activationDate, ");
|
||||
sqlBuilder.append("c.id as clientId, c.display_name as clientName, ");
|
||||
sqlBuilder.append("g.id as groupId, g.display_name as groupName, ");
|
||||
sqlBuilder.append("sp.id as productId, sp.name as productName, ");
|
||||
sqlBuilder.append("s.id fieldOfficerId, s.display_name as fieldOfficerName, ");
|
||||
sqlBuilder.append("sa.status_enum as statusEnum, ");
|
||||
|
||||
sqlBuilder.append("sa.submittedon_date as submittedOnDate,");
|
||||
sqlBuilder.append("sbu.username as submittedByUsername,");
|
||||
sqlBuilder.append("sbu.firstname as submittedByFirstname, sbu.lastname as submittedByLastname,");
|
||||
|
||||
sqlBuilder.append("sa.rejectedon_date as rejectedOnDate,");
|
||||
sqlBuilder.append("rbu.username as rejectedByUsername,");
|
||||
sqlBuilder.append("rbu.firstname as rejectedByFirstname, rbu.lastname as rejectedByLastname,");
|
||||
|
||||
sqlBuilder.append("sa.withdrawnon_date as withdrawnOnDate,");
|
||||
sqlBuilder.append("wbu.username as withdrawnByUsername,");
|
||||
sqlBuilder.append("wbu.firstname as withdrawnByFirstname, wbu.lastname as withdrawnByLastname,");
|
||||
|
||||
sqlBuilder.append("sa.approvedon_date as approvedOnDate,");
|
||||
sqlBuilder.append("abu.username as approvedByUsername,");
|
||||
sqlBuilder.append("abu.firstname as approvedByFirstname, abu.lastname as approvedByLastname,");
|
||||
|
||||
sqlBuilder.append("sa.activatedon_date as activatedOnDate,");
|
||||
sqlBuilder.append("avbu.username as activatedByUsername,");
|
||||
sqlBuilder.append("avbu.firstname as activatedByFirstname, avbu.lastname as activatedByLastname,");
|
||||
|
||||
sqlBuilder.append("sa.closedon_date as closedOnDate,");
|
||||
sqlBuilder.append("cbu.username as closedByUsername,");
|
||||
sqlBuilder.append("cbu.firstname as closedByFirstname, cbu.lastname as closedByLastname,");
|
||||
|
||||
sqlBuilder.append("sa.currency_code as currencyCode, sa.currency_digits as currencyDigits, ");
|
||||
sqlBuilder.append("curr.name as currencyName, curr.internationalized_name_code as currencyNameCode, ");
|
||||
sqlBuilder.append("curr.display_symbol as currencyDisplaySymbol, ");
|
||||
|
||||
sqlBuilder.append("sa.nominal_annual_interest_rate as nominalAnnualInterestRate, ");
|
||||
sqlBuilder.append("sa.interest_compounding_period_enum as interestCompoundingPeriodType, ");
|
||||
sqlBuilder.append("sa.interest_posting_period_enum as interestPostingPeriodType, ");
|
||||
@@ -180,10 +214,17 @@ public class SavingsAccountReadPlatformServiceImpl implements SavingsAccountRead
|
||||
sqlBuilder.append("sa.total_interest_posted_derived as totalInterestPosted, ");
|
||||
sqlBuilder.append("sa.account_balance_derived as accountBalance ");
|
||||
sqlBuilder.append("from m_savings_account sa ");
|
||||
sqlBuilder.append("left outer join m_client c ON c.id = sa.client_id ");
|
||||
sqlBuilder.append("left outer join m_group g ON g.id = sa.group_id ");
|
||||
sqlBuilder.append("join m_savings_product sp ON sa.product_id = sp.id ");
|
||||
sqlBuilder.append("join m_currency curr on curr.code = sa.currency_code ");
|
||||
sqlBuilder.append("left join m_client c ON c.id = sa.client_id ");
|
||||
sqlBuilder.append("left join m_group g ON g.id = sa.group_id ");
|
||||
sqlBuilder.append("left join m_staff s ON s.id = sa.field_officer_id ");
|
||||
sqlBuilder.append("left join m_appuser sbu on sbu.id = sa.submittedon_userid ");
|
||||
sqlBuilder.append("left join m_appuser rbu on rbu.id = sa.rejectedon_userid ");
|
||||
sqlBuilder.append("left join m_appuser wbu on wbu.id = sa.withdrawnon_userid ");
|
||||
sqlBuilder.append("left join m_appuser abu on abu.id = sa.approvedon_userid ");
|
||||
sqlBuilder.append("left join m_appuser avbu on rbu.id = sa.activatedon_userid ");
|
||||
sqlBuilder.append("left join m_appuser cbu on cbu.id = sa.closedon_userid ");
|
||||
|
||||
this.schemaSql = sqlBuilder.toString();
|
||||
}
|
||||
@@ -199,11 +240,6 @@ public class SavingsAccountReadPlatformServiceImpl implements SavingsAccountRead
|
||||
final String accountNo = rs.getString("accountNo");
|
||||
final String externalId = rs.getString("externalId");
|
||||
|
||||
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 Long clientId = JdbcSupport.getLong(rs, "clientId");
|
||||
@@ -212,6 +248,49 @@ public class SavingsAccountReadPlatformServiceImpl implements SavingsAccountRead
|
||||
final Long productId = rs.getLong("productId");
|
||||
final String productName = rs.getString("productName");
|
||||
|
||||
final Long fieldOfficerId = rs.getLong("fieldOfficerId");
|
||||
final String fieldOfficerName = rs.getString("fieldOfficerName");
|
||||
|
||||
final Integer statusEnum = JdbcSupport.getInteger(rs, "statusEnum");
|
||||
final SavingsAccountStatusEnumData status = SavingsEnumerations.status(statusEnum);
|
||||
|
||||
final LocalDate submittedOnDate = JdbcSupport.getLocalDate(rs, "submittedOnDate");
|
||||
final String submittedByUsername = rs.getString("submittedByUsername");
|
||||
final String submittedByFirstname = rs.getString("submittedByFirstname");
|
||||
final String submittedByLastname = rs.getString("submittedByLastname");
|
||||
|
||||
final LocalDate rejectedOnDate = JdbcSupport.getLocalDate(rs, "rejectedOnDate");
|
||||
final String rejectedByUsername = rs.getString("rejectedByUsername");
|
||||
final String rejectedByFirstname = rs.getString("rejectedByFirstname");
|
||||
final String rejectedByLastname = rs.getString("rejectedByLastname");
|
||||
|
||||
final LocalDate withdrawnOnDate = JdbcSupport.getLocalDate(rs, "withdrawnOnDate");
|
||||
final String withdrawnByUsername = rs.getString("withdrawnByUsername");
|
||||
final String withdrawnByFirstname = rs.getString("withdrawnByFirstname");
|
||||
final String withdrawnByLastname = rs.getString("withdrawnByLastname");
|
||||
|
||||
final LocalDate approvedOnDate = JdbcSupport.getLocalDate(rs, "approvedOnDate");
|
||||
final String approvedByUsername = rs.getString("approvedByUsername");
|
||||
final String approvedByFirstname = rs.getString("approvedByFirstname");
|
||||
final String approvedByLastname = rs.getString("approvedByLastname");
|
||||
|
||||
final LocalDate activatedOnDate = JdbcSupport.getLocalDate(rs, "activatedOnDate");
|
||||
final String activatedByUsername = rs.getString("activatedByUsername");
|
||||
final String activatedByFirstname = rs.getString("activatedByFirstname");
|
||||
final String activatedByLastname = rs.getString("activatedByLastname");
|
||||
|
||||
final LocalDate closedOnDate = JdbcSupport.getLocalDate(rs, "closedOnDate");
|
||||
final String closedByUsername = rs.getString("closedByUsername");
|
||||
final String closedByFirstname = rs.getString("closedByFirstname");
|
||||
final String closedByLastname = rs.getString("closedByLastname");
|
||||
|
||||
final SavingsAccountApplicationTimelineData timeline = new SavingsAccountApplicationTimelineData(submittedOnDate,
|
||||
submittedByUsername, submittedByFirstname, submittedByLastname, rejectedOnDate, rejectedByUsername,
|
||||
rejectedByFirstname, rejectedByLastname, withdrawnOnDate, withdrawnByUsername, withdrawnByFirstname,
|
||||
withdrawnByLastname, approvedOnDate, approvedByUsername, approvedByFirstname, approvedByLastname, activatedOnDate,
|
||||
activatedByUsername, activatedByFirstname, activatedByLastname, closedOnDate, closedByUsername, closedByFirstname,
|
||||
closedByLastname);
|
||||
|
||||
final String currencyCode = rs.getString("currencyCode");
|
||||
final String currencyName = rs.getString("currencyName");
|
||||
final String currencyNameCode = rs.getString("currencyNameCode");
|
||||
@@ -226,7 +305,7 @@ public class SavingsAccountReadPlatformServiceImpl implements SavingsAccountRead
|
||||
.compoundingInterestPeriodType(SavingsCompoundingInterestPeriodType.fromInt(JdbcSupport.getInteger(rs,
|
||||
"interestCompoundingPeriodType")));
|
||||
|
||||
final EnumOptionData interestPostingPeriodType = SavingsEnumerations.interestPostingPeriodType(SavingsInterestPostingPeriodType
|
||||
final EnumOptionData interestPostingPeriodType = SavingsEnumerations.interestPostingPeriodType(SavingsPostingInterestPeriodType
|
||||
.fromInt(JdbcSupport.getInteger(rs, "interestPostingPeriodType")));
|
||||
|
||||
final EnumOptionData interestCalculationType = SavingsEnumerations.interestCalculationType(SavingsInterestCalculationType
|
||||
@@ -277,27 +356,31 @@ public class SavingsAccountReadPlatformServiceImpl implements SavingsAccountRead
|
||||
final SavingsAccountSummaryData summary = new SavingsAccountSummaryData(currency, totalDeposits, totalWithdrawals,
|
||||
totalWithdrawalFees, totalAnnualFees, totalInterestEarned, totalInterestPosted, accountBalance);
|
||||
|
||||
return SavingsAccountData.instance(id, accountNo, externalId, status, activationDate, groupId, groupName, clientId, clientName,
|
||||
productId, productName, currency, nominalAnnualInterestRate, interestCompoundingPeriodType, interestPostingPeriodType,
|
||||
interestCalculationType, interestCalculationDaysInYearType, minRequiredOpeningBalance, lockinPeriodFrequency,
|
||||
lockinPeriodFrequencyType, withdrawalFeeAmount, withdrawalFeeType, annualFeeAmount, annualFeeOnMonthDay,
|
||||
annualFeeNextDueDate, summary);
|
||||
return SavingsAccountData.instance(id, accountNo, externalId, groupId, groupName, clientId, clientName, productId, productName,
|
||||
fieldOfficerId, fieldOfficerName, status, timeline, currency, nominalAnnualInterestRate, interestCompoundingPeriodType,
|
||||
interestPostingPeriodType, interestCalculationType, interestCalculationDaysInYearType, minRequiredOpeningBalance,
|
||||
lockinPeriodFrequency, lockinPeriodFrequencyType, withdrawalFeeAmount, withdrawalFeeType, annualFeeAmount,
|
||||
annualFeeOnMonthDay, annualFeeNextDueDate, summary);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public SavingsAccountData retrieveTemplate(final Long clientId, final Long groupId, final Long productId) {
|
||||
public SavingsAccountData retrieveTemplate(final Long clientId, final Long groupId, final Long productId,
|
||||
final boolean staffInSelectedOfficeOnly) {
|
||||
|
||||
context.authenticatedUser();
|
||||
AppUser loggedInUser = context.authenticatedUser();
|
||||
Long officeId = loggedInUser.getOffice().getId();
|
||||
|
||||
ClientData client = null;
|
||||
if (clientId != null) {
|
||||
client = this.clientReadPlatformService.retrieveOne(clientId);
|
||||
officeId = client.officeId();
|
||||
}
|
||||
|
||||
GroupGeneralData group = null;
|
||||
if (groupId != null) {
|
||||
group = this.groupReadPlatformService.retrieveOne(groupId);
|
||||
officeId = group.officeId();
|
||||
}
|
||||
|
||||
final Collection<SavingsProductData> productOptions = this.savingsProductReadPlatformService.retrieveAllForLookup();
|
||||
@@ -328,9 +411,35 @@ public class SavingsAccountReadPlatformServiceImpl implements SavingsAccountRead
|
||||
|
||||
final Collection<SavingsAccountTransactionData> transactions = null;
|
||||
|
||||
template = SavingsAccountData.withTemplateOptions(template, productOptions, interestCompoundingPeriodTypeOptions,
|
||||
interestPostingPeriodTypeOptions, interestCalculationTypeOptions, interestCalculationDaysInYearTypeOptions,
|
||||
lockinPeriodFrequencyTypeOptions, withdrawalFeeTypeOptions, transactions);
|
||||
Collection<StaffData> fieldOfficerOptions = null;
|
||||
|
||||
if (officeId != null) {
|
||||
|
||||
if (staffInSelectedOfficeOnly) {
|
||||
// only bring back loan officers in selected branch/office
|
||||
Collection<StaffData> fieldOfficersInBranch = this.staffReadPlatformService
|
||||
.retrieveAllLoanOfficersInOfficeById(officeId);
|
||||
|
||||
if (!CollectionUtils.isEmpty(fieldOfficersInBranch)) {
|
||||
fieldOfficerOptions = new ArrayList<StaffData>(fieldOfficersInBranch);
|
||||
}
|
||||
} else {
|
||||
// by default bring back all officers in selected
|
||||
// branch/office as well as officers in office above
|
||||
// this office
|
||||
final boolean restrictToLoanOfficersOnly = true;
|
||||
Collection<StaffData> loanOfficersInHierarchy = this.staffReadPlatformService
|
||||
.retrieveAllStaffInOfficeAndItsParentOfficeHierarchy(officeId, restrictToLoanOfficersOnly);
|
||||
|
||||
if (!CollectionUtils.isEmpty(loanOfficersInHierarchy)) {
|
||||
fieldOfficerOptions = new ArrayList<StaffData>(loanOfficersInHierarchy);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
template = SavingsAccountData.withTemplateOptions(template, productOptions, fieldOfficerOptions,
|
||||
interestCompoundingPeriodTypeOptions, interestPostingPeriodTypeOptions, interestCalculationTypeOptions,
|
||||
interestCalculationDaysInYearTypeOptions, lockinPeriodFrequencyTypeOptions, withdrawalFeeTypeOptions, transactions);
|
||||
} else {
|
||||
|
||||
String clientName = null;
|
||||
@@ -345,6 +454,7 @@ public class SavingsAccountReadPlatformServiceImpl implements SavingsAccountRead
|
||||
|
||||
template = SavingsAccountData.withClientTemplate(clientId, clientName, groupId, groupName);
|
||||
|
||||
final Collection<StaffData> fieldOfficerOptions = null;
|
||||
final Collection<EnumOptionData> interestCompoundingPeriodTypeOptions = null;
|
||||
final Collection<EnumOptionData> interestPostingPeriodTypeOptions = null;
|
||||
final Collection<EnumOptionData> interestCalculationTypeOptions = null;
|
||||
@@ -354,9 +464,9 @@ public class SavingsAccountReadPlatformServiceImpl implements SavingsAccountRead
|
||||
|
||||
final Collection<SavingsAccountTransactionData> transactions = null;
|
||||
|
||||
template = SavingsAccountData.withTemplateOptions(template, productOptions, interestCompoundingPeriodTypeOptions,
|
||||
interestPostingPeriodTypeOptions, interestCalculationTypeOptions, interestCalculationDaysInYearTypeOptions,
|
||||
lockinPeriodFrequencyTypeOptions, withdrawalFeeTypeOptions, transactions);
|
||||
template = SavingsAccountData.withTemplateOptions(template, productOptions, fieldOfficerOptions,
|
||||
interestCompoundingPeriodTypeOptions, interestPostingPeriodTypeOptions, interestCalculationTypeOptions,
|
||||
interestCalculationDaysInYearTypeOptions, lockinPeriodFrequencyTypeOptions, withdrawalFeeTypeOptions, transactions);
|
||||
}
|
||||
|
||||
return template;
|
||||
@@ -553,7 +663,7 @@ public class SavingsAccountReadPlatformServiceImpl implements SavingsAccountRead
|
||||
.compoundingInterestPeriodType(SavingsCompoundingInterestPeriodType.fromInt(JdbcSupport.getInteger(rs,
|
||||
"interestCompoundingPeriodType")));
|
||||
|
||||
final EnumOptionData interestPostingPeriodType = SavingsEnumerations.interestPostingPeriodType(SavingsInterestPostingPeriodType
|
||||
final EnumOptionData interestPostingPeriodType = SavingsEnumerations.interestPostingPeriodType(SavingsPostingInterestPeriodType
|
||||
.fromInt(JdbcSupport.getInteger(rs, "interestPostingPeriodType")));
|
||||
|
||||
EnumOptionData interestCalculationType = SavingsEnumerations.interestCalculationType(SavingsInterestCalculationType
|
||||
@@ -604,16 +714,19 @@ public class SavingsAccountReadPlatformServiceImpl implements SavingsAccountRead
|
||||
groupName = group.getName();
|
||||
}
|
||||
|
||||
final Long fieldOfficerId = null;
|
||||
final String fieldOfficerName = null;
|
||||
final SavingsAccountStatusEnumData status = null;
|
||||
final LocalDate activationDate = null;
|
||||
final LocalDate annualFeeNextDueDate = null;
|
||||
final SavingsAccountSummaryData summary = null;
|
||||
|
||||
return SavingsAccountData.instance(null, null, null, status, activationDate, groupId, groupName, clientId, clientName,
|
||||
productId, productName, currency, nominalAnnualIterestRate, interestCompoundingPeriodType, interestPostingPeriodType,
|
||||
interestCalculationType, interestCalculationDaysInYearType, minRequiredOpeningBalance, lockinPeriodFrequency,
|
||||
lockinPeriodFrequencyType, withdrawalFeeAmount, withdrawalFeeType, annualFeeAmount, annualFeeOnMonthDay,
|
||||
annualFeeNextDueDate, summary);
|
||||
final SavingsAccountApplicationTimelineData timeline = SavingsAccountApplicationTimelineData.templateDefault();
|
||||
|
||||
return SavingsAccountData.instance(null, null, null, groupId, groupName, clientId, clientName, productId, productName,
|
||||
fieldOfficerId, fieldOfficerName, status, timeline, currency, nominalAnnualIterestRate, interestCompoundingPeriodType,
|
||||
interestPostingPeriodType, interestCalculationType, interestCalculationDaysInYearType, minRequiredOpeningBalance,
|
||||
lockinPeriodFrequency, lockinPeriodFrequencyType, withdrawalFeeAmount, withdrawalFeeType, annualFeeAmount,
|
||||
annualFeeOnMonthDay, annualFeeNextDueDate, summary);
|
||||
}
|
||||
}
|
||||
}
|
||||
+3
-9
@@ -10,21 +10,15 @@ import org.mifosplatform.infrastructure.core.data.CommandProcessingResult;
|
||||
|
||||
public interface SavingsAccountWritePlatformService {
|
||||
|
||||
CommandProcessingResult createSavingAccount(JsonCommand command);
|
||||
|
||||
CommandProcessingResult updateSavingAccount(Long accountId, JsonCommand command);
|
||||
|
||||
CommandProcessingResult deleteSavingAccount(Long accountId);
|
||||
|
||||
CommandProcessingResult activate(Long savingsId, JsonCommand command);
|
||||
|
||||
CommandProcessingResult deposit(Long savingsId, JsonCommand command);
|
||||
|
||||
CommandProcessingResult withdrawal(Long savingsId, JsonCommand command);
|
||||
|
||||
|
||||
CommandProcessingResult applyAnnualFee(Long savingsId);
|
||||
|
||||
CommandProcessingResult calculateInterest(Long savingsId, JsonCommand command);
|
||||
CommandProcessingResult calculateInterest(Long savingsId);
|
||||
|
||||
CommandProcessingResult postInterest(Long savingsId, JsonCommand command);
|
||||
CommandProcessingResult postInterest(Long savingsId);
|
||||
}
|
||||
+54
-199
@@ -6,6 +6,8 @@
|
||||
package org.mifosplatform.portfolio.savings.service;
|
||||
|
||||
import java.math.BigDecimal;
|
||||
import java.math.MathContext;
|
||||
import java.math.RoundingMode;
|
||||
import java.util.ArrayList;
|
||||
import java.util.LinkedHashMap;
|
||||
import java.util.List;
|
||||
@@ -19,66 +21,45 @@ import org.mifosplatform.accounting.journalentry.service.JournalEntryWritePlatfo
|
||||
import org.mifosplatform.infrastructure.core.api.JsonCommand;
|
||||
import org.mifosplatform.infrastructure.core.data.CommandProcessingResult;
|
||||
import org.mifosplatform.infrastructure.core.data.CommandProcessingResultBuilder;
|
||||
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.portfolio.client.domain.AccountNumberGenerator;
|
||||
import org.mifosplatform.portfolio.client.domain.AccountNumberGeneratorFactory;
|
||||
import org.mifosplatform.portfolio.client.domain.Client;
|
||||
import org.mifosplatform.portfolio.client.domain.ClientRepositoryWrapper;
|
||||
import org.mifosplatform.portfolio.group.domain.Group;
|
||||
import org.mifosplatform.portfolio.group.domain.GroupRepository;
|
||||
import org.mifosplatform.portfolio.group.exception.GroupNotFoundException;
|
||||
import org.mifosplatform.portfolio.paymentdetail.domain.PaymentDetail;
|
||||
import org.mifosplatform.portfolio.paymentdetail.service.PaymentDetailWritePlatformService;
|
||||
import org.mifosplatform.portfolio.savings.api.SavingsApiConstants;
|
||||
import org.mifosplatform.portfolio.savings.data.SavingsAccountDataValidator;
|
||||
import org.mifosplatform.portfolio.savings.data.SavingsAccountTransactionDataValidator;
|
||||
import org.mifosplatform.portfolio.savings.domain.SavingsAccount;
|
||||
import org.mifosplatform.portfolio.savings.domain.SavingsAccountAssembler;
|
||||
import org.mifosplatform.portfolio.savings.domain.SavingsAccountRepositoryWrapper;
|
||||
import org.mifosplatform.portfolio.savings.domain.SavingsAccountTransaction;
|
||||
import org.mifosplatform.portfolio.savings.domain.SavingsAccountTransactionRepository;
|
||||
import org.mifosplatform.portfolio.savings.domain.SavingsProduct;
|
||||
import org.mifosplatform.portfolio.savings.domain.SavingsProductRepository;
|
||||
import org.mifosplatform.portfolio.savings.exception.SavingsProductNotFoundException;
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
import org.mifosplatform.portfolio.savings.domain.SavingsHelper;
|
||||
import org.mifosplatform.useradministration.domain.AppUser;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.dao.DataAccessException;
|
||||
import org.springframework.stereotype.Service;
|
||||
import org.springframework.transaction.annotation.Transactional;
|
||||
|
||||
@Service
|
||||
public class SavingsAccountWritePlatformServiceJpaRepositoryImpl implements SavingsAccountWritePlatformService {
|
||||
|
||||
private final static Logger logger = LoggerFactory.getLogger(SavingsAccountWritePlatformServiceJpaRepositoryImpl.class);
|
||||
|
||||
private final PlatformSecurityContext context;
|
||||
private final SavingsAccountRepositoryWrapper savingAccountRepository;
|
||||
private final SavingsAccountTransactionRepository savingsAccountTransactionRepository;
|
||||
private final SavingsAccountAssembler savingAccountAssembler;
|
||||
private final SavingsAccountDataValidator savingsAccountDataValidator;
|
||||
private final SavingsAccountTransactionDataValidator savingsAccountTransactionDataValidator;
|
||||
private final AccountNumberGeneratorFactory accountIdentifierGeneratorFactory;
|
||||
private final ClientRepositoryWrapper clientRepository;
|
||||
private final GroupRepository groupRepository;
|
||||
private final SavingsProductRepository savingsProductRepository;
|
||||
private final PaymentDetailWritePlatformService paymentDetailWritePlatformService;
|
||||
private final ApplicationCurrencyRepositoryWrapper applicationCurrencyRepositoryWrapper;
|
||||
private final JournalEntryWritePlatformService journalEntryWritePlatformService;
|
||||
|
||||
private final SavingsHelper savingsHelper = new SavingsHelper();
|
||||
|
||||
@Autowired
|
||||
public SavingsAccountWritePlatformServiceJpaRepositoryImpl(final PlatformSecurityContext context,
|
||||
final SavingsAccountRepositoryWrapper savingAccountRepository,
|
||||
final SavingsAccountTransactionRepository savingsAccountTransactionRepository,
|
||||
final SavingsAccountAssembler savingAccountAssembler, final SavingsAccountDataValidator savingsAccountDataValidator,
|
||||
final SavingsAccountAssembler savingAccountAssembler,
|
||||
final SavingsAccountTransactionDataValidator savingsAccountTransactionDataValidator,
|
||||
final AccountNumberGeneratorFactory accountIdentifierGeneratorFactory, final ClientRepositoryWrapper clientRepository,
|
||||
final GroupRepository groupRepository, final SavingsProductRepository savingsProductRepository,
|
||||
final PaymentDetailWritePlatformService paymentDetailWritePlatformService,
|
||||
final ApplicationCurrencyRepositoryWrapper applicationCurrencyRepositoryWrapper,
|
||||
final JournalEntryWritePlatformService journalEntryWritePlatformService) {
|
||||
@@ -87,184 +68,29 @@ public class SavingsAccountWritePlatformServiceJpaRepositoryImpl implements Savi
|
||||
this.savingsAccountTransactionRepository = savingsAccountTransactionRepository;
|
||||
this.savingAccountAssembler = savingAccountAssembler;
|
||||
this.savingsAccountTransactionDataValidator = savingsAccountTransactionDataValidator;
|
||||
this.accountIdentifierGeneratorFactory = accountIdentifierGeneratorFactory;
|
||||
this.savingsAccountDataValidator = savingsAccountDataValidator;
|
||||
this.clientRepository = clientRepository;
|
||||
this.groupRepository = groupRepository;
|
||||
this.savingsProductRepository = savingsProductRepository;
|
||||
this.paymentDetailWritePlatformService = paymentDetailWritePlatformService;
|
||||
this.applicationCurrencyRepositoryWrapper = applicationCurrencyRepositoryWrapper;
|
||||
this.journalEntryWritePlatformService = journalEntryWritePlatformService;
|
||||
}
|
||||
|
||||
/*
|
||||
* Guaranteed to throw an exception no matter what the data integrity issue
|
||||
* is.
|
||||
*/
|
||||
private void handleDataIntegrityIssues(final JsonCommand command, final DataAccessException dve) {
|
||||
|
||||
final StringBuilder errorCodeBuilder = new StringBuilder("error.msg.").append(SavingsApiConstants.SAVINGS_ACCOUNT_RESOURCE_NAME);
|
||||
|
||||
final Throwable realCause = dve.getMostSpecificCause();
|
||||
if (realCause.getMessage().contains("sa_account_no_UNIQUE")) {
|
||||
final String accountNo = command.stringValueOfParameterNamed("accountNo");
|
||||
errorCodeBuilder.append(".duplicate.accountNo");
|
||||
throw new PlatformDataIntegrityException(errorCodeBuilder.toString(), "Savings account with accountNo " + accountNo
|
||||
+ " already exists", "accountNo", accountNo);
|
||||
|
||||
} else if (realCause.getMessage().contains("sa_external_id_UNIQUE")) {
|
||||
|
||||
final String externalId = command.stringValueOfParameterNamed("externalId");
|
||||
errorCodeBuilder.append(".duplicate.externalId");
|
||||
throw new PlatformDataIntegrityException(errorCodeBuilder.toString(), "Savings account with externalId " + externalId
|
||||
+ " already exists", "externalId", externalId);
|
||||
}
|
||||
|
||||
errorCodeBuilder.append(".unknown.data.integrity.issue");
|
||||
logger.error(dve.getMessage(), dve);
|
||||
throw new PlatformDataIntegrityException(errorCodeBuilder.toString(), "Unknown data integrity issue with savings account.");
|
||||
}
|
||||
|
||||
@Transactional
|
||||
@Override
|
||||
public CommandProcessingResult createSavingAccount(final JsonCommand command) {
|
||||
try {
|
||||
this.context.authenticatedUser();
|
||||
this.savingsAccountDataValidator.validateForCreate(command.json());
|
||||
|
||||
final List<Long> existingTransactionIds = new ArrayList<Long>();
|
||||
final List<Long> existingReversedTransactionIds = new ArrayList<Long>();
|
||||
final SavingsAccount account = this.savingAccountAssembler.assembleFrom(command, existingTransactionIds,
|
||||
existingReversedTransactionIds);
|
||||
this.savingAccountRepository.save(account);
|
||||
|
||||
if (account.isAccountNumberRequiresAutoGeneration()) {
|
||||
final AccountNumberGenerator accountNoGenerator = this.accountIdentifierGeneratorFactory
|
||||
.determineLoanAccountNoGenerator(account.getId());
|
||||
account.updateAccountNo(accountNoGenerator.generate());
|
||||
|
||||
this.savingAccountRepository.save(account);
|
||||
}
|
||||
|
||||
postJournalEntries(account, existingTransactionIds, existingReversedTransactionIds);
|
||||
|
||||
final Long savingsId = account.getId();
|
||||
return new CommandProcessingResultBuilder() //
|
||||
.withCommandId(command.commandId()) //
|
||||
.withEntityId(savingsId) //
|
||||
.withOfficeId(account.officeId()) //
|
||||
.withClientId(account.clientId()) //
|
||||
.withGroupId(account.groupId()) //
|
||||
.withSavingsId(savingsId) //
|
||||
.build();
|
||||
} catch (DataAccessException dve) {
|
||||
handleDataIntegrityIssues(command, dve);
|
||||
return CommandProcessingResult.empty();
|
||||
}
|
||||
}
|
||||
|
||||
@Transactional
|
||||
@Override
|
||||
public CommandProcessingResult updateSavingAccount(final Long savingsId, final JsonCommand command) {
|
||||
try {
|
||||
this.context.authenticatedUser();
|
||||
this.savingsAccountDataValidator.validateForUpdate(command.json());
|
||||
|
||||
final Map<String, Object> changes = new LinkedHashMap<String, Object>(20);
|
||||
|
||||
final SavingsAccount account = this.savingAccountRepository.findOneWithNotFoundDetection(savingsId);
|
||||
|
||||
account.update(command, changes);
|
||||
|
||||
if (!changes.isEmpty()) {
|
||||
|
||||
if (changes.containsKey(SavingsApiConstants.clientIdParamName)) {
|
||||
final Long clientId = command.longValueOfParameterNamed(SavingsApiConstants.clientIdParamName);
|
||||
if (clientId != null) {
|
||||
final Client client = this.clientRepository.findOneWithNotFoundDetection(clientId);
|
||||
account.update(client);
|
||||
} else {
|
||||
final Client client = null;
|
||||
account.update(client);
|
||||
}
|
||||
}
|
||||
|
||||
if (changes.containsKey(SavingsApiConstants.groupIdParamName)) {
|
||||
final Long groupId = command.longValueOfParameterNamed(SavingsApiConstants.groupIdParamName);
|
||||
if (groupId != null) {
|
||||
final Group group = this.groupRepository.findOne(groupId);
|
||||
if (group == null) { throw new GroupNotFoundException(groupId); }
|
||||
account.update(group);
|
||||
} else {
|
||||
final Group group = null;
|
||||
account.update(group);
|
||||
}
|
||||
}
|
||||
|
||||
if (changes.containsKey(SavingsApiConstants.productIdParamName)) {
|
||||
final Long productId = command.longValueOfParameterNamed(SavingsApiConstants.productIdParamName);
|
||||
final SavingsProduct product = this.savingsProductRepository.findOne(productId);
|
||||
if (product == null) { throw new SavingsProductNotFoundException(productId); }
|
||||
|
||||
account.update(product);
|
||||
}
|
||||
|
||||
this.savingAccountRepository.saveAndFlush(account);
|
||||
}
|
||||
|
||||
return new CommandProcessingResultBuilder() //
|
||||
.withCommandId(command.commandId()) //
|
||||
.withEntityId(savingsId) //
|
||||
.withOfficeId(account.officeId()) //
|
||||
.withClientId(account.clientId()) //
|
||||
.withGroupId(account.groupId()) //
|
||||
.withSavingsId(savingsId) //
|
||||
.with(changes) //
|
||||
.build();
|
||||
} catch (DataAccessException dve) {
|
||||
handleDataIntegrityIssues(command, dve);
|
||||
return new CommandProcessingResult(Long.valueOf(-1));
|
||||
}
|
||||
}
|
||||
|
||||
@Transactional
|
||||
@Override
|
||||
public CommandProcessingResult deleteSavingAccount(final Long savingsId) {
|
||||
|
||||
this.context.authenticatedUser();
|
||||
|
||||
final SavingsAccount account = this.savingAccountRepository.findOneWithNotFoundDetection(savingsId);
|
||||
|
||||
this.savingAccountRepository.delete(account);
|
||||
|
||||
return new CommandProcessingResultBuilder() //
|
||||
.withEntityId(savingsId) //
|
||||
.withOfficeId(account.officeId()) //
|
||||
.withClientId(account.clientId()) //
|
||||
.withGroupId(account.groupId()) //
|
||||
.withSavingsId(savingsId) //
|
||||
.build();
|
||||
}
|
||||
|
||||
@Transactional
|
||||
@Override
|
||||
public CommandProcessingResult activate(final Long savingsId, final JsonCommand command) {
|
||||
|
||||
this.context.authenticatedUser();
|
||||
final AppUser user = this.context.authenticatedUser();
|
||||
|
||||
this.savingsAccountTransactionDataValidator.validateActivation(command);
|
||||
|
||||
final SavingsAccount account = this.savingAccountRepository.findOneWithNotFoundDetection(savingsId);
|
||||
final SavingsAccount account = this.savingAccountAssembler.assembleFrom(savingsId);
|
||||
|
||||
final Locale locale = command.extractLocale();
|
||||
final DateTimeFormatter fmt = DateTimeFormat.forPattern(command.dateFormat()).withLocale(locale);
|
||||
final LocalDate activationDate = command.localDateValueOfParameterNamed("activationDate");
|
||||
final List<Long> existingTransactionIds = new ArrayList<Long>();
|
||||
final List<Long> existingReversedTransactionIds = new ArrayList<Long>();
|
||||
|
||||
account.activate(fmt, activationDate, existingReversedTransactionIds, existingReversedTransactionIds);
|
||||
|
||||
this.savingAccountRepository.save(account);
|
||||
final Map<String, Object> changes = account.activate(user, command, DateUtils.getLocalDateOfTenant(),
|
||||
existingReversedTransactionIds, existingReversedTransactionIds);
|
||||
if (!changes.isEmpty()) {
|
||||
this.savingAccountRepository.save(account);
|
||||
}
|
||||
|
||||
postJournalEntries(account, existingTransactionIds, existingReversedTransactionIds);
|
||||
|
||||
@@ -274,6 +100,7 @@ public class SavingsAccountWritePlatformServiceJpaRepositoryImpl implements Savi
|
||||
.withClientId(account.clientId()) //
|
||||
.withGroupId(account.groupId()) //
|
||||
.withSavingsId(savingsId) //
|
||||
.with(changes) //
|
||||
.build();
|
||||
}
|
||||
|
||||
@@ -285,7 +112,7 @@ public class SavingsAccountWritePlatformServiceJpaRepositoryImpl implements Savi
|
||||
|
||||
this.savingsAccountTransactionDataValidator.validate(command);
|
||||
|
||||
final SavingsAccount account = this.savingAccountRepository.findOneWithNotFoundDetection(savingsId);
|
||||
final SavingsAccount account = this.savingAccountAssembler.assembleFrom(savingsId);
|
||||
|
||||
final Locale locale = command.extractLocale();
|
||||
final DateTimeFormatter fmt = DateTimeFormat.forPattern(command.dateFormat()).withLocale(locale);
|
||||
@@ -298,8 +125,18 @@ public class SavingsAccountWritePlatformServiceJpaRepositoryImpl implements Savi
|
||||
final Map<String, Object> changes = new LinkedHashMap<String, Object>();
|
||||
PaymentDetail paymentDetail = paymentDetailWritePlatformService.createAndPersistPaymentDetail(command, changes);
|
||||
|
||||
final MathContext mc = new MathContext(10, RoundingMode.HALF_EVEN);
|
||||
final SavingsAccountTransaction deposit = account.deposit(fmt, transactionDate, transactionAmount, existingTransactionIds,
|
||||
existingReversedTransactionIds, paymentDetail);
|
||||
|
||||
if (account.isBeforeLastPostingPeriod(transactionDate)) {
|
||||
final LocalDate today = DateUtils.getLocalDateOfTenant();
|
||||
account.postInterest(this.savingsHelper, mc, today, existingTransactionIds, existingReversedTransactionIds);
|
||||
} else {
|
||||
final LocalDate today = DateUtils.getLocalDateOfTenant();
|
||||
account.calculateInterestUsing(this.savingsHelper, mc, today);
|
||||
}
|
||||
|
||||
final Long transactionId = saveTransactionToGenerateTransactionId(deposit);
|
||||
|
||||
this.savingAccountRepository.save(account);
|
||||
@@ -329,7 +166,7 @@ public class SavingsAccountWritePlatformServiceJpaRepositoryImpl implements Savi
|
||||
|
||||
this.savingsAccountTransactionDataValidator.validate(command);
|
||||
|
||||
final SavingsAccount account = this.savingAccountRepository.findOneWithNotFoundDetection(savingsId);
|
||||
final SavingsAccount account = this.savingAccountAssembler.assembleFrom(savingsId);
|
||||
|
||||
final LocalDate transactionDate = command.localDateValueOfParameterNamed("transactionDate");
|
||||
final BigDecimal transactionAmount = command.bigDecimalValueOfParameterNamed("transactionAmount");
|
||||
@@ -342,8 +179,18 @@ public class SavingsAccountWritePlatformServiceJpaRepositoryImpl implements Savi
|
||||
final Map<String, Object> changes = new LinkedHashMap<String, Object>();
|
||||
PaymentDetail paymentDetail = paymentDetailWritePlatformService.createAndPersistPaymentDetail(command, changes);
|
||||
|
||||
final MathContext mc = new MathContext(10, RoundingMode.HALF_EVEN);
|
||||
final SavingsAccountTransaction withdrawal = account.withdraw(fmt, transactionDate, transactionAmount, existingTransactionIds,
|
||||
existingReversedTransactionIds, paymentDetail);
|
||||
|
||||
if (account.isBeforeLastPostingPeriod(transactionDate)) {
|
||||
final LocalDate today = DateUtils.getLocalDateOfTenant();
|
||||
account.postInterest(this.savingsHelper, mc, today, existingTransactionIds, existingReversedTransactionIds);
|
||||
} else {
|
||||
final LocalDate today = DateUtils.getLocalDateOfTenant();
|
||||
account.calculateInterestUsing(this.savingsHelper, mc, today);
|
||||
}
|
||||
|
||||
final Long transactionId = saveTransactionToGenerateTransactionId(withdrawal);
|
||||
this.savingAccountRepository.save(account);
|
||||
|
||||
@@ -363,7 +210,7 @@ public class SavingsAccountWritePlatformServiceJpaRepositoryImpl implements Savi
|
||||
@Override
|
||||
public CommandProcessingResult applyAnnualFee(final Long savingsId) {
|
||||
|
||||
final SavingsAccount account = this.savingAccountRepository.findOneWithNotFoundDetection(savingsId);
|
||||
final SavingsAccount account = this.savingAccountAssembler.assembleFrom(savingsId);
|
||||
|
||||
final LocalDate transactionDate = LocalDate.now();
|
||||
|
||||
@@ -372,8 +219,9 @@ public class SavingsAccountWritePlatformServiceJpaRepositoryImpl implements Savi
|
||||
final List<Long> existingTransactionIds = new ArrayList<Long>();
|
||||
final List<Long> existingReversedTransactionIds = new ArrayList<Long>();
|
||||
|
||||
final SavingsAccountTransaction annualFee = account.addAnnualFee(fmt, transactionDate, existingTransactionIds,
|
||||
existingReversedTransactionIds);
|
||||
final MathContext mc = new MathContext(10, RoundingMode.HALF_EVEN);
|
||||
final SavingsAccountTransaction annualFee = account.addAnnualFee(this.savingsHelper, mc, fmt, transactionDate,
|
||||
existingTransactionIds, existingReversedTransactionIds);
|
||||
final Long transactionId = saveTransactionToGenerateTransactionId(annualFee);
|
||||
this.savingAccountRepository.save(account);
|
||||
|
||||
@@ -388,14 +236,19 @@ public class SavingsAccountWritePlatformServiceJpaRepositoryImpl implements Savi
|
||||
.build();
|
||||
}
|
||||
|
||||
@Transactional
|
||||
@Override
|
||||
public CommandProcessingResult calculateInterest(final Long savingsId, final JsonCommand command) {
|
||||
public CommandProcessingResult calculateInterest(final Long savingsId) {
|
||||
this.context.authenticatedUser();
|
||||
|
||||
final SavingsAccount account = this.savingAccountRepository.findOneWithNotFoundDetection(savingsId);
|
||||
final SavingsAccount account = this.savingAccountAssembler.assembleFrom(savingsId);
|
||||
|
||||
final LocalDate today = DateUtils.getLocalDateOfTenant();
|
||||
account.calculateInterest(today);
|
||||
|
||||
final MathContext mc = new MathContext(15, RoundingMode.HALF_EVEN);
|
||||
|
||||
account.calculateInterestUsing(this.savingsHelper, mc, today);
|
||||
|
||||
this.savingAccountRepository.save(account);
|
||||
|
||||
return new CommandProcessingResultBuilder() //
|
||||
@@ -409,15 +262,17 @@ public class SavingsAccountWritePlatformServiceJpaRepositoryImpl implements Savi
|
||||
|
||||
@Transactional
|
||||
@Override
|
||||
public CommandProcessingResult postInterest(final Long savingsId, final JsonCommand command) {
|
||||
public CommandProcessingResult postInterest(final Long savingsId) {
|
||||
this.context.authenticatedUser();
|
||||
final List<Long> existingTransactionIds = new ArrayList<Long>();
|
||||
final List<Long> existingReversedTransactionIds = new ArrayList<Long>();
|
||||
|
||||
final SavingsAccount account = this.savingAccountRepository.findOneWithNotFoundDetection(savingsId);
|
||||
final SavingsAccount account = this.savingAccountAssembler.assembleFrom(savingsId);
|
||||
|
||||
final LocalDate today = DateUtils.getLocalDateOfTenant();
|
||||
account.postInterest(today, existingTransactionIds, existingReversedTransactionIds);
|
||||
final MathContext mc = new MathContext(10, RoundingMode.HALF_EVEN);
|
||||
|
||||
account.postInterest(this.savingsHelper, mc, today, existingTransactionIds, existingReversedTransactionIds);
|
||||
this.savingAccountRepository.save(account);
|
||||
|
||||
postJournalEntries(account, existingTransactionIds, existingReversedTransactionIds);
|
||||
|
||||
+26
@@ -0,0 +1,26 @@
|
||||
/**
|
||||
* 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.service;
|
||||
|
||||
import org.mifosplatform.infrastructure.core.api.JsonCommand;
|
||||
import org.mifosplatform.infrastructure.core.data.CommandProcessingResult;
|
||||
|
||||
public interface SavingsApplicationProcessWritePlatformService {
|
||||
|
||||
CommandProcessingResult submitApplication(JsonCommand command);
|
||||
|
||||
CommandProcessingResult modifyApplication(Long savingsId, JsonCommand command);
|
||||
|
||||
CommandProcessingResult deleteApplication(Long savingsId);
|
||||
|
||||
CommandProcessingResult approveApplication(Long savingsId, JsonCommand command);
|
||||
|
||||
CommandProcessingResult undoApplicationApproval(Long savingsId, JsonCommand command);
|
||||
|
||||
CommandProcessingResult rejectApplication(Long savingsId, JsonCommand command);
|
||||
|
||||
CommandProcessingResult applicantWithdrawsFromApplication(Long savingsId, JsonCommand command);
|
||||
}
|
||||
+382
@@ -0,0 +1,382 @@
|
||||
/**
|
||||
* 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.service;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.LinkedHashMap;
|
||||
import java.util.List;
|
||||
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.CommandProcessingResult;
|
||||
import org.mifosplatform.infrastructure.core.data.CommandProcessingResultBuilder;
|
||||
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.portfolio.client.domain.AccountNumberGenerator;
|
||||
import org.mifosplatform.portfolio.client.domain.AccountNumberGeneratorFactory;
|
||||
import org.mifosplatform.portfolio.client.domain.Client;
|
||||
import org.mifosplatform.portfolio.client.domain.ClientRepositoryWrapper;
|
||||
import org.mifosplatform.portfolio.group.domain.Group;
|
||||
import org.mifosplatform.portfolio.group.domain.GroupRepository;
|
||||
import org.mifosplatform.portfolio.group.exception.GroupNotFoundException;
|
||||
import org.mifosplatform.portfolio.note.domain.Note;
|
||||
import org.mifosplatform.portfolio.note.domain.NoteRepository;
|
||||
import org.mifosplatform.portfolio.savings.SavingsApiConstants;
|
||||
import org.mifosplatform.portfolio.savings.data.SavingsAccountDataValidator;
|
||||
import org.mifosplatform.portfolio.savings.domain.SavingsAccount;
|
||||
import org.mifosplatform.portfolio.savings.domain.SavingsAccountAssembler;
|
||||
import org.mifosplatform.portfolio.savings.domain.SavingsAccountRepositoryWrapper;
|
||||
import org.mifosplatform.portfolio.savings.domain.SavingsProduct;
|
||||
import org.mifosplatform.portfolio.savings.domain.SavingsProductRepository;
|
||||
import org.mifosplatform.portfolio.savings.exception.SavingsProductNotFoundException;
|
||||
import org.mifosplatform.useradministration.domain.AppUser;
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.dao.DataAccessException;
|
||||
import org.springframework.stereotype.Service;
|
||||
import org.springframework.transaction.annotation.Transactional;
|
||||
|
||||
@Service
|
||||
public class SavingsApplicationProcessWritePlatformServiceJpaRepositoryImpl implements SavingsApplicationProcessWritePlatformService {
|
||||
|
||||
private final static Logger logger = LoggerFactory.getLogger(SavingsApplicationProcessWritePlatformServiceJpaRepositoryImpl.class);
|
||||
|
||||
private final PlatformSecurityContext context;
|
||||
private final SavingsAccountRepositoryWrapper savingAccountRepository;
|
||||
private final SavingsAccountAssembler savingAccountAssembler;
|
||||
private final SavingsAccountDataValidator savingsAccountDataValidator;
|
||||
private final AccountNumberGeneratorFactory accountIdentifierGeneratorFactory;
|
||||
private final ClientRepositoryWrapper clientRepository;
|
||||
private final GroupRepository groupRepository;
|
||||
private final SavingsProductRepository savingsProductRepository;
|
||||
private final NoteRepository noteRepository;
|
||||
private final SavingsAccountApplicationTransitionApiJsonValidator savingsAccountApplicationTransitionApiJsonValidator;
|
||||
private final ApplicationCurrencyRepositoryWrapper applicationCurrencyRepositoryWrapper;
|
||||
private final JournalEntryWritePlatformService journalEntryWritePlatformService;
|
||||
|
||||
@Autowired
|
||||
public SavingsApplicationProcessWritePlatformServiceJpaRepositoryImpl(final PlatformSecurityContext context,
|
||||
final SavingsAccountRepositoryWrapper savingAccountRepository, final SavingsAccountAssembler savingAccountAssembler,
|
||||
final SavingsAccountDataValidator savingsAccountDataValidator,
|
||||
final AccountNumberGeneratorFactory accountIdentifierGeneratorFactory, final ClientRepositoryWrapper clientRepository,
|
||||
final GroupRepository groupRepository, final SavingsProductRepository savingsProductRepository,
|
||||
final NoteRepository noteRepository,
|
||||
final SavingsAccountApplicationTransitionApiJsonValidator savingsAccountApplicationTransitionApiJsonValidator,
|
||||
final ApplicationCurrencyRepositoryWrapper applicationCurrencyRepositoryWrapper,
|
||||
final JournalEntryWritePlatformService journalEntryWritePlatformService) {
|
||||
this.context = context;
|
||||
this.savingAccountRepository = savingAccountRepository;
|
||||
this.savingAccountAssembler = savingAccountAssembler;
|
||||
this.accountIdentifierGeneratorFactory = accountIdentifierGeneratorFactory;
|
||||
this.savingsAccountDataValidator = savingsAccountDataValidator;
|
||||
this.clientRepository = clientRepository;
|
||||
this.groupRepository = groupRepository;
|
||||
this.savingsProductRepository = savingsProductRepository;
|
||||
this.noteRepository = noteRepository;
|
||||
this.savingsAccountApplicationTransitionApiJsonValidator = savingsAccountApplicationTransitionApiJsonValidator;
|
||||
this.applicationCurrencyRepositoryWrapper = applicationCurrencyRepositoryWrapper;
|
||||
this.journalEntryWritePlatformService = journalEntryWritePlatformService;
|
||||
}
|
||||
|
||||
/*
|
||||
* Guaranteed to throw an exception no matter what the data integrity issue
|
||||
* is.
|
||||
*/
|
||||
private void handleDataIntegrityIssues(final JsonCommand command, final DataAccessException dve) {
|
||||
|
||||
final StringBuilder errorCodeBuilder = new StringBuilder("error.msg.").append(SavingsApiConstants.SAVINGS_ACCOUNT_RESOURCE_NAME);
|
||||
|
||||
final Throwable realCause = dve.getMostSpecificCause();
|
||||
if (realCause.getMessage().contains("sa_account_no_UNIQUE")) {
|
||||
final String accountNo = command.stringValueOfParameterNamed("accountNo");
|
||||
errorCodeBuilder.append(".duplicate.accountNo");
|
||||
throw new PlatformDataIntegrityException(errorCodeBuilder.toString(), "Savings account with accountNo " + accountNo
|
||||
+ " already exists", "accountNo", accountNo);
|
||||
|
||||
} else if (realCause.getMessage().contains("sa_external_id_UNIQUE")) {
|
||||
|
||||
final String externalId = command.stringValueOfParameterNamed("externalId");
|
||||
errorCodeBuilder.append(".duplicate.externalId");
|
||||
throw new PlatformDataIntegrityException(errorCodeBuilder.toString(), "Savings account with externalId " + externalId
|
||||
+ " already exists", "externalId", externalId);
|
||||
}
|
||||
|
||||
errorCodeBuilder.append(".unknown.data.integrity.issue");
|
||||
logger.error(dve.getMessage(), dve);
|
||||
throw new PlatformDataIntegrityException(errorCodeBuilder.toString(), "Unknown data integrity issue with savings account.");
|
||||
}
|
||||
|
||||
@Transactional
|
||||
@Override
|
||||
public CommandProcessingResult submitApplication(final JsonCommand command) {
|
||||
try {
|
||||
this.savingsAccountDataValidator.validateForSubmit(command.json());
|
||||
|
||||
final List<Long> existingTransactionIds = new ArrayList<Long>();
|
||||
final List<Long> existingReversedTransactionIds = new ArrayList<Long>();
|
||||
final SavingsAccount account = this.savingAccountAssembler.assembleFrom(command);
|
||||
this.savingAccountRepository.save(account);
|
||||
|
||||
if (account.isAccountNumberRequiresAutoGeneration()) {
|
||||
final AccountNumberGenerator accountNoGenerator = this.accountIdentifierGeneratorFactory
|
||||
.determineSavingsAccountNoGenerator(account.getId());
|
||||
account.updateAccountNo(accountNoGenerator.generate());
|
||||
|
||||
this.savingAccountRepository.save(account);
|
||||
}
|
||||
|
||||
postJournalEntries(account, existingTransactionIds, existingReversedTransactionIds);
|
||||
|
||||
final Long savingsId = account.getId();
|
||||
return new CommandProcessingResultBuilder() //
|
||||
.withCommandId(command.commandId()) //
|
||||
.withEntityId(savingsId) //
|
||||
.withOfficeId(account.officeId()) //
|
||||
.withClientId(account.clientId()) //
|
||||
.withGroupId(account.groupId()) //
|
||||
.withSavingsId(savingsId) //
|
||||
.build();
|
||||
} catch (DataAccessException dve) {
|
||||
handleDataIntegrityIssues(command, dve);
|
||||
return CommandProcessingResult.empty();
|
||||
}
|
||||
}
|
||||
|
||||
@Transactional
|
||||
@Override
|
||||
public CommandProcessingResult modifyApplication(final Long savingsId, final JsonCommand command) {
|
||||
try {
|
||||
this.savingsAccountDataValidator.validateForUpdate(command.json());
|
||||
|
||||
final Map<String, Object> changes = new LinkedHashMap<String, Object>(20);
|
||||
|
||||
final SavingsAccount account = this.savingAccountRepository.findOneWithNotFoundDetection(savingsId);
|
||||
|
||||
account.update(command, changes);
|
||||
|
||||
if (!changes.isEmpty()) {
|
||||
|
||||
if (changes.containsKey(SavingsApiConstants.clientIdParamName)) {
|
||||
final Long clientId = command.longValueOfParameterNamed(SavingsApiConstants.clientIdParamName);
|
||||
if (clientId != null) {
|
||||
final Client client = this.clientRepository.findOneWithNotFoundDetection(clientId);
|
||||
account.update(client);
|
||||
} else {
|
||||
final Client client = null;
|
||||
account.update(client);
|
||||
}
|
||||
}
|
||||
|
||||
if (changes.containsKey(SavingsApiConstants.groupIdParamName)) {
|
||||
final Long groupId = command.longValueOfParameterNamed(SavingsApiConstants.groupIdParamName);
|
||||
if (groupId != null) {
|
||||
final Group group = this.groupRepository.findOne(groupId);
|
||||
if (group == null) { throw new GroupNotFoundException(groupId); }
|
||||
account.update(group);
|
||||
} else {
|
||||
final Group group = null;
|
||||
account.update(group);
|
||||
}
|
||||
}
|
||||
|
||||
if (changes.containsKey(SavingsApiConstants.productIdParamName)) {
|
||||
final Long productId = command.longValueOfParameterNamed(SavingsApiConstants.productIdParamName);
|
||||
final SavingsProduct product = this.savingsProductRepository.findOne(productId);
|
||||
if (product == null) { throw new SavingsProductNotFoundException(productId); }
|
||||
|
||||
account.update(product);
|
||||
}
|
||||
|
||||
this.savingAccountRepository.saveAndFlush(account);
|
||||
}
|
||||
|
||||
return new CommandProcessingResultBuilder() //
|
||||
.withCommandId(command.commandId()) //
|
||||
.withEntityId(savingsId) //
|
||||
.withOfficeId(account.officeId()) //
|
||||
.withClientId(account.clientId()) //
|
||||
.withGroupId(account.groupId()) //
|
||||
.withSavingsId(savingsId) //
|
||||
.with(changes) //
|
||||
.build();
|
||||
} catch (DataAccessException dve) {
|
||||
handleDataIntegrityIssues(command, dve);
|
||||
return new CommandProcessingResult(Long.valueOf(-1));
|
||||
}
|
||||
}
|
||||
|
||||
@Transactional
|
||||
@Override
|
||||
public CommandProcessingResult deleteApplication(final Long savingsId) {
|
||||
|
||||
this.context.authenticatedUser();
|
||||
|
||||
final SavingsAccount account = this.savingAccountRepository.findOneWithNotFoundDetection(savingsId);
|
||||
|
||||
List<Note> relatedNotes = this.noteRepository.findBySavingsAccountId(savingsId);
|
||||
this.noteRepository.deleteInBatch(relatedNotes);
|
||||
|
||||
this.savingAccountRepository.delete(account);
|
||||
|
||||
return new CommandProcessingResultBuilder() //
|
||||
.withEntityId(savingsId) //
|
||||
.withOfficeId(account.officeId()) //
|
||||
.withClientId(account.clientId()) //
|
||||
.withGroupId(account.groupId()) //
|
||||
.withSavingsId(savingsId) //
|
||||
.build();
|
||||
}
|
||||
|
||||
@Transactional
|
||||
@Override
|
||||
public CommandProcessingResult approveApplication(final Long savingsId, final JsonCommand command) {
|
||||
|
||||
final AppUser currentUser = context.authenticatedUser();
|
||||
|
||||
this.savingsAccountApplicationTransitionApiJsonValidator.validateApproval(command.json());
|
||||
|
||||
final SavingsAccount savingsAccount = this.savingAccountAssembler.assembleFrom(savingsId);
|
||||
|
||||
final Map<String, Object> changes = savingsAccount.approveApplication(currentUser, command, DateUtils.getLocalDateOfTenant());
|
||||
if (!changes.isEmpty()) {
|
||||
this.savingAccountRepository.save(savingsAccount);
|
||||
|
||||
final String noteText = command.stringValueOfParameterNamed("note");
|
||||
if (StringUtils.isNotBlank(noteText)) {
|
||||
Note note = Note.savingNote(savingsAccount, noteText);
|
||||
changes.put("note", noteText);
|
||||
this.noteRepository.save(note);
|
||||
}
|
||||
}
|
||||
|
||||
return new CommandProcessingResultBuilder() //
|
||||
.withCommandId(command.commandId()) //
|
||||
.withEntityId(savingsId) //
|
||||
.withOfficeId(savingsAccount.officeId()) //
|
||||
.withClientId(savingsAccount.clientId()) //
|
||||
.withGroupId(savingsAccount.groupId()) //
|
||||
.withSavingsId(savingsId) //
|
||||
.with(changes) //
|
||||
.build();
|
||||
}
|
||||
|
||||
@Transactional
|
||||
@Override
|
||||
public CommandProcessingResult undoApplicationApproval(final Long savingsId, final JsonCommand command) {
|
||||
|
||||
context.authenticatedUser();
|
||||
|
||||
this.savingsAccountApplicationTransitionApiJsonValidator.validateForUndo(command.json());
|
||||
|
||||
final SavingsAccount savingsAccount = this.savingAccountAssembler.assembleFrom(savingsId);
|
||||
|
||||
final Map<String, Object> changes = savingsAccount.undoApplicationApproval();
|
||||
if (!changes.isEmpty()) {
|
||||
this.savingAccountRepository.save(savingsAccount);
|
||||
|
||||
final String noteText = command.stringValueOfParameterNamed("note");
|
||||
if (StringUtils.isNotBlank(noteText)) {
|
||||
Note note = Note.savingNote(savingsAccount, noteText);
|
||||
changes.put("note", noteText);
|
||||
this.noteRepository.save(note);
|
||||
}
|
||||
}
|
||||
|
||||
return new CommandProcessingResultBuilder() //
|
||||
.withCommandId(command.commandId()) //
|
||||
.withEntityId(savingsId) //
|
||||
.withOfficeId(savingsAccount.officeId()) //
|
||||
.withClientId(savingsAccount.clientId()) //
|
||||
.withGroupId(savingsAccount.groupId()) //
|
||||
.withSavingsId(savingsId) //
|
||||
.with(changes) //
|
||||
.build();
|
||||
}
|
||||
|
||||
@Transactional
|
||||
@Override
|
||||
public CommandProcessingResult rejectApplication(final Long savingsId, final JsonCommand command) {
|
||||
|
||||
final AppUser currentUser = context.authenticatedUser();
|
||||
|
||||
this.savingsAccountApplicationTransitionApiJsonValidator.validateRejection(command.json());
|
||||
|
||||
final SavingsAccount savingsAccount = this.savingAccountAssembler.assembleFrom(savingsId);
|
||||
|
||||
final Map<String, Object> changes = savingsAccount.rejectApplication(currentUser, command, DateUtils.getLocalDateOfTenant());
|
||||
if (!changes.isEmpty()) {
|
||||
this.savingAccountRepository.save(savingsAccount);
|
||||
|
||||
final String noteText = command.stringValueOfParameterNamed("note");
|
||||
if (StringUtils.isNotBlank(noteText)) {
|
||||
Note note = Note.savingNote(savingsAccount, noteText);
|
||||
changes.put("note", noteText);
|
||||
this.noteRepository.save(note);
|
||||
}
|
||||
}
|
||||
|
||||
return new CommandProcessingResultBuilder() //
|
||||
.withCommandId(command.commandId()) //
|
||||
.withEntityId(savingsId) //
|
||||
.withOfficeId(savingsAccount.officeId()) //
|
||||
.withClientId(savingsAccount.clientId()) //
|
||||
.withGroupId(savingsAccount.groupId()) //
|
||||
.withSavingsId(savingsId) //
|
||||
.with(changes) //
|
||||
.build();
|
||||
}
|
||||
|
||||
@Transactional
|
||||
@Override
|
||||
public CommandProcessingResult applicantWithdrawsFromApplication(final Long savingsId, final JsonCommand command) {
|
||||
final AppUser currentUser = context.authenticatedUser();
|
||||
|
||||
this.savingsAccountApplicationTransitionApiJsonValidator.validateApplicantWithdrawal(command.json());
|
||||
|
||||
final SavingsAccount savingsAccount = this.savingAccountAssembler.assembleFrom(savingsId);
|
||||
|
||||
final Map<String, Object> changes = savingsAccount.applicantWithdrawsFromApplication(currentUser, command,
|
||||
DateUtils.getLocalDateOfTenant());
|
||||
if (!changes.isEmpty()) {
|
||||
this.savingAccountRepository.save(savingsAccount);
|
||||
|
||||
final String noteText = command.stringValueOfParameterNamed("note");
|
||||
if (StringUtils.isNotBlank(noteText)) {
|
||||
Note note = Note.savingNote(savingsAccount, noteText);
|
||||
changes.put("note", noteText);
|
||||
this.noteRepository.save(note);
|
||||
}
|
||||
}
|
||||
|
||||
return new CommandProcessingResultBuilder() //
|
||||
.withCommandId(command.commandId()) //
|
||||
.withEntityId(savingsId) //
|
||||
.withOfficeId(savingsAccount.officeId()) //
|
||||
.withClientId(savingsAccount.clientId()) //
|
||||
.withGroupId(savingsAccount.groupId()) //
|
||||
.withSavingsId(savingsId) //
|
||||
.with(changes) //
|
||||
.build();
|
||||
}
|
||||
|
||||
private void postJournalEntries(final SavingsAccount savingsAccount, final List<Long> existingTransactionIds,
|
||||
final List<Long> existingReversedTransactionIds) {
|
||||
|
||||
final MonetaryCurrency currency = savingsAccount.getCurrency();
|
||||
final ApplicationCurrency applicationCurrency = this.applicationCurrencyRepositoryWrapper.findOneWithNotFoundDetection(currency);
|
||||
|
||||
final Map<String, Object> accountingBridgeData = savingsAccount.deriveAccountingBridgeData(applicationCurrency.toData(),
|
||||
existingTransactionIds, existingReversedTransactionIds);
|
||||
journalEntryWritePlatformService.createJournalEntriesForSavings(accountingBridgeData);
|
||||
}
|
||||
}
|
||||
+16
-17
@@ -10,12 +10,12 @@ import java.util.Collection;
|
||||
import java.util.List;
|
||||
|
||||
import org.mifosplatform.infrastructure.core.data.EnumOptionData;
|
||||
import org.mifosplatform.portfolio.savings.domain.SavingsCompoundingInterestPeriodType;
|
||||
import org.mifosplatform.portfolio.savings.domain.SavingsInterestCalculationDaysInYearType;
|
||||
import org.mifosplatform.portfolio.savings.domain.SavingsInterestCalculationType;
|
||||
import org.mifosplatform.portfolio.savings.domain.SavingsInterestPostingPeriodType;
|
||||
import org.mifosplatform.portfolio.savings.domain.SavingsPeriodFrequencyType;
|
||||
import org.mifosplatform.portfolio.savings.domain.SavingsWithdrawalFeesType;
|
||||
import org.mifosplatform.portfolio.savings.SavingsCompoundingInterestPeriodType;
|
||||
import org.mifosplatform.portfolio.savings.SavingsInterestCalculationDaysInYearType;
|
||||
import org.mifosplatform.portfolio.savings.SavingsInterestCalculationType;
|
||||
import org.mifosplatform.portfolio.savings.SavingsPeriodFrequencyType;
|
||||
import org.mifosplatform.portfolio.savings.SavingsPostingInterestPeriodType;
|
||||
import org.mifosplatform.portfolio.savings.SavingsWithdrawalFeesType;
|
||||
import org.springframework.stereotype.Service;
|
||||
|
||||
@Service
|
||||
@@ -47,13 +47,13 @@ public class SavingsDropdownReadPlatformServiceImpl implements SavingsDropdownRe
|
||||
public Collection<EnumOptionData> retrieveCompoundingInterestPeriodTypeOptions() {
|
||||
List<EnumOptionData> allowedOptions = Arrays.asList( //
|
||||
SavingsEnumerations.compoundingInterestPeriodType(SavingsCompoundingInterestPeriodType.DAILY), //
|
||||
SavingsEnumerations.compoundingInterestPeriodType(SavingsCompoundingInterestPeriodType.WEEKLY), //
|
||||
SavingsEnumerations.compoundingInterestPeriodType(SavingsCompoundingInterestPeriodType.BIWEEKLY), //
|
||||
SavingsEnumerations.compoundingInterestPeriodType(SavingsCompoundingInterestPeriodType.MONTHLY), //
|
||||
SavingsEnumerations.compoundingInterestPeriodType(SavingsCompoundingInterestPeriodType.QUATERLY), //
|
||||
SavingsEnumerations.compoundingInterestPeriodType(SavingsCompoundingInterestPeriodType.BI_ANNUAL), //
|
||||
SavingsEnumerations.compoundingInterestPeriodType(SavingsCompoundingInterestPeriodType.ANNUAL), //
|
||||
SavingsEnumerations.compoundingInterestPeriodType(SavingsCompoundingInterestPeriodType.NO_COMPOUNDING_SIMPLE_INTEREST) //
|
||||
// SavingsEnumerations.compoundingInterestPeriodType(SavingsCompoundingInterestPeriodType.WEEKLY), //
|
||||
// SavingsEnumerations.compoundingInterestPeriodType(SavingsCompoundingInterestPeriodType.BIWEEKLY), //
|
||||
SavingsEnumerations.compoundingInterestPeriodType(SavingsCompoundingInterestPeriodType.MONTHLY)
|
||||
// SavingsEnumerations.compoundingInterestPeriodType(SavingsCompoundingInterestPeriodType.QUATERLY), //
|
||||
// SavingsEnumerations.compoundingInterestPeriodType(SavingsCompoundingInterestPeriodType.BI_ANNUAL), //
|
||||
// SavingsEnumerations.compoundingInterestPeriodType(SavingsCompoundingInterestPeriodType.ANNUAL), //
|
||||
// SavingsEnumerations.compoundingInterestPeriodType(SavingsCompoundingInterestPeriodType.NO_COMPOUNDING_SIMPLE_INTEREST) //
|
||||
);
|
||||
|
||||
return allowedOptions;
|
||||
@@ -62,10 +62,9 @@ public class SavingsDropdownReadPlatformServiceImpl implements SavingsDropdownRe
|
||||
@Override
|
||||
public Collection<EnumOptionData> retrieveInterestPostingPeriodTypeOptions() {
|
||||
List<EnumOptionData> allowedOptions = Arrays.asList( //
|
||||
SavingsEnumerations.interestPostingPeriodType(SavingsInterestPostingPeriodType.MONTHLY), //
|
||||
SavingsEnumerations.interestPostingPeriodType(SavingsInterestPostingPeriodType.QUATERLY), //
|
||||
SavingsEnumerations.interestPostingPeriodType(SavingsInterestPostingPeriodType.BI_ANNUAL), //
|
||||
SavingsEnumerations.interestPostingPeriodType(SavingsInterestPostingPeriodType.ANNUAL) //
|
||||
SavingsEnumerations.interestPostingPeriodType(SavingsPostingInterestPeriodType.MONTHLY), //
|
||||
SavingsEnumerations.interestPostingPeriodType(SavingsPostingInterestPeriodType.QUATERLY), //
|
||||
SavingsEnumerations.interestPostingPeriodType(SavingsPostingInterestPeriodType.ANNUAL) //
|
||||
);
|
||||
|
||||
return allowedOptions;
|
||||
|
||||
+92
-54
@@ -6,16 +6,16 @@
|
||||
package org.mifosplatform.portfolio.savings.service;
|
||||
|
||||
import org.mifosplatform.infrastructure.core.data.EnumOptionData;
|
||||
import org.mifosplatform.portfolio.savings.SavingsAccountTransactionType;
|
||||
import org.mifosplatform.portfolio.savings.SavingsCompoundingInterestPeriodType;
|
||||
import org.mifosplatform.portfolio.savings.SavingsInterestCalculationDaysInYearType;
|
||||
import org.mifosplatform.portfolio.savings.SavingsInterestCalculationType;
|
||||
import org.mifosplatform.portfolio.savings.SavingsPeriodFrequencyType;
|
||||
import org.mifosplatform.portfolio.savings.SavingsPostingInterestPeriodType;
|
||||
import org.mifosplatform.portfolio.savings.SavingsWithdrawalFeesType;
|
||||
import org.mifosplatform.portfolio.savings.data.SavingsAccountStatusEnumData;
|
||||
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.SavingsCompoundingInterestPeriodType;
|
||||
import org.mifosplatform.portfolio.savings.domain.SavingsInterestCalculationDaysInYearType;
|
||||
import org.mifosplatform.portfolio.savings.domain.SavingsInterestCalculationType;
|
||||
import org.mifosplatform.portfolio.savings.domain.SavingsInterestPostingPeriodType;
|
||||
import org.mifosplatform.portfolio.savings.domain.SavingsPeriodFrequencyType;
|
||||
import org.mifosplatform.portfolio.savings.domain.SavingsWithdrawalFeesType;
|
||||
|
||||
public class SavingsEnumerations {
|
||||
|
||||
@@ -94,59 +94,81 @@ public class SavingsEnumerations {
|
||||
|
||||
public static SavingsAccountStatusEnumData status(final SavingsAccountStatusType type) {
|
||||
|
||||
final boolean submittedAndPendingApproval = type.isSubmittedAndPendingApproval();
|
||||
final boolean isApproved = type.isApproved();
|
||||
final boolean isRejected = type.isRejected();
|
||||
final boolean isWithdrawnByApplicant = type.isApplicationWithdrawnByApplicant();
|
||||
final boolean isActive = type.isActive();
|
||||
final boolean isClosed = type.isClosed();
|
||||
|
||||
SavingsAccountStatusEnumData optionData = new SavingsAccountStatusEnumData(SavingsAccountStatusType.INVALID.getValue().longValue(),
|
||||
SavingsAccountStatusType.INVALID.getCode(), "Invalid", false, false, false);
|
||||
SavingsAccountStatusType.INVALID.getCode(), "Invalid", submittedAndPendingApproval, isApproved, isRejected,
|
||||
isWithdrawnByApplicant, isActive, isClosed);
|
||||
|
||||
switch (type) {
|
||||
case INVALID:
|
||||
optionData = new SavingsAccountStatusEnumData(SavingsAccountStatusType.INVALID.getValue().longValue(),
|
||||
SavingsAccountStatusType.INVALID.getCode(), "Invalid", type.isUnactivated(), type.isActive(), type.isClosed());
|
||||
SavingsAccountStatusType.INVALID.getCode(), "Invalid", submittedAndPendingApproval, isApproved, isRejected,
|
||||
isWithdrawnByApplicant, isActive, isClosed);
|
||||
break;
|
||||
case UNACTIVATED:
|
||||
optionData = new SavingsAccountStatusEnumData(SavingsAccountStatusType.UNACTIVATED.getValue().longValue(),
|
||||
SavingsAccountStatusType.UNACTIVATED.getCode(), "Unactivated", type.isUnactivated(), type.isActive(),
|
||||
type.isClosed());
|
||||
case SUBMITTED_AND_PENDING_APPROVAL:
|
||||
optionData = new SavingsAccountStatusEnumData(SavingsAccountStatusType.SUBMITTED_AND_PENDING_APPROVAL.getValue()
|
||||
.longValue(), SavingsAccountStatusType.SUBMITTED_AND_PENDING_APPROVAL.getCode(), "Submitted and pending approval",
|
||||
submittedAndPendingApproval, isApproved, isRejected, isWithdrawnByApplicant, isActive, isClosed);
|
||||
break;
|
||||
case REJECTED:
|
||||
optionData = new SavingsAccountStatusEnumData(SavingsAccountStatusType.REJECTED.getValue().longValue(),
|
||||
SavingsAccountStatusType.REJECTED.getCode(), "Rejected", submittedAndPendingApproval, isApproved, isRejected,
|
||||
isWithdrawnByApplicant, isActive, isClosed);
|
||||
break;
|
||||
case WITHDRAWN_BY_APPLICANT:
|
||||
optionData = new SavingsAccountStatusEnumData(SavingsAccountStatusType.WITHDRAWN_BY_APPLICANT.getValue().longValue(),
|
||||
SavingsAccountStatusType.WITHDRAWN_BY_APPLICANT.getCode(), "Withdrawn by applicant", submittedAndPendingApproval,
|
||||
isApproved, isRejected, isWithdrawnByApplicant, isActive, isClosed);
|
||||
break;
|
||||
case APPROVED:
|
||||
optionData = new SavingsAccountStatusEnumData(SavingsAccountStatusType.APPROVED.getValue().longValue(),
|
||||
SavingsAccountStatusType.APPROVED.getCode(), "Approved", submittedAndPendingApproval, isApproved, isRejected,
|
||||
isWithdrawnByApplicant, isActive, isClosed);
|
||||
break;
|
||||
case ACTIVE:
|
||||
optionData = new SavingsAccountStatusEnumData(SavingsAccountStatusType.ACTIVE.getValue().longValue(),
|
||||
SavingsAccountStatusType.ACTIVE.getCode(), "Active", type.isUnactivated(), type.isActive(), type.isClosed());
|
||||
SavingsAccountStatusType.ACTIVE.getCode(), "Active", submittedAndPendingApproval, isApproved, isRejected,
|
||||
isWithdrawnByApplicant, isActive, isClosed);
|
||||
break;
|
||||
case CLOSED:
|
||||
optionData = new SavingsAccountStatusEnumData(SavingsAccountStatusType.CLOSED.getValue().longValue(),
|
||||
SavingsAccountStatusType.CLOSED.getCode(), "Closed", type.isUnactivated(), type.isActive(), type.isClosed());
|
||||
SavingsAccountStatusType.CLOSED.getCode(), "Closed", submittedAndPendingApproval, isApproved, isRejected,
|
||||
isWithdrawnByApplicant, isActive, isClosed);
|
||||
break;
|
||||
}
|
||||
return optionData;
|
||||
}
|
||||
|
||||
public static EnumOptionData interestPostingPeriodType(final Integer type) {
|
||||
return interestPostingPeriodType(SavingsInterestPostingPeriodType.fromInt(type));
|
||||
return interestPostingPeriodType(SavingsPostingInterestPeriodType.fromInt(type));
|
||||
}
|
||||
|
||||
public static EnumOptionData interestPostingPeriodType(final SavingsInterestPostingPeriodType type) {
|
||||
public static EnumOptionData interestPostingPeriodType(final SavingsPostingInterestPeriodType type) {
|
||||
|
||||
final String codePrefix = "savings.interest.posting.period.";
|
||||
EnumOptionData optionData = new EnumOptionData(SavingsInterestPostingPeriodType.INVALID.getValue().longValue(),
|
||||
SavingsInterestPostingPeriodType.INVALID.getCode(), "Invalid");
|
||||
EnumOptionData optionData = new EnumOptionData(SavingsPostingInterestPeriodType.INVALID.getValue().longValue(),
|
||||
SavingsPostingInterestPeriodType.INVALID.getCode(), "Invalid");
|
||||
|
||||
switch (type) {
|
||||
case INVALID:
|
||||
break;
|
||||
case MONTHLY:
|
||||
optionData = new EnumOptionData(SavingsInterestPostingPeriodType.MONTHLY.getValue().longValue(), codePrefix
|
||||
+ SavingsInterestPostingPeriodType.MONTHLY.getCode(), "Monthly");
|
||||
optionData = new EnumOptionData(SavingsPostingInterestPeriodType.MONTHLY.getValue().longValue(), codePrefix
|
||||
+ SavingsPostingInterestPeriodType.MONTHLY.getCode(), "Monthly");
|
||||
break;
|
||||
case QUATERLY:
|
||||
optionData = new EnumOptionData(SavingsInterestPostingPeriodType.QUATERLY.getValue().longValue(), codePrefix
|
||||
+ SavingsInterestPostingPeriodType.QUATERLY.getCode(), "Quarterly");
|
||||
break;
|
||||
case BI_ANNUAL:
|
||||
optionData = new EnumOptionData(SavingsInterestPostingPeriodType.BI_ANNUAL.getValue().longValue(), codePrefix
|
||||
+ SavingsInterestPostingPeriodType.BI_ANNUAL.getCode(), "Semi-Annual");
|
||||
optionData = new EnumOptionData(SavingsPostingInterestPeriodType.QUATERLY.getValue().longValue(), codePrefix
|
||||
+ SavingsPostingInterestPeriodType.QUATERLY.getCode(), "Quarterly");
|
||||
break;
|
||||
case ANNUAL:
|
||||
optionData = new EnumOptionData(SavingsInterestPostingPeriodType.ANNUAL.getValue().longValue(), codePrefix
|
||||
+ SavingsInterestPostingPeriodType.ANNUAL.getCode(), "Annually");
|
||||
optionData = new EnumOptionData(SavingsPostingInterestPeriodType.ANNUAL.getValue().longValue(), codePrefix
|
||||
+ SavingsPostingInterestPeriodType.ANNUAL.getCode(), "Annually");
|
||||
break;
|
||||
}
|
||||
|
||||
@@ -170,35 +192,51 @@ public class SavingsEnumerations {
|
||||
optionData = new EnumOptionData(SavingsCompoundingInterestPeriodType.DAILY.getValue().longValue(), codePrefix
|
||||
+ SavingsCompoundingInterestPeriodType.DAILY.getCode(), "Daily");
|
||||
break;
|
||||
case WEEKLY:
|
||||
optionData = new EnumOptionData(SavingsCompoundingInterestPeriodType.WEEKLY.getValue().longValue(), codePrefix
|
||||
+ SavingsCompoundingInterestPeriodType.WEEKLY.getCode(), "Weekly");
|
||||
break;
|
||||
case BIWEEKLY:
|
||||
optionData = new EnumOptionData(SavingsCompoundingInterestPeriodType.BIWEEKLY.getValue().longValue(), codePrefix
|
||||
+ SavingsCompoundingInterestPeriodType.BIWEEKLY.getCode(), "Bi-Weekly");
|
||||
break;
|
||||
// case WEEKLY:
|
||||
// optionData = new
|
||||
// EnumOptionData(SavingsCompoundingInterestPeriodType.WEEKLY.getValue().longValue(),
|
||||
// codePrefix
|
||||
// + SavingsCompoundingInterestPeriodType.WEEKLY.getCode(),
|
||||
// "Weekly");
|
||||
// break;
|
||||
// case BIWEEKLY:
|
||||
// optionData = new
|
||||
// EnumOptionData(SavingsCompoundingInterestPeriodType.BIWEEKLY.getValue().longValue(),
|
||||
// codePrefix
|
||||
// + SavingsCompoundingInterestPeriodType.BIWEEKLY.getCode(),
|
||||
// "Bi-Weekly");
|
||||
// break;
|
||||
case MONTHLY:
|
||||
optionData = new EnumOptionData(SavingsCompoundingInterestPeriodType.MONTHLY.getValue().longValue(), codePrefix
|
||||
+ SavingsCompoundingInterestPeriodType.MONTHLY.getCode(), "Monthly");
|
||||
break;
|
||||
case QUATERLY:
|
||||
optionData = new EnumOptionData(SavingsCompoundingInterestPeriodType.QUATERLY.getValue().longValue(), codePrefix
|
||||
+ SavingsCompoundingInterestPeriodType.QUATERLY.getCode(), "Quarterly");
|
||||
break;
|
||||
case BI_ANNUAL:
|
||||
optionData = new EnumOptionData(SavingsCompoundingInterestPeriodType.BI_ANNUAL.getValue().longValue(), codePrefix
|
||||
+ SavingsCompoundingInterestPeriodType.BI_ANNUAL.getCode(), "Semi-Annual");
|
||||
break;
|
||||
case ANNUAL:
|
||||
optionData = new EnumOptionData(SavingsCompoundingInterestPeriodType.ANNUAL.getValue().longValue(), codePrefix
|
||||
+ SavingsCompoundingInterestPeriodType.ANNUAL.getCode(), "Annually");
|
||||
break;
|
||||
case NO_COMPOUNDING_SIMPLE_INTEREST:
|
||||
optionData = new EnumOptionData(SavingsCompoundingInterestPeriodType.NO_COMPOUNDING_SIMPLE_INTEREST.getValue().longValue(),
|
||||
codePrefix + SavingsCompoundingInterestPeriodType.NO_COMPOUNDING_SIMPLE_INTEREST.getCode(),
|
||||
"No Compounding - Simple Interest");
|
||||
break;
|
||||
// case QUATERLY:
|
||||
// optionData = new
|
||||
// EnumOptionData(SavingsCompoundingInterestPeriodType.QUATERLY.getValue().longValue(),
|
||||
// codePrefix
|
||||
// + SavingsCompoundingInterestPeriodType.QUATERLY.getCode(),
|
||||
// "Quarterly");
|
||||
// break;
|
||||
// case BI_ANNUAL:
|
||||
// optionData = new
|
||||
// EnumOptionData(SavingsCompoundingInterestPeriodType.BI_ANNUAL.getValue().longValue(),
|
||||
// codePrefix
|
||||
// + SavingsCompoundingInterestPeriodType.BI_ANNUAL.getCode(),
|
||||
// "Semi-Annual");
|
||||
// break;
|
||||
// case ANNUAL:
|
||||
// optionData = new
|
||||
// EnumOptionData(SavingsCompoundingInterestPeriodType.ANNUAL.getValue().longValue(),
|
||||
// codePrefix
|
||||
// + SavingsCompoundingInterestPeriodType.ANNUAL.getCode(), "Annually");
|
||||
// break;
|
||||
// case NO_COMPOUNDING_SIMPLE_INTEREST:
|
||||
// optionData = new
|
||||
// EnumOptionData(SavingsCompoundingInterestPeriodType.NO_COMPOUNDING_SIMPLE_INTEREST.getValue().longValue(),
|
||||
// codePrefix +
|
||||
// SavingsCompoundingInterestPeriodType.NO_COMPOUNDING_SIMPLE_INTEREST.getCode(),
|
||||
// "No Compounding - Simple Interest");
|
||||
// break;
|
||||
}
|
||||
|
||||
return optionData;
|
||||
|
||||
+2
-1
@@ -24,7 +24,8 @@ import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.dao.DataAccessException;
|
||||
import org.springframework.stereotype.Service;
|
||||
import org.springframework.transaction.annotation.Transactional;
|
||||
import static org.mifosplatform.portfolio.savings.api.SavingsApiConstants.accountingRuleParamName;
|
||||
|
||||
import static org.mifosplatform.portfolio.savings.SavingsApiConstants.accountingRuleParamName;
|
||||
|
||||
@Service
|
||||
public class SavingsProductWritePlatformServiceJpaRepositoryImpl implements SavingsProductWritePlatformService {
|
||||
|
||||
-1
@@ -205,5 +205,4 @@ public class ScheduledJobRunnerServiceImpl implements ScheduledJobRunnerService
|
||||
|
||||
logger.info(ThreadLocalContextUtil.getTenant().getName() + ": Results affected by update: " + savingsIds.size());
|
||||
}
|
||||
|
||||
}
|
||||
+13
-13
@@ -4,20 +4,20 @@ import org.mifosplatform.organisation.monetary.domain.MonetaryCurrency;
|
||||
|
||||
public class MonetaryCurrencyBuilder {
|
||||
|
||||
private String code = "XOF";
|
||||
private int digitsAfterDecimal = 0;
|
||||
private String code = "XOF";
|
||||
private int digitsAfterDecimal = 0;
|
||||
|
||||
public MonetaryCurrency build() {
|
||||
return new MonetaryCurrency(code, digitsAfterDecimal);
|
||||
}
|
||||
public MonetaryCurrency build() {
|
||||
return new MonetaryCurrency(code, digitsAfterDecimal);
|
||||
}
|
||||
|
||||
public MonetaryCurrencyBuilder withCode(String withCode) {
|
||||
this.code = withCode;
|
||||
return this;
|
||||
}
|
||||
public MonetaryCurrencyBuilder withCode(final String withCode) {
|
||||
this.code = withCode;
|
||||
return this;
|
||||
}
|
||||
|
||||
public MonetaryCurrencyBuilder withDigitsAfterDecimal(int withDigitsAfterDecimal) {
|
||||
this.digitsAfterDecimal = withDigitsAfterDecimal;
|
||||
return this;
|
||||
}
|
||||
public MonetaryCurrencyBuilder withDigitsAfterDecimal(final int withDigitsAfterDecimal) {
|
||||
this.digitsAfterDecimal = withDigitsAfterDecimal;
|
||||
return this;
|
||||
}
|
||||
}
|
||||
|
||||
+15
-15
@@ -7,20 +7,20 @@ import org.mifosplatform.organisation.monetary.domain.Money;
|
||||
|
||||
public class MoneyBuilder {
|
||||
|
||||
private MonetaryCurrency currencyDetail = new MonetaryCurrencyBuilder().build();
|
||||
private BigDecimal newAmount = BigDecimal.ZERO;
|
||||
|
||||
public Money build() {
|
||||
return Money.of(currencyDetail, newAmount);
|
||||
}
|
||||
private MonetaryCurrency currencyDetail = new MonetaryCurrencyBuilder().build();
|
||||
private BigDecimal newAmount = BigDecimal.ZERO;
|
||||
|
||||
public MoneyBuilder with(MonetaryCurrency withDetail) {
|
||||
this.currencyDetail = withDetail;
|
||||
return this;
|
||||
}
|
||||
|
||||
public MoneyBuilder with(String withAmount) {
|
||||
this.newAmount = BigDecimal.valueOf(Double.valueOf(withAmount));
|
||||
return this;
|
||||
}
|
||||
public Money build() {
|
||||
return Money.of(currencyDetail, newAmount);
|
||||
}
|
||||
|
||||
public MoneyBuilder with(final MonetaryCurrency withDetail) {
|
||||
this.currencyDetail = withDetail;
|
||||
return this;
|
||||
}
|
||||
|
||||
public MoneyBuilder with(final String withAmount) {
|
||||
this.newAmount = BigDecimal.valueOf(Double.valueOf(withAmount));
|
||||
return this;
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user