MIFOSX-245: add basic shell for savings products and accounts.

This commit is contained in:
Keith Woodlock
2013-03-20 00:35:56 +00:00
parent eb7d616834
commit 2c8efb4977
172 changed files with 3863 additions and 16432 deletions
+724 -2062
View File
File diff suppressed because it is too large Load Diff
@@ -0,0 +1,66 @@
ALTER TABLE `mifostenant-default`.`m_note`
DROP FOREIGN KEY `FK_m_note_m_saving_account`,
DROP FOREIGN KEY `FK_m_note_m_deposit_account`;
ALTER TABLE `mifostenant-default`.`m_note`
DROP COLUMN `saving_account_id`,
DROP COLUMN `deposit_account_id`,
DROP INDEX `FK_m_note_m_saving_account`,
DROP INDEX `FK_m_note_m_deposit_account`;
drop table `mifostenant-default`.`m_saving_account_transaction`;
drop table `mifostenant-default`.`m_saving_schedule`;
drop table `mifostenant-default`.`m_saving_account`;
drop table `mifostenant-default`.`m_deposit_account_transaction`;
drop table `mifostenant-default`.`m_deposit_account`;
drop table `mifostenant-default`.`m_product_savings`;
drop table `mifostenant-default`.`m_product_deposit`;
DROP TABLE IF EXISTS `m_savings_account`;
DROP TABLE IF EXISTS `m_savings_product`;
CREATE TABLE `m_savings_product` (
`id` bigint(20) NOT NULL AUTO_INCREMENT,
`name` varchar(100) NOT NULL,
`description` varchar(500) NOT NULL,
`currency_code` varchar(3) NOT NULL,
`currency_digits` smallint(5) NOT NULL,
`nominal_interest_rate_per_period` decimal(19,6) NOT NULL,
`nominal_interest_rate_period_frequency_enum` smallint(5) NOT NULL,
`min_required_opening_balance` decimal(19,6) DEFAULT NULL,
`lockin_period_frequency` decimal(19,6) DEFAULT NULL,
`lockin_period_frequency_enum` smallint(5) DEFAULT NULL,
PRIMARY KEY (`id`),
UNIQUE KEY `sp_unq_name` (`name`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8;
CREATE TABLE `m_savings_account` (
`id` bigint(20) NOT NULL AUTO_INCREMENT,
`account_no` varchar(20) NOT NULL,
`external_id` varchar(100) DEFAULT NULL,
`client_id` bigint(20) DEFAULT NULL,
`group_id` bigint(20) DEFAULT NULL,
`product_id` bigint(20) DEFAULT NULL,
`currency_code` varchar(3) NOT NULL,
`currency_digits` smallint(5) NOT NULL,
`nominal_interest_rate_per_period` decimal(19,6) NOT NULL,
`nominal_interest_rate_period_frequency_enum` smallint(5) NOT NULL,
`annual_nominal_interest_rate` decimal(19,6) NOT NULL,
`min_required_opening_balance` decimal(19,6) DEFAULT NULL,
`lockin_period_frequency` decimal(19,6) DEFAULT NULL,
`lockin_period_frequency_enum` smallint(5) DEFAULT NULL,
PRIMARY KEY (`id`),
UNIQUE KEY `sa_account_no_UNIQUE` (`account_no`),
UNIQUE KEY `sa_externalid_UNIQUE` (`external_id`),
KEY `FKSA00000000000001` (`client_id`),
KEY `FKSA00000000000002` (`group_id`),
KEY `FKSA00000000000003` (`product_id`),
CONSTRAINT `FKSA00000000000001` FOREIGN KEY (`client_id`) REFERENCES `m_client` (`id`),
CONSTRAINT `FKSA00000000000002` FOREIGN KEY (`group_id`) REFERENCES `m_group` (`id`),
CONSTRAINT `FKSA00000000000003` FOREIGN KEY (`product_id`) REFERENCES `m_savings_product` (`id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8;
@@ -27,7 +27,8 @@ public class CommandWrapperBuilder {
public CommandWrapper build() {
return new CommandWrapper(this.officeId, this.groupId, this.clientId, this.loanId, this.actionName, this.entityName, this.entityId,
this.apptableId, this.datatableId, this.codeId, this.supportedEntityType, this.supportedEntityId, this.href, this.json, this.transactionId);
this.apptableId, this.datatableId, this.codeId, this.supportedEntityType, this.supportedEntityId, this.href, this.json,
this.transactionId);
}
// public CommandWrapperBuilder withEntityId(final Long withId) {
@@ -372,7 +373,7 @@ public class CommandWrapperBuilder {
return this;
}
public CommandWrapperBuilder updateLoanCharge(final Long loanId, Long loanChargeId) {
public CommandWrapperBuilder updateLoanCharge(final Long loanId, final Long loanChargeId) {
this.actionName = "UPDATE";
this.entityName = "LOANCHARGE";
this.entityId = loanChargeId;
@@ -568,7 +569,7 @@ public class CommandWrapperBuilder {
return this;
}
public CommandWrapperBuilder updateCodeValue(Long codeId, final Long codeValueId) {
public CommandWrapperBuilder updateCodeValue(final Long codeId, final Long codeValueId) {
this.actionName = "UPDATE";
this.entityName = "CODEVALUE";
this.entityId = codeValueId;
@@ -633,7 +634,7 @@ public class CommandWrapperBuilder {
this.href = "/glaccounts/" + glAccountId;
return this;
}
public CommandWrapperBuilder createJournalEntry() {
this.actionName = "CREATE";
this.entityName = "JOURNALENTRY";
@@ -641,16 +642,16 @@ public class CommandWrapperBuilder {
this.href = "/journalentries/template";
return this;
}
public CommandWrapperBuilder reverseJournalEntry(final String transactionId) {
this.actionName = "REVERSE";
this.entityName = "JOURNALENTRY";
this.entityId = null;
this.transactionId = transactionId;
this.href = "/journalentries/"+transactionId;
this.href = "/journalentries/" + transactionId;
return this;
}
public CommandWrapperBuilder createDepositProduct() {
this.actionName = "CREATE";
this.entityName = "DEPOSITPRODUCT";
@@ -659,198 +660,166 @@ public class CommandWrapperBuilder {
return this;
}
public CommandWrapperBuilder updateDepositProduct(final Long productId) {
this.actionName = "UPDATE";
public CommandWrapperBuilder updateDepositProduct(final Long productId) {
this.actionName = "UPDATE";
this.entityName = "DEPOSITPRODUCT";
this.entityId = productId;
this.href = "/depositproducts/"+productId;
this.href = "/depositproducts/" + productId;
return this;
}
public CommandWrapperBuilder deleteDepositProduct(final Long productId) {
this.actionName = "DELETE";
this.entityName = "DEPOSITPRODUCT";
this.entityId = productId;
this.href = "/depositproducts/"+productId;
return this;
}
}
public CommandWrapperBuilder createDepositAccount() {
this.actionName = "CREATE";
public CommandWrapperBuilder deleteDepositProduct(final Long productId) {
this.actionName = "DELETE";
this.entityName = "DEPOSITPRODUCT";
this.entityId = productId;
this.href = "/depositproducts/" + productId;
return this;
}
public CommandWrapperBuilder createDepositAccount() {
this.actionName = "CREATE";
this.entityName = "DEPOSITACCOUNT";
this.entityId = null;
this.href = "/depositaccounts/template";
return this;
}
}
public CommandWrapperBuilder updateDepositAccount(Long accountId) {
this.actionName = "UPDATE";
public CommandWrapperBuilder updateDepositAccount(final Long accountId) {
this.actionName = "UPDATE";
this.entityName = "DEPOSITACCOUNT";
this.entityId = accountId;
this.href = "/depositaccounts/"+accountId;
this.href = "/depositaccounts/" + accountId;
return this;
}
}
public CommandWrapperBuilder deleteDepositAccount(Long accountId) {
this.actionName = "DELETE";
public CommandWrapperBuilder deleteDepositAccount(final Long accountId) {
this.actionName = "DELETE";
this.entityName = "DEPOSITACCOUNT";
this.entityId = accountId;
this.href = "/depositaccounts/"+accountId;
this.href = "/depositaccounts/" + accountId;
return this;
}
}
public CommandWrapperBuilder approveDepositApplication(Long accountId) {
this.actionName = "APPROVE";
public CommandWrapperBuilder approveDepositApplication(final Long accountId) {
this.actionName = "APPROVE";
this.entityName = "DEPOSITACCOUNT";
this.entityId = accountId;
this.href = "/depositaccounts/"+accountId;
this.href = "/depositaccounts/" + accountId;
return this;
}
}
public CommandWrapperBuilder withdrawDepositAmount(Long accountId) {
this.actionName = "WITHDRAWAL";
public CommandWrapperBuilder withdrawDepositAmount(final Long accountId) {
this.actionName = "WITHDRAWAL";
this.entityName = "DEPOSITACCOUNT";
this.entityId = accountId;
this.href = "/depositaccounts/"+accountId;
this.href = "/depositaccounts/" + accountId;
return this;
}
}
public CommandWrapperBuilder withdrawInterestDepositAmount(Long accountId) {
this.actionName = "INTEREST";
public CommandWrapperBuilder withdrawInterestDepositAmount(final Long accountId) {
this.actionName = "INTEREST";
this.entityName = "DEPOSITACCOUNT";
this.entityId = accountId;
this.href = "/depositaccounts/"+accountId;
this.href = "/depositaccounts/" + accountId;
return this;
}
}
public CommandWrapperBuilder renewDepositAccount(Long accountId) {
this.actionName = "RENEW";
public CommandWrapperBuilder renewDepositAccount(final Long accountId) {
this.actionName = "RENEW";
this.entityName = "DEPOSITACCOUNT";
this.entityId = accountId;
this.href = "/depositaccounts/"+accountId;
this.href = "/depositaccounts/" + accountId;
return this;
}
}
public CommandWrapperBuilder rejectDepositAccount(Long accountId) {
this.actionName = "REJECT";
public CommandWrapperBuilder rejectDepositAccount(final Long accountId) {
this.actionName = "REJECT";
this.entityName = "DEPOSITACCOUNT";
this.entityId = accountId;
this.href = "/depositaccounts/"+accountId;
this.href = "/depositaccounts/" + accountId;
return this;
}
}
public CommandWrapperBuilder withdrawDepositApplication(Long accountId) {
this.actionName = "WITHDRAW";
public CommandWrapperBuilder withdrawDepositApplication(final Long accountId) {
this.actionName = "WITHDRAW";
this.entityName = "DEPOSITACCOUNT";
this.entityId = accountId;
this.href = "/depositaccounts/"+accountId;
this.href = "/depositaccounts/" + accountId;
return this;
}
}
public CommandWrapperBuilder undoDepositApplicationApproval(Long accountId) {
this.actionName = "APPROVALUNDO";
public CommandWrapperBuilder undoDepositApplicationApproval(final Long accountId) {
this.actionName = "APPROVALUNDO";
this.entityName = "DEPOSITACCOUNT";
this.entityId = accountId;
this.href = "/depositaccounts/"+accountId;
this.href = "/depositaccounts/" + accountId;
return this;
}
}
public CommandWrapperBuilder createSavingProduct() {
this.actionName = "CREATE";
public CommandWrapperBuilder createSavingProduct() {
this.actionName = "CREATE";
this.entityName = "SAVINGSPRODUCT";
this.entityId = null;
this.href = "/savingproducts/template";
this.href = "/savingsproducts/template";
return this;
}
}
public CommandWrapperBuilder updateSavingProduct(Long productId) {
this.actionName = "UPDATE";
public CommandWrapperBuilder updateSavingProduct(final Long productId) {
this.actionName = "UPDATE";
this.entityName = "SAVINGSPRODUCT";
this.entityId = productId;
this.href = "/savingproducts/"+productId;
this.href = "/savingsproducts/" + productId;
return this;
}
}
public CommandWrapperBuilder deleteSavingProduct(Long productId) {
this.actionName = "DELETE";
public CommandWrapperBuilder deleteSavingProduct(final Long productId) {
this.actionName = "DELETE";
this.entityName = "SAVINGSPRODUCT";
this.entityId = productId;
this.href = "/savingproducts/"+productId;
this.href = "/savingsproducts/" + productId;
return this;
}
}
public CommandWrapperBuilder createSavingAccount() {
this.actionName = "CREATE";
public CommandWrapperBuilder createSavingsAccount() {
this.actionName = "CREATE";
this.entityName = "SAVINGSACCOUNT";
this.entityId = null;
this.href = "/savingaccounts/template";
this.href = "/savingsaccounts/template";
return this;
}
}
public CommandWrapperBuilder updateSavingAccount(Long accountId) {
this.actionName = "UPDATE";
public CommandWrapperBuilder updateSavingsAccount(final Long accountId) {
this.actionName = "UPDATE";
this.entityName = "SAVINGSACCOUNT";
this.entityId = accountId;
this.href = "/savingproducts/"+accountId;
this.href = "/savingsaccounts/" + accountId;
return this;
}
}
public CommandWrapperBuilder deleteSavingAccount(Long accountId) {
this.actionName = "DELETE";
public CommandWrapperBuilder deleteSavingsAccount(final Long accountId) {
this.actionName = "DELETE";
this.entityName = "SAVINGSACCOUNT";
this.entityId = accountId;
this.href = "/savingproducts/"+accountId;
this.href = "/savingsaccounts/" + accountId;
return this;
}
}
public CommandWrapperBuilder approveSavingAccountApplication(Long accountId) {
this.actionName = "APPROVE";
public CommandWrapperBuilder depositOfSavingAmount(final Long accountId) {
this.actionName = "DEPOSIT";
this.entityName = "SAVINGSACCOUNT";
this.entityId = accountId;
this.href = "/depositaccounts/"+accountId;
this.href = "/savingsaccounts/" + accountId;
return this;
}
}
public CommandWrapperBuilder depositOfSavingAmount(Long accountId) {
this.actionName = "DEPOSIT";
public CommandWrapperBuilder withdrawSavingAmount(final Long accountId) {
this.actionName = "WITHDRAWAL";
this.entityName = "SAVINGSACCOUNT";
this.entityId = accountId;
this.href = "/depositaccounts/"+accountId;
this.href = "/savingsaccounts/" + accountId;
return this;
}
}
public CommandWrapperBuilder withdrawSavingAmount(Long accountId) {
this.actionName = "WITHDRAWAL";
this.entityName = "SAVINGSACCOUNT";
this.entityId = accountId;
this.href = "/depositaccounts/"+accountId;
return this;
}
public CommandWrapperBuilder rejectSavingApplication(Long accountId) {
this.actionName = "REJECT";
this.entityName = "SAVINGSACCOUNT";
this.entityId = accountId;
this.href = "/depositaccounts/"+accountId;
return this;
}
public CommandWrapperBuilder withdrawSavingApplication(Long accountId) {
this.actionName = "WITHDRAW";
this.entityName = "SAVINGSACCOUNT";
this.entityId = accountId;
this.href = "/depositaccounts/"+accountId;
return this;
}
public CommandWrapperBuilder undoApprovalOfSavingApplication(Long accountId) {
this.actionName = "APPROVALUNDO";
this.entityName = "SAVINGSACCOUNT";
this.entityId = accountId;
this.href = "/depositaccounts/"+accountId;
return this;
}
public CommandWrapperBuilder createCalendar(final String supportedEntityType, final Long supportedEntityId) {
this.actionName = "CREATE";
this.entityName = "CALENDAR";
@@ -875,10 +844,11 @@ public class CommandWrapperBuilder {
this.href = "/" + supportedEntityType + "/" + supportedEntityId + "/calendars/" + calendarId;
return this;
}
public CommandWrapperBuilder createNote(final String entityName, final String resourceType, final Long resourceId) {
this.actionName = "CREATE";
this.entityName = entityName;//Note supports multiple resources. Note Permissions are set for each resource.
this.entityName = entityName;// Note supports multiple resources. Note
// Permissions are set for each resource.
this.supportedEntityType = resourceType;
this.supportedEntityId = resourceId;
this.href = "/" + resourceType + "/" + resourceId + "/notes/template";
@@ -887,7 +857,8 @@ public class CommandWrapperBuilder {
public CommandWrapperBuilder updateNote(final String entityName, final String resourceType, final Long resourceId, final Long noteId) {
this.actionName = "UPDATE";
this.entityName = entityName;//Note supports multiple resources. Note Permissions are set for each resource.
this.entityName = entityName;// Note supports multiple resources. Note
// Permissions are set for each resource.
this.entityId = noteId;
this.supportedEntityType = resourceType;
this.supportedEntityId = resourceId;
@@ -897,21 +868,22 @@ public class CommandWrapperBuilder {
public CommandWrapperBuilder deleteNote(final String entityName, final String resourceType, final Long resourceId, final Long noteId) {
this.actionName = "DELETE";
this.entityName = entityName;//Note supports multiple resources. Note Permissions are set for each resource.
this.entityName = entityName;// Note supports multiple resources. Note
// Permissions are set for each resource.
this.entityId = noteId;
this.supportedEntityType = resourceType;
this.supportedEntityId = resourceId;
this.href = "/" + resourceType + "/" + resourceId + "/calendars/" + noteId;
return this;
}
public CommandWrapperBuilder createGroup() {
this.actionName = "CREATE";
this.entityName = "GROUP";
this.href = "/groups/template";
return this;
}
public CommandWrapperBuilder updateGroup(final Long groupId) {
this.actionName = "UPDATE";
this.entityName = "GROUP";
@@ -375,33 +375,21 @@ public class SynchronousCommandProcessingService implements CommandProcessingSer
}
} else if (wrapper.isSavingProductResource()) {
if (wrapper.isCreate()) {
handler = applicationContext.getBean("createSavingProductCommandHandler", NewCommandSourceHandler.class);
handler = applicationContext.getBean("createSavingsProductCommandHandler", NewCommandSourceHandler.class);
} else if (wrapper.isUpdate()) {
handler = applicationContext.getBean("updateSavingProductCommandHandler", NewCommandSourceHandler.class);
handler = applicationContext.getBean("updateSavingsProductCommandHandler", NewCommandSourceHandler.class);
} else if (wrapper.isDelete()) {
handler = applicationContext.getBean("deleteSavingProductCommandHandler", NewCommandSourceHandler.class);
handler = applicationContext.getBean("deleteSavingsProductCommandHandler", NewCommandSourceHandler.class);
} else {
throw new UnsupportedCommandException(wrapper.commandName());
}
} else if (wrapper.isSavingAccountResource()) {
if (wrapper.isCreate()) {
handler = applicationContext.getBean("createSavingAccountCommandHandler", NewCommandSourceHandler.class);
handler = applicationContext.getBean("createSavingsAccountCommandHandler", NewCommandSourceHandler.class);
} else if (wrapper.isUpdate()) {
handler = applicationContext.getBean("updateSavingAccountCommandHandler", NewCommandSourceHandler.class);
handler = applicationContext.getBean("updateSavingsAccountCommandHandler", NewCommandSourceHandler.class);
} else if (wrapper.isDelete()) {
handler = applicationContext.getBean("deleteSavingAccountCommandHandler", NewCommandSourceHandler.class);
} else if (wrapper.isApprovalOfSaving()) {
handler = applicationContext.getBean("approveSavingAccountCommandHandler", NewCommandSourceHandler.class);
} else if (wrapper.isSavingAccountDeposit()) {
handler = applicationContext.getBean("depositSavingAmountCommandHandler", NewCommandSourceHandler.class);
} else if (wrapper.isRejectOfSavingAccount()) {
handler = applicationContext.getBean("rejectSavingAccountCommandHandler", NewCommandSourceHandler.class);
} else if (wrapper.isWithdrawSavingAmount()) {
handler = applicationContext.getBean("withdrawSavingAmountCommandHandler", NewCommandSourceHandler.class);
} else if (wrapper.isWithdrawOfSavingApplicatin()) {
handler = applicationContext.getBean("withdrawSavingApplicationCommandHandler", NewCommandSourceHandler.class);
} else if (wrapper.isUndoApprovalOfSavingAccount()) {
handler = applicationContext.getBean("undoApprovalSavingAccountCommandHandler", NewCommandSourceHandler.class);
handler = applicationContext.getBean("deleteSavingsAccountCommandHandler", NewCommandSourceHandler.class);
} else {
throw new UnsupportedCommandException(wrapper.commandName());
}
@@ -42,6 +42,7 @@ import org.springframework.jdbc.core.JdbcTemplate;
import org.springframework.jdbc.support.rowset.SqlRowSet;
import org.springframework.jdbc.support.rowset.SqlRowSetMetaData;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import com.google.gson.reflect.TypeToken;
@@ -103,6 +104,7 @@ public class ReadWriteNonCoreDataServiceImpl implements ReadWriteNonCoreDataServ
logger.error(dve.getMessage(), dve);
}
@Transactional
@Override
public void registerDatatable(final String dataTableName, final String applicationTableName) {
@@ -176,6 +178,7 @@ public class ReadWriteNonCoreDataServiceImpl implements ReadWriteNonCoreDataServ
}
@Transactional
@Override
public void deregisterDatatable(final String datatable) {
final String permissionList = "('CREATE_" + datatable + "', 'CREATE_" + datatable + "_CHECKER', 'READ_" + datatable + "', 'UPDATE_"
@@ -192,6 +195,7 @@ public class ReadWriteNonCoreDataServiceImpl implements ReadWriteNonCoreDataServ
this.jdbcTemplate.batchUpdate(sqlArray);
}
@Transactional
@Override
public void createNewDatatableEntry(final String dataTableName, final Long appTableId, final JsonCommand command) {
@@ -230,6 +234,7 @@ public class ReadWriteNonCoreDataServiceImpl implements ReadWriteNonCoreDataServ
}
}
@Transactional
@Override
public Map<String, Object> updateDatatableEntryOneToOne(final String datatable, final Long appTableId, final JsonCommand command) {
@@ -258,6 +263,7 @@ public class ReadWriteNonCoreDataServiceImpl implements ReadWriteNonCoreDataServ
return changes;
}
@Transactional
@Override
public Map<String, Object> updateDatatableEntryOneToMany(final String datatable, final Long appTableId, final Long datatableId,
final JsonCommand command) {
@@ -284,6 +290,7 @@ public class ReadWriteNonCoreDataServiceImpl implements ReadWriteNonCoreDataServ
return changes;
}
@Transactional
@Override
public void deleteDatatableEntries(final String datatable, final Long appTableId) {
@@ -295,6 +302,7 @@ public class ReadWriteNonCoreDataServiceImpl implements ReadWriteNonCoreDataServ
if (rowsDeleted < 1) { throw new DatatableNotFoundException(datatable, appTableId); }
}
@Transactional
@Override
public void deleteDatatableEntry(final String datatable, final Long appTableId, final Long datatableId) {
@@ -17,4 +17,8 @@ public class AccountNumberGeneratorFactory {
public AccountNumberGenerator determineLoanAccountNoGenerator(final Long loanId) {
return new ZeroPaddedAccountNumberGenerator(loanId, 9);
}
public AccountNumberGenerator determineSavingsAccountNoGenerator(final Long savingsAccountId) {
return new ZeroPaddedAccountNumberGenerator(savingsAccountId, 9);
}
}
@@ -37,7 +37,7 @@ import org.mifosplatform.portfolio.group.domain.Group;
import org.springframework.data.jpa.domain.AbstractPersistable;
@Entity
@Table(name = "m_client", uniqueConstraints = { @UniqueConstraint(columnNames = { "account_no" }, name = "account_no_UNIQUE")})
@Table(name = "m_client", uniqueConstraints = { @UniqueConstraint(columnNames = { "account_no" }, name = "account_no_UNIQUE") })
public class Client extends AbstractPersistable<Long> {
@Column(name = "account_no", length = 20, unique = true, nullable = false)
@@ -79,11 +79,11 @@ public class Client extends AbstractPersistable<Long> {
@ManyToMany
@JoinTable(name = "m_group_client", joinColumns = @JoinColumn(name = "client_id"), inverseJoinColumns = @JoinColumn(name = "group_id"))
private Set<Group> parentGroups;
@Transient
private boolean accountNumberRequiresAutoGeneration = false;
public static Client fromJson(final Office clientOffice, final Group clientParentGroup , final JsonCommand command) {
public static Client fromJson(final Office clientOffice, final Group clientParentGroup, final JsonCommand command) {
final String accountNo = command.stringValueOfParameterNamed("accountNo");
final String firstname = command.stringValueOfParameterNamed("firstname");
@@ -93,15 +93,15 @@ public class Client extends AbstractPersistable<Long> {
final LocalDate joiningDate = command.localDateValueOfParameterNamed("joinedDate");
final String externalId = command.stringValueOfParameterNamed("externalId");
return new Client(clientOffice, clientParentGroup ,accountNo, firstname, middlename, lastname, fullname, joiningDate, externalId);
return new Client(clientOffice, clientParentGroup, accountNo, firstname, middlename, lastname, fullname, joiningDate, externalId);
}
protected Client() {
}
private Client(final Office office, final Group clientParentGroup, final String accountNo, final String firstname, final String middlename, final String lastname,
final String fullname, final LocalDate openingDate, final String externalId) {
private Client(final Office office, final Group clientParentGroup, final String accountNo, final String firstname,
final String middlename, final String lastname, final String fullname, final LocalDate openingDate, final String externalId) {
if (StringUtils.isBlank(accountNo)) {
this.accountNumber = new RandomPasswordGenerator(19).generate();
this.accountNumberRequiresAutoGeneration = true;
@@ -139,11 +139,11 @@ public class Client extends AbstractPersistable<Long> {
this.fullname = null;
}
if(clientParentGroup != null){
if (clientParentGroup != null) {
this.parentGroups = new HashSet<Group>();
this.parentGroups.add(clientParentGroup);
}
deriveDisplayName();
validateNameParts();
}
@@ -152,7 +152,7 @@ public class Client extends AbstractPersistable<Long> {
return this.accountNumberRequiresAutoGeneration;
}
public void setAccountNumberRequiresAutoGeneration(boolean accountNumberRequiresAutoGeneration) {
public void setAccountNumberRequiresAutoGeneration(final boolean accountNumberRequiresAutoGeneration) {
this.accountNumberRequiresAutoGeneration = accountNumberRequiresAutoGeneration;
}
@@ -160,7 +160,7 @@ public class Client extends AbstractPersistable<Long> {
return identifier.equalsIgnoreCase(this.externalId);
}
public boolean identifiedBy(Long clientId) {
public boolean identifiedBy(final Long clientId) {
return getId().equals(clientId);
}
@@ -346,7 +346,11 @@ public class Client extends AbstractPersistable<Long> {
return imageKey;
}
public void setImageKey(String imageKey) {
public void setImageKey(final String imageKey) {
this.imageKey = imageKey;
}
public Long officeId() {
return this.office.getId();
}
}
@@ -216,31 +216,35 @@ public class ClientReadPlatformServiceImpl implements ClientReadPlatformService
List<ClientAccountSummaryData> preclosedDepositAccounts = new ArrayList<ClientAccountSummaryData>();
List<ClientAccountSummaryData> maturedDepositAccounts = new ArrayList<ClientAccountSummaryData>();
ClientDespoitAccountSummaryDataMapper depositAccountMapper = new ClientDespoitAccountSummaryDataMapper();
String depositAccountsSql = "select " + depositAccountMapper.schema() + " where da.client_id = ? and da.is_deleted=0";
List<ClientAccountSummaryData> depositAccountResults = this.jdbcTemplate.query(depositAccountsSql, depositAccountMapper,
new Object[] { clientId });
if (depositAccountResults != null) {
for (ClientAccountSummaryData row : depositAccountResults) {
if (row.accountStatusId() == 100) {
pendingApprovalDepositAccounts.add(row);
} else if (row.accountStatusId() == 300) {
approvedDepositAccounts.add(row);
} else if (row.accountStatusId() == 400) {
withdrawnByClientDespositAccounts.add(row);
} else if (row.accountStatusId() == 500) {
rejectedDepositAccounts.add(row);
} else if (row.accountStatusId() == 600) {
closedDepositAccounts.add(row);
} else if (row.accountStatusId() == 700) {
maturedDepositAccounts.add(row);
} else if (row.accountStatusId() == 800) {
preclosedDepositAccounts.add(row);
}
}
}
// ClientDespoitAccountSummaryDataMapper depositAccountMapper = new
// ClientDespoitAccountSummaryDataMapper();
//
// String depositAccountsSql = "select " +
// depositAccountMapper.schema() +
// " where da.client_id = ? and da.is_deleted=0";
// List<ClientAccountSummaryData> depositAccountResults =
// this.jdbcTemplate.query(depositAccountsSql, depositAccountMapper,
// new Object[] { clientId });
// if (depositAccountResults != null) {
// for (ClientAccountSummaryData row : depositAccountResults) {
//
// if (row.accountStatusId() == 100) {
// pendingApprovalDepositAccounts.add(row);
// } else if (row.accountStatusId() == 300) {
// approvedDepositAccounts.add(row);
// } else if (row.accountStatusId() == 400) {
// withdrawnByClientDespositAccounts.add(row);
// } else if (row.accountStatusId() == 500) {
// rejectedDepositAccounts.add(row);
// } else if (row.accountStatusId() == 600) {
// closedDepositAccounts.add(row);
// } else if (row.accountStatusId() == 700) {
// maturedDepositAccounts.add(row);
// } else if (row.accountStatusId() == 800) {
// preclosedDepositAccounts.add(row);
// }
// }
// }
List<ClientAccountSummaryData> pendingApprovalSavingAccounts = new ArrayList<ClientAccountSummaryData>();
List<ClientAccountSummaryData> approvedSavingAccounts = new ArrayList<ClientAccountSummaryData>();
@@ -248,25 +252,30 @@ public class ClientReadPlatformServiceImpl implements ClientReadPlatformService
List<ClientAccountSummaryData> rejectedSavingAccounts = new ArrayList<ClientAccountSummaryData>();
List<ClientAccountSummaryData> closedSavingAccounts = new ArrayList<ClientAccountSummaryData>();
ClientSavingAccountSummaryDataMapper clientSavingAccountSummaryDataMapper = new ClientSavingAccountSummaryDataMapper();
String savingAccountsSql = "select " + clientSavingAccountSummaryDataMapper.schema()
+ " where sa.client_id=? and sa.is_deleted=0";
List<ClientAccountSummaryData> savingAccountsResults = this.jdbcTemplate.query(savingAccountsSql,
clientSavingAccountSummaryDataMapper, new Object[] { clientId });
if (savingAccountsResults != null) {
for (ClientAccountSummaryData account : savingAccountsResults) {
if (account.accountStatusId() == 100)
pendingApprovalSavingAccounts.add(account);
else if (account.accountStatusId() == 300)
approvedSavingAccounts.add(account);
else if (account.accountStatusId() == 400)
withdrawnByClientSavingAccounts.add(account);
else if (account.accountStatusId() == 500)
rejectedSavingAccounts.add(account);
else if (account.accountStatusId() == 600) closedSavingAccounts.add(account);
}
}
// ClientSavingAccountSummaryDataMapper
// clientSavingAccountSummaryDataMapper = new
// ClientSavingAccountSummaryDataMapper();
// String savingAccountsSql = "select " +
// clientSavingAccountSummaryDataMapper.schema()
// + " where sa.client_id=? and sa.is_deleted=0";
// List<ClientAccountSummaryData> savingAccountsResults =
// this.jdbcTemplate.query(savingAccountsSql,
// clientSavingAccountSummaryDataMapper, new Object[] { clientId });
//
// if (savingAccountsResults != null) {
// for (ClientAccountSummaryData account : savingAccountsResults) {
// if (account.accountStatusId() == 100)
// pendingApprovalSavingAccounts.add(account);
// else if (account.accountStatusId() == 300)
// approvedSavingAccounts.add(account);
// else if (account.accountStatusId() == 400)
// withdrawnByClientSavingAccounts.add(account);
// else if (account.accountStatusId() == 500)
// rejectedSavingAccounts.add(account);
// else if (account.accountStatusId() == 600)
// closedSavingAccounts.add(account);
// }
// }
return new ClientAccountSummaryCollectionData(pendingApprovalLoans, awaitingDisbursalLoans, openLoans, closedLoans,
pendingApprovalDepositAccounts, approvedDepositAccounts, withdrawnByClientDespositAccounts, rejectedDepositAccounts,
@@ -320,30 +329,6 @@ public class ClientReadPlatformServiceImpl implements ClientReadPlatformService
}
}
private static final class ClientDespoitAccountSummaryDataMapper implements RowMapper<ClientAccountSummaryData> {
public String schema() {
StringBuilder accountsSummary = new StringBuilder("da.id as id, da.external_id as externalId,");
accountsSummary.append("da.product_id as productId, dp.name as productName,").append("da.status_enum as statusId ")
.append("from m_deposit_account da ").append("LEFT JOIN m_product_deposit AS dp ON dp.id = da.product_id ");
return accountsSummary.toString();
}
@Override
public ClientAccountSummaryData mapRow(final ResultSet rs, @SuppressWarnings("unused") final int rowNum) throws SQLException {
Long id = JdbcSupport.getLong(rs, "id");
String externalId = rs.getString("externalId");
Long productId = JdbcSupport.getLong(rs, "productId");
String productName = rs.getString("productName");
Integer accountStatusId = JdbcSupport.getInteger(rs, "statusId");
return new ClientAccountSummaryData(id, externalId, productId, productName, accountStatusId);
}
}
@Override
public ClientData retrieveClientByIdentifier(final Long identifierTypeId, final String identifierKey) {
try {
@@ -383,29 +368,4 @@ public class ClientReadPlatformServiceImpl implements ClientReadPlatformService
return ClientData.clientIdentifier(id, accountNo, firstname, middlename, lastname, fullname, displayName, officeId, officeName);
}
}
private static final class ClientSavingAccountSummaryDataMapper implements RowMapper<ClientAccountSummaryData> {
public String schema() {
StringBuilder accountsSummary = new StringBuilder("sa.id as id, sa.external_id as externalId,");
accountsSummary.append("sa.product_id as productId, sp.name as productName,").append("sa.status_enum as statusId ")
.append("from m_saving_account sa ").append("LEFT JOIN m_product_savings AS sp ON sp.id = sa.product_id ");
return accountsSummary.toString();
}
@Override
public ClientAccountSummaryData mapRow(final ResultSet rs, @SuppressWarnings("unused") final int rowNum) throws SQLException {
Long id = JdbcSupport.getLong(rs, "id");
String externalId = rs.getString("externalId");
Long productId = JdbcSupport.getLong(rs, "productId");
String productName = rs.getString("productName");
Integer accountStatusId = JdbcSupport.getInteger(rs, "statusId");
return new ClientAccountSummaryData(id, externalId, productId, productName, accountStatusId);
}
}
}
@@ -215,4 +215,7 @@ public class Group extends AbstractPersistable<Long> {
return this.office.identifiedBy(officeId);
}
}
public Long officeId() {
return this.office.getId();
}
}
@@ -191,8 +191,6 @@ public class LoansApiResource {
final boolean feeChargesOnly = false;
chargeOptions = this.chargeReadPlatformService.retrieveLoanApplicableCharges(feeChargesOnly);
// chargeTemplate =
// this.loanChargeReadPlatformService.retrieveLoanChargeTemplate();
}
LoanAccountData newLoanAccount = null;
@@ -441,7 +441,7 @@ public class Loan extends AbstractPersistable<Long> {
* @param suppliedTransactionDate
* @return
*/
private LoanTransaction getChargeAppliedTransaction(final LoanCharge loanCharge, LocalDate suppliedTransactionDate) {
private LoanTransaction getChargeAppliedTransaction(final LoanCharge loanCharge, final LocalDate suppliedTransactionDate) {
final Money chargeAmount = loanCharge.getAmount(getCurrency());
Money feeCharges = chargeAmount;
Money penaltyCharges = Money.zero(loanCurrency());
@@ -2165,9 +2165,9 @@ public class Loan extends AbstractPersistable<Long> {
public Long getOfficeId() {
Long officeId = null;
if (this.client != null) {
officeId = this.client.getOffice().getId();
officeId = this.client.officeId();
} else {
// officeId = this.group.getOffice().getId();
officeId = this.group.officeId();
}
return officeId;
}
@@ -13,10 +13,11 @@ import org.springframework.stereotype.Component;
@Component
public class AprCalculator {
public BigDecimal calculateFrom(PeriodFrequencyType interestPeriodFrequencyType, BigDecimal interestRatePerPeriod) {
public BigDecimal calculateFrom(final PeriodFrequencyType interestPeriodFrequencyType, final BigDecimal interestRatePerPeriod) {
BigDecimal defaultAnnualNominalInterestRate = BigDecimal.ZERO;
switch (interestPeriodFrequencyType) {
case DAYS:
defaultAnnualNominalInterestRate = interestRatePerPeriod.multiply(BigDecimal.valueOf(365));
break;
case WEEKS:
defaultAnnualNominalInterestRate = interestRatePerPeriod.multiply(BigDecimal.valueOf(52));
@@ -33,5 +34,4 @@ public class AprCalculator {
return defaultAnnualNominalInterestRate;
}
}
}
@@ -69,13 +69,14 @@ public class NotesApiResource {
@Produces({ MediaType.APPLICATION_JSON })
public String retrieveNotesByResource(@PathParam("resourceType") final String resourceType,
@PathParam("resourceId") final Long resourceId, @Context final UriInfo uriInfo) {
NoteType noteType = NoteType.fromApiUrl(resourceType);
if(noteType == null){ throw new NoteResourceNotSupportedException(resourceType); };
if (noteType == null) { throw new NoteResourceNotSupportedException(resourceType); }
;
this.context.authenticatedUser().validateHasReadPermission(getResourceNameForPermissions(noteType));
final Integer noteTypeId = noteType.getValue();
final Collection<NoteData> notes = this.readPlatformService.retrieveNotesByResource(resourceId, noteTypeId);
@@ -92,9 +93,10 @@ public class NotesApiResource {
@PathParam("noteId") final Long noteId, @Context final UriInfo uriInfo) {
NoteType noteType = NoteType.fromApiUrl(resourceType);
if(noteType == null){ throw new NoteResourceNotSupportedException(resourceType); };
if (noteType == null) { throw new NoteResourceNotSupportedException(resourceType); }
;
this.context.authenticatedUser().validateHasReadPermission(getResourceNameForPermissions(noteType));
final Integer noteTypeId = noteType.getValue();
@@ -112,9 +114,10 @@ public class NotesApiResource {
final String apiRequestBodyAsJson) {
NoteType noteType = NoteType.fromApiUrl(resourceType);
if(noteType == null){ throw new NoteResourceNotSupportedException(resourceType); };
if (noteType == null) { throw new NoteResourceNotSupportedException(resourceType); }
;
final String resourceNameForPermissions = getResourceNameForPermissions(noteType);
final CommandWrapper commandRequest = new CommandWrapperBuilder().createNote(resourceNameForPermissions, resourceType, resourceId)
.withJson(apiRequestBodyAsJson).build();
@@ -130,20 +133,22 @@ public class NotesApiResource {
@Produces({ MediaType.APPLICATION_JSON })
public String updateNote(@PathParam("resourceType") final String resourceType, @PathParam("resourceId") final Long resourceId,
@PathParam("noteId") final Long noteId, final String apiRequestBodyAsJson) {
NoteType noteType = NoteType.fromApiUrl(resourceType);
if(noteType == null){ throw new NoteResourceNotSupportedException(resourceType); };
if (noteType == null) { throw new NoteResourceNotSupportedException(resourceType); }
;
final String resourceNameForPermissions = getResourceNameForPermissions(noteType);
final CommandWrapper commandRequest = new CommandWrapperBuilder().updateNote(resourceNameForPermissions, resourceType, resourceId, noteId).withJson(apiRequestBodyAsJson).build();
final CommandWrapper commandRequest = new CommandWrapperBuilder()
.updateNote(resourceNameForPermissions, resourceType, resourceId, noteId).withJson(apiRequestBodyAsJson).build();
final CommandProcessingResult result = this.commandsSourceWritePlatformService.logCommandSource(commandRequest);
return this.toApiJsonSerializer.serialize(result);
}
@DELETE
@Path("{noteId}")
@Consumes({ MediaType.APPLICATION_JSON })
@@ -152,42 +157,41 @@ public class NotesApiResource {
@PathParam("noteId") final Long noteId) {
NoteType noteType = NoteType.fromApiUrl(resourceType);
if(noteType == null){ throw new NoteResourceNotSupportedException(resourceType); };
if (noteType == null) { throw new NoteResourceNotSupportedException(resourceType); }
;
final String resourceNameForPermissions = getResourceNameForPermissions(noteType);
final CommandWrapper commandRequest = new CommandWrapperBuilder().deleteNote(resourceNameForPermissions, resourceType, resourceId, noteId).build();
final CommandWrapper commandRequest = new CommandWrapperBuilder().deleteNote(resourceNameForPermissions, resourceType, resourceId,
noteId).build();
final CommandProcessingResult result = this.commandsSourceWritePlatformService.logCommandSource(commandRequest);
return this.toApiJsonSerializer.serialize(result);
}
private String getResourceNameForPermissions(NoteType type){
private String getResourceNameForPermissions(final NoteType type) {
String resourceNameForPermissions = "INVALIDNOTE";
switch(type){
switch (type) {
case CLIENT:
resourceNameForPermissions = "CLIENTNOTE";
break;
break;
case LOAN:
resourceNameForPermissions = "LOANNOTE";
break;
break;
case LOAN_TRANSACTION:
resourceNameForPermissions = "LOANTRANSACTIONNOTE";
break;
case DEPOSIT:
resourceNameForPermissions = "DEPOSITNOTE";
break;
case SAVING:
break;
case SAVING_ACCOUNT:
resourceNameForPermissions = "SAVINGNOTE";
break;
break;
case GROUP:
resourceNameForPermissions = "GROUPNOTE";
break;
break;
}
return resourceNameForPermissions;
}
@@ -21,8 +21,6 @@ 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.savingsaccount.domain.SavingAccount;
import org.mifosplatform.portfolio.savingsdepositaccount.domain.DepositAccount;
import org.mifosplatform.useradministration.domain.AppUser;
@Entity
@@ -55,15 +53,10 @@ public class Note extends AbstractAuditableCustom<AppUser, Long> {
@Column(name = "note_type_enum")
private final Integer noteTypeId;
@SuppressWarnings("unused")
@ManyToOne
@JoinColumn(name = "deposit_account_id", nullable = true)
private DepositAccount depositAccount;
@SuppressWarnings("unused")
@ManyToOne
@JoinColumn(name = "saving_account_id", nullable = true)
private SavingAccount savingAccount;
// @SuppressWarnings("unused")
// @ManyToOne
// @JoinColumn(name = "saving_account_id", nullable = true)
// private SavingAccount savingAccount;
public static Note clientNoteFromJson(final Client client, final JsonCommand command) {
final String note = command.stringValueOfParameterNamed("note");
@@ -83,13 +76,10 @@ public class Note extends AbstractAuditableCustom<AppUser, Long> {
return new Note(loan, loanTransaction, note);
}
public static Note depositNote(final DepositAccount account, final String note) {
return new Note(account, note);
}
public static Note savingNote(final SavingAccount account, final String note) {
return new Note(account, note);
}
// public static Note savingNote(final SavingAccount account, final String
// note) {
// return new Note(account, note);
// }
private Note(final Client client, final String note) {
this.client = client;
@@ -128,19 +118,12 @@ public class Note extends AbstractAuditableCustom<AppUser, Long> {
this.noteTypeId = null;
}
public Note(final DepositAccount account, final String note) {
this.depositAccount = account;
this.client = account.client();
this.note = note;
this.noteTypeId = NoteType.DEPOSIT.getValue();
}
public Note(final SavingAccount account, final String note) {
this.savingAccount = account;
this.client = account.getClient();
this.note = note;
this.noteTypeId = NoteType.SAVING.getValue();
}
// 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 Map<String, Object> update(final JsonCommand command) {
final Map<String, Object> actualChanges = new LinkedHashMap<String, Object>(7);
@@ -24,7 +24,7 @@ public interface NoteRepository extends JpaRepository<Note, Long>, JpaSpecificat
Note findByLoanTransactionIdAndId(Long loanTransactionId, Long id);
Note findByDepositAccountIdAndId(Long depositAccountId, Long id);
// Note findByDepositAccountIdAndId(Long depositAccountId, Long id);
Note findBySavingAccountIdAndId(Long savingAccountId, Long id);
// Note findBySavingAccountIdAndId(Long savingAccountId, Long id);
}
@@ -5,9 +5,11 @@ import java.util.Map;
public enum NoteType {
CLIENT(100, "noteType.client", "clients"), LOAN(200, "noteType.loan", "loans"), LOAN_TRANSACTION(300, "noteType.loan.transaction",
"loanTransactions"), DEPOSIT(400, "noteType.deposit", "deposits"), SAVING(500, "noteType.saving", "savings"), GROUP(600,
"noteType.group", "groups");
CLIENT(100, "noteType.client", "clients"), //
LOAN(200, "noteType.loan", "loans"), //
LOAN_TRANSACTION(300, "noteType.loan.transaction", "loanTransactions"), //
SAVING_ACCOUNT(500, "noteType.saving", "savings"), //
GROUP(600, "noteType.group", "groups");
private Integer value;
private String code;
@@ -26,11 +26,8 @@ public class NoteEnumerations {
case LOAN_TRANSACTION:
optionData = new EnumOptionData(type.getValue().longValue(), type.getCode(), "Loan transaction note");
break;
case DEPOSIT:
optionData = new EnumOptionData(type.getValue().longValue(), type.getCode(), "Deposit transaction note");
break;
case SAVING:
optionData = new EnumOptionData(type.getValue().longValue(), type.getCode(), "Saving transaction note");
case SAVING_ACCOUNT:
optionData = new EnumOptionData(type.getValue().longValue(), type.getCode(), "Saving account note");
break;
case GROUP:
optionData = new EnumOptionData(type.getValue().longValue(), type.getCode(), "Group note");
@@ -41,5 +38,5 @@ public class NoteEnumerations {
}
return optionData;
}
}
@@ -31,8 +31,8 @@ public class NoteReadPlatformServiceImpl implements NoteReadPlatformService {
private static final class NoteMapper implements RowMapper<NoteData> {
public String schema() {
return " select n.id as id, n.client_id as clientId, n.group_id as groupId, n.loan_id as loanId, n.loan_transaction_id as transactionId, n.deposit_account_id as depositAccountId, "
+ " n.saving_account_id as savingAccountId, n.note_type_enum as noteTypeEnum, n.note as note, n.created_date as createdDate, n.createdby_id as createdById, "
return " select n.id as id, n.client_id as clientId, n.group_id as groupId, n.loan_id as loanId, n.loan_transaction_id as transactionId, "
+ " n.note_type_enum as noteTypeEnum, n.note as note, n.created_date as createdDate, n.createdby_id as createdById, "
+ " cb.username as createdBy, n.lastmodified_date as lastModifiedDate, n.lastmodifiedby_id as lastModifiedById, mb.username as modifiedBy "
+ " from m_note n left join m_appuser cb on cb.id=n.createdby_id left join m_appuser mb on mb.id=n.lastmodifiedby_id ";
}
@@ -45,8 +45,10 @@ public class NoteReadPlatformServiceImpl implements NoteReadPlatformService {
final Long groupId = JdbcSupport.getLong(rs, "groupId");
final Long loanId = JdbcSupport.getLong(rs, "loanId");
final Long transactionId = JdbcSupport.getLong(rs, "transactionId");
final Long depositAccountId = JdbcSupport.getLong(rs, "depositAccountId");
final Long savingAccountId = JdbcSupport.getLong(rs, "savingAccountId");
// final Long depositAccountId = JdbcSupport.getLong(rs,
// "depositAccountId");
// final Long savingAccountId = JdbcSupport.getLong(rs,
// "savingAccountId");
final Integer noteTypeId = JdbcSupport.getInteger(rs, "noteTypeEnum");
final EnumOptionData noteType = NoteEnumerations.noteType(noteTypeId);
final String note = rs.getString("note");
@@ -56,7 +58,7 @@ public class NoteReadPlatformServiceImpl implements NoteReadPlatformService {
final Long lastModifiedById = JdbcSupport.getLong(rs, "lastModifiedById");
final String createdByUsername = rs.getString("createdBy");
final String updatedByUsername = rs.getString("modifiedBy");
return new NoteData(id, clientId, groupId, loanId, transactionId, depositAccountId, savingAccountId, noteType, note,
return new NoteData(id, clientId, groupId, loanId, transactionId, null, null, noteType, note,
createdDate, createdById, createdByUsername, lastModifiedDate, lastModifiedById, updatedByUsername);
}
}
@@ -84,7 +86,7 @@ public class NoteReadPlatformServiceImpl implements NoteReadPlatformService {
final NoteType noteType = NoteType.fromInt(noteTypeId);
final NoteMapper rm = new NoteMapper();
String conditionSql = getResourceCondition(noteType);
final String sql = rm.schema() + " where " + conditionSql + " order by n.created_date DESC";
return this.jdbcTemplate.query(sql, rm, new Object[] { resourceId });
@@ -102,10 +104,7 @@ public class NoteReadPlatformServiceImpl implements NoteReadPlatformService {
case LOAN_TRANSACTION:
conditionSql = " n.loan_transaction_id = ? ";
break;
case DEPOSIT:
conditionSql = " n.deposit_account_id = ? ";
break;
case SAVING:
case SAVING_ACCOUNT:
conditionSql = " n.saving_account_id = ? ";
break;
case GROUP:
@@ -28,12 +28,6 @@ import org.mifosplatform.portfolio.note.domain.NoteType;
import org.mifosplatform.portfolio.note.exception.NoteNotFoundException;
import org.mifosplatform.portfolio.note.exception.NoteResourceNotSupportedException;
import org.mifosplatform.portfolio.note.serialization.NoteCommandFromApiJsonDeserializer;
import org.mifosplatform.portfolio.savingsaccount.domain.SavingAccount;
import org.mifosplatform.portfolio.savingsaccount.domain.SavingAccountRepository;
import org.mifosplatform.portfolio.savingsaccount.exception.SavingAccountNotFoundException;
import org.mifosplatform.portfolio.savingsdepositaccount.domain.DepositAccount;
import org.mifosplatform.portfolio.savingsdepositaccount.domain.DepositAccountRepository;
import org.mifosplatform.portfolio.savingsdepositaccount.exception.DepositAccountNotFoundException;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
@@ -43,22 +37,21 @@ public class NoteWritePlatformServiceJpaRepositoryImpl implements NoteWritePlatf
private final NoteRepository noteRepository;
private final ClientRepository clientRepository;
private final GroupRepository groupRepository;
private final DepositAccountRepository depositAccountRepository;
private final SavingAccountRepository savingAccountRepository;
// private final SavingAccountRepository savingAccountRepository;
private final LoanRepository loanRepository;
private final LoanTransactionRepository loanTransactionRepository;
private final NoteCommandFromApiJsonDeserializer fromApiJsonDeserializer;
@Autowired
public NoteWritePlatformServiceJpaRepositoryImpl(final NoteRepository noteRepository, final ClientRepository clientRepository,
final GroupRepository groupRepository, final DepositAccountRepository depositAccountRepository,
final SavingAccountRepository savingAccountRepository, final LoanRepository loanRepository,
final LoanTransactionRepository loanTransactionRepository, final NoteCommandFromApiJsonDeserializer fromApiJsonDeserializer) {
final GroupRepository groupRepository,
// final SavingAccountRepository savingAccountRepository,
final LoanRepository loanRepository, final LoanTransactionRepository loanTransactionRepository,
final NoteCommandFromApiJsonDeserializer fromApiJsonDeserializer) {
this.noteRepository = noteRepository;
this.clientRepository = clientRepository;
this.groupRepository = groupRepository;
this.depositAccountRepository = depositAccountRepository;
this.savingAccountRepository = savingAccountRepository;
// this.savingAccountRepository = savingAccountRepository;
this.loanRepository = loanRepository;
this.loanTransactionRepository = loanTransactionRepository;
this.fromApiJsonDeserializer = fromApiJsonDeserializer;
@@ -145,41 +138,26 @@ public class NoteWritePlatformServiceJpaRepositoryImpl implements NoteWritePlatf
.build();
}
private CommandProcessingResult createDepositAccountNote(final JsonCommand command) {
final Long resourceId = command.getSupportedEntityId();
final DepositAccount depositAccount = this.depositAccountRepository.findOne(resourceId);
if (depositAccount == null) { throw new DepositAccountNotFoundException(resourceId); }
final String note = command.stringValueOfParameterNamed("note");
final Note newNote = Note.depositNote(depositAccount, note);
this.noteRepository.save(newNote);
return new CommandProcessingResultBuilder() //
.withCommandId(command.commandId()) //
.withEntityId(newNote.getId()) //
.withClientId(depositAccount.client().getId()).withOfficeId(depositAccount.client().getOffice().getId()).build();
}
private CommandProcessingResult createSavingAccountNote(final JsonCommand command) {
final Long resourceId = command.getSupportedEntityId();
final SavingAccount savingAccount = this.savingAccountRepository.findOne(resourceId);
if (savingAccount == null) { throw new SavingAccountNotFoundException(resourceId); }
final String note = command.stringValueOfParameterNamed("note");
final Note newNote = Note.savingNote(savingAccount, note);
this.noteRepository.save(newNote);
return new CommandProcessingResultBuilder() //
.withCommandId(command.commandId()) //
.withEntityId(newNote.getId()) //
.withClientId(savingAccount.getClient().getId()).withOfficeId(savingAccount.getClient().getOffice().getId()).build();
}
// private CommandProcessingResult createSavingAccountNote(final JsonCommand
// command) {
//
// final Long resourceId = command.getSupportedEntityId();
//
// final SavingAccount savingAccount =
// this.savingAccountRepository.findOne(resourceId);
// if (savingAccount == null) { throw new
// SavingAccountNotFoundException(resourceId); }
//
// final String note = command.stringValueOfParameterNamed("note");
// final Note newNote = Note.savingNote(savingAccount, note);
//
// this.noteRepository.save(newNote);
//
// return new CommandProcessingResultBuilder() //
// .withCommandId(command.commandId()) //
// .withEntityId(newNote.getId()) //
// .withClientId(savingAccount.getClient().getId()).withOfficeId(savingAccount.getClient().getOffice().getId()).build();
// }
@Override
public CommandProcessingResult createNote(final JsonCommand command) {
@@ -192,9 +170,6 @@ public class NoteWritePlatformServiceJpaRepositoryImpl implements NoteWritePlatf
case CLIENT: {
return createClientNote(command);
}
case DEPOSIT: {
return createDepositAccountNote(command);
}
case GROUP: {
return createGroupNote(command);
}
@@ -204,9 +179,9 @@ public class NoteWritePlatformServiceJpaRepositoryImpl implements NoteWritePlatf
case LOAN_TRANSACTION: {
return createLoanTransactionNote(command);
}
case SAVING: {
return createSavingAccountNote(command);
}
// case SAVING_ACCOUNT: {
// return createSavingAccountNote(command);
// }
default:
throw new NoteResourceNotSupportedException(resourceUrl);
}
@@ -236,40 +211,10 @@ public class NoteWritePlatformServiceJpaRepositoryImpl implements NoteWritePlatf
return new CommandProcessingResultBuilder() //
.withCommandId(command.commandId()) //
.withEntityId(noteForUpdate.getId()) //
.withClientId(client.getId()).withOfficeId(client.getOffice().getId())
.with(changes)
.build();
.withClientId(client.getId()).withOfficeId(client.getOffice().getId()).with(changes).build();
}
private CommandProcessingResult updateDepositAccountNote(final JsonCommand command) {
final Long resourceId = command.getSupportedEntityId();
final Long noteId = command.entityId();
final String resourceUrl = command.getSupportedEntityType();
final NoteType type = NoteType.fromApiUrl(resourceUrl);
final DepositAccount depositAccount = this.depositAccountRepository.findOne(resourceId);
if (depositAccount == null) { throw new DepositAccountNotFoundException(resourceId); }
final Note noteForUpdate = this.noteRepository.findByDepositAccountIdAndId(resourceId, noteId);
if (noteForUpdate == null) { throw new NoteNotFoundException(noteId, resourceId, type.name().toLowerCase()); }
final Map<String, Object> changes = noteForUpdate.update(command);
if (!changes.isEmpty()) {
this.noteRepository.saveAndFlush(noteForUpdate);
}
return new CommandProcessingResultBuilder() //
.withCommandId(command.commandId()) //
.withEntityId(noteForUpdate.getId()) //
.withClientId(depositAccount.client().getId()).withOfficeId(depositAccount.client().getOffice().getId())
.with(changes)
.build();
}
private CommandProcessingResult updateGroupNote(final JsonCommand command) {
final Long resourceId = command.getSupportedEntityId();
@@ -293,9 +238,7 @@ public class NoteWritePlatformServiceJpaRepositoryImpl implements NoteWritePlatf
return new CommandProcessingResultBuilder() //
.withCommandId(command.commandId()) //
.withEntityId(noteForUpdate.getId()) //
.withGroupId(group.getId()).withOfficeId(group.getOfficeId())
.with(changes)
.build();
.withGroupId(group.getId()).withOfficeId(group.getOfficeId()).with(changes).build();
}
private CommandProcessingResult updateLoanNote(final JsonCommand command) {
@@ -320,8 +263,7 @@ public class NoteWritePlatformServiceJpaRepositoryImpl implements NoteWritePlatf
return new CommandProcessingResultBuilder().withCommandId(command.commandId()).withEntityId(noteForUpdate.getId())
.withClientId(loan.getClientId()).withLoanId(loan.getId()).withGroupId(loan.getGroupId()).withOfficeId(loan.getOfficeId())
.with(changes)
.build();
.with(changes).build();
}
private CommandProcessingResult updateLoanTransactionNote(final JsonCommand command) {
@@ -348,38 +290,44 @@ public class NoteWritePlatformServiceJpaRepositoryImpl implements NoteWritePlatf
return new CommandProcessingResultBuilder().withCommandId(command.commandId()).withEntityId(noteForUpdate.getId())
.withClientId(loan.getClientId()).withLoanId(loan.getId()).withGroupId(loan.getGroupId()).withOfficeId(loan.getOfficeId())
.with(changes)
.build();
.with(changes).build();
}
private CommandProcessingResult updateSavingAccountNote(final JsonCommand command) {
final Long resourceId = command.getSupportedEntityId();
final Long noteId = command.entityId();
final String resourceUrl = command.getSupportedEntityType();
final NoteType type = NoteType.fromApiUrl(resourceUrl);
final SavingAccount savingAccount = this.savingAccountRepository.findOne(resourceId);
if (savingAccount == null) { throw new SavingAccountNotFoundException(resourceId); }
final Note noteForUpdate = this.noteRepository.findBySavingAccountIdAndId(resourceId, noteId);
if (noteForUpdate == null) { throw new NoteNotFoundException(noteId, resourceId, type.name().toLowerCase()); }
final Map<String, Object> changes = noteForUpdate.update(command);
if (!changes.isEmpty()) {
this.noteRepository.saveAndFlush(noteForUpdate);
}
return new CommandProcessingResultBuilder() //
.withCommandId(command.commandId()) //
.withEntityId(noteForUpdate.getId()) //
.withClientId(savingAccount.getClient().getId()).withOfficeId(savingAccount.getClient().getOffice().getId())
.with(changes)
.build();
}
// private CommandProcessingResult updateSavingAccountNote(final JsonCommand
// command) {
//
// final Long resourceId = command.getSupportedEntityId();
// final Long noteId = command.entityId();
// final String resourceUrl = command.getSupportedEntityType();
//
// final NoteType type = NoteType.fromApiUrl(resourceUrl);
//
// final SavingAccount savingAccount =
// this.savingAccountRepository.findOne(resourceId);
// if (savingAccount == null) { throw new
// SavingAccountNotFoundException(resourceId); }
//
// final Note noteForUpdate =
// this.noteRepository.findBySavingAccountIdAndId(resourceId, noteId);
//
// if (noteForUpdate == null) { throw new NoteNotFoundException(noteId,
// resourceId, type.name().toLowerCase()); }
//
// final Map<String, Object> changes = noteForUpdate.update(command);
//
// if (!changes.isEmpty()) {
// this.noteRepository.saveAndFlush(noteForUpdate);
// }
//
// return new CommandProcessingResultBuilder()
// //
// .withCommandId(command.commandId())
// //
// .withEntityId(noteForUpdate.getId())
// //
// .withClientId(savingAccount.getClient().getId()).withOfficeId(savingAccount.getClient().getOffice().getId()).with(changes)
// .build();
// }
@Override
public CommandProcessingResult updateNote(final JsonCommand command) {
@@ -393,9 +341,6 @@ public class NoteWritePlatformServiceJpaRepositoryImpl implements NoteWritePlatf
case CLIENT: {
return updateClientNote(command);
}
case DEPOSIT: {
return updateDepositAccountNote(command);
}
case GROUP: {
return updateGroupNote(command);
}
@@ -405,9 +350,9 @@ public class NoteWritePlatformServiceJpaRepositoryImpl implements NoteWritePlatf
case LOAN_TRANSACTION: {
return updateLoanTransactionNote(command);
}
case SAVING: {
return updateSavingAccountNote(command);
}
// case SAVING_ACCOUNT: {
// return updateSavingAccountNote(command);
// }
default:
throw new NoteResourceNotSupportedException(resourceUrl);
}
@@ -436,10 +381,6 @@ public class NoteWritePlatformServiceJpaRepositoryImpl implements NoteWritePlatf
noteForUpdate = this.noteRepository.findByClientIdAndId(resourceId, noteId);
}
break;
case DEPOSIT: {
noteForUpdate = this.noteRepository.findByDepositAccountIdAndId(resourceId, noteId);
}
break;
case GROUP: {
noteForUpdate = this.noteRepository.findByGroupIdAndId(resourceId, noteId);
}
@@ -452,9 +393,12 @@ public class NoteWritePlatformServiceJpaRepositoryImpl implements NoteWritePlatf
noteForUpdate = this.noteRepository.findByLoanTransactionIdAndId(resourceId, noteId);
}
break;
case SAVING: {
noteForUpdate = this.noteRepository.findBySavingAccountIdAndId(resourceId, noteId);
}
// case SAVING_ACCOUNT: {
// noteForUpdate =
// this.noteRepository.findBySavingAccountIdAndId(resourceId, noteId);
// }
// break;
case SAVING_ACCOUNT:
break;
}
if (noteForUpdate == null) { throw new NoteNotFoundException(noteId, resourceId, type.name().toLowerCase()); }
@@ -0,0 +1,168 @@
/**
* 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.api;
import java.util.Collection;
import javax.ws.rs.Consumes;
import javax.ws.rs.DELETE;
import javax.ws.rs.GET;
import javax.ws.rs.POST;
import javax.ws.rs.PUT;
import javax.ws.rs.Path;
import javax.ws.rs.PathParam;
import javax.ws.rs.Produces;
import javax.ws.rs.QueryParam;
import javax.ws.rs.core.Context;
import javax.ws.rs.core.MediaType;
import javax.ws.rs.core.UriInfo;
import org.mifosplatform.commands.domain.CommandWrapper;
import org.mifosplatform.commands.service.CommandWrapperBuilder;
import org.mifosplatform.commands.service.PortfolioCommandSourceWritePlatformService;
import org.mifosplatform.infrastructure.core.api.ApiRequestParameterHelper;
import org.mifosplatform.infrastructure.core.data.CommandProcessingResult;
import org.mifosplatform.infrastructure.core.data.EnumOptionData;
import org.mifosplatform.infrastructure.core.serialization.ApiRequestJsonSerializationSettings;
import org.mifosplatform.infrastructure.core.serialization.DefaultToApiJsonSerializer;
import org.mifosplatform.infrastructure.security.service.PlatformSecurityContext;
import org.mifosplatform.portfolio.savings.data.SavingsAccountData;
import org.mifosplatform.portfolio.savings.data.SavingsProductData;
import org.mifosplatform.portfolio.savings.service.SavingsAccountReadPlatformService;
import org.mifosplatform.portfolio.savings.service.SavingsDropdownReadPlatformService;
import org.mifosplatform.portfolio.savings.service.SavingsProductReadPlatformService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Scope;
import org.springframework.stereotype.Component;
@Path("/savingsaccounts")
@Component
@Scope("singleton")
public class SavingsAccountsApiResource {
private final SavingsAccountReadPlatformService savingsAccountReadPlatformService;
private final SavingsProductReadPlatformService savingsProductReadPlatformService;
private final SavingsDropdownReadPlatformService dropdownReadPlatformService;
private final PlatformSecurityContext context;
private final DefaultToApiJsonSerializer<SavingsAccountData> toApiJsonSerializer;
private final PortfolioCommandSourceWritePlatformService commandsSourceWritePlatformService;
private final ApiRequestParameterHelper apiRequestParameterHelper;
@Autowired
public SavingsAccountsApiResource(final SavingsAccountReadPlatformService savingsAccountReadPlatformService,
final SavingsProductReadPlatformService savingsProductReadPlatformService,
final SavingsDropdownReadPlatformService dropdownReadPlatformService, final PlatformSecurityContext context,
final DefaultToApiJsonSerializer<SavingsAccountData> toApiJsonSerializer,
final PortfolioCommandSourceWritePlatformService commandsSourceWritePlatformService,
final ApiRequestParameterHelper apiRequestParameterHelper) {
this.savingsAccountReadPlatformService = savingsAccountReadPlatformService;
this.savingsProductReadPlatformService = savingsProductReadPlatformService;
this.dropdownReadPlatformService = dropdownReadPlatformService;
this.context = context;
this.toApiJsonSerializer = toApiJsonSerializer;
this.commandsSourceWritePlatformService = commandsSourceWritePlatformService;
this.apiRequestParameterHelper = apiRequestParameterHelper;
}
@POST
@Consumes({ MediaType.APPLICATION_JSON })
@Produces({ MediaType.APPLICATION_JSON })
public String create(final String apiRequestBodyAsJson) {
final CommandWrapper commandRequest = new CommandWrapperBuilder().createSavingsAccount().withJson(apiRequestBodyAsJson).build();
final CommandProcessingResult result = this.commandsSourceWritePlatformService.logCommandSource(commandRequest);
return this.toApiJsonSerializer.serialize(result);
}
@PUT
@Path("{accountId}")
@Consumes({ MediaType.APPLICATION_JSON })
@Produces({ MediaType.APPLICATION_JSON })
public String update(@PathParam("accountId") final Long accountId, final String apiRequestBodyAsJson) {
final CommandWrapper commandRequest = new CommandWrapperBuilder().updateSavingsAccount(accountId).withJson(apiRequestBodyAsJson)
.build();
final CommandProcessingResult result = this.commandsSourceWritePlatformService.logCommandSource(commandRequest);
return this.toApiJsonSerializer.serialize(result);
}
@GET
@Consumes({ MediaType.APPLICATION_JSON })
@Produces({ MediaType.APPLICATION_JSON })
public String retrieveAll(@Context final UriInfo uriInfo) {
context.authenticatedUser().validateHasReadPermission(SavingsApiConstants.SAVINGS_ACCOUNT_RESOURCE_NAME);
final Collection<SavingsAccountData> products = this.savingsAccountReadPlatformService.retrieveAll();
final ApiRequestJsonSerializationSettings settings = apiRequestParameterHelper.process(uriInfo.getQueryParameters());
return this.toApiJsonSerializer.serialize(settings, products, SavingsApiConstants.SAVINGS_ACCOUNT_RESPONSE_DATA_PARAMETERS);
}
@GET
@Path("{accountId}")
@Consumes({ MediaType.APPLICATION_JSON })
@Produces({ MediaType.APPLICATION_JSON })
public String retrieveOne(@PathParam("accountId") final Long accountId, @Context final UriInfo uriInfo) {
context.authenticatedUser().validateHasReadPermission(SavingsApiConstants.SAVINGS_ACCOUNT_RESOURCE_NAME);
SavingsAccountData savingsAccount = this.savingsAccountReadPlatformService.retrieveOne(accountId);
final ApiRequestJsonSerializationSettings settings = apiRequestParameterHelper.process(uriInfo.getQueryParameters());
if (settings.isTemplate()) {
savingsAccount = populateTemplateOptions(savingsAccount);
}
return this.toApiJsonSerializer.serialize(settings, savingsAccount, SavingsApiConstants.SAVINGS_ACCOUNT_RESPONSE_DATA_PARAMETERS);
}
private SavingsAccountData populateTemplateOptions(final SavingsAccountData savingsAccount) {
final Collection<SavingsProductData> productOptions = this.savingsProductReadPlatformService.retrieveAllForLookup();
final Collection<EnumOptionData> interestRatePeriodFrequencyTypeOptions = this.dropdownReadPlatformService
.retrieveInterestRatePeriodFrequencyTypeOptions();
final Collection<EnumOptionData> lockinPeriodFrequencyTypeOptions = this.dropdownReadPlatformService
.retrieveLockinPeriodFrequencyTypeOptions();
return SavingsAccountData.withTemplateOptions(savingsAccount, productOptions, interestRatePeriodFrequencyTypeOptions,
lockinPeriodFrequencyTypeOptions);
}
@GET
@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) {
context.authenticatedUser().validateHasReadPermission(SavingsApiConstants.SAVINGS_ACCOUNT_RESOURCE_NAME);
final SavingsAccountData savingsAccount = this.savingsAccountReadPlatformService.retrieveTemplate(clientId, groupId, productId);
final ApiRequestJsonSerializationSettings settings = apiRequestParameterHelper.process(uriInfo.getQueryParameters());
return this.toApiJsonSerializer.serialize(settings, savingsAccount, SavingsApiConstants.SAVINGS_ACCOUNT_RESPONSE_DATA_PARAMETERS);
}
@DELETE
@Path("{accountId}")
@Consumes({ MediaType.APPLICATION_JSON })
@Produces({ MediaType.APPLICATION_JSON })
public String delete(@PathParam("accountId") final Long accountId) {
final CommandWrapper commandRequest = new CommandWrapperBuilder().deleteSavingsAccount(accountId).build();
final CommandProcessingResult result = this.commandsSourceWritePlatformService.logCommandSource(commandRequest);
return this.toApiJsonSerializer.serialize(result);
}
}
@@ -0,0 +1,63 @@
package org.mifosplatform.portfolio.savings.api;
import java.util.Arrays;
import java.util.HashSet;
import java.util.Set;
import org.mifosplatform.portfolio.savings.data.SavingsAccountData;
import org.mifosplatform.portfolio.savings.data.SavingsProductData;
public class SavingsApiConstants {
public static final String SAVINGS_PRODUCT_RESOURCE_NAME = "savingsproduct";
public static final String SAVINGS_ACCOUNT_RESOURCE_NAME = "savingsaccount";
public static final String localeParamName = "locale";
public static final String idParamName = "id";
public static final String accountNoParamName = "accountNo";
public static final String externalIdParamName = "externalId";
public static final String clientIdParamName = "clientId";
public static final String groupIdParamName = "groupId";
public static final String productIdParamName = "productId";
public static final String nameParamName = "name";
public static final String descriptionParamName = "description";
public static final String currencyCodeParamName = "currencyCode";
public static final String digitsAfterDecimalParamName = "digitsAfterDecimal";
public static final String interestRateParamName = "interestRate";
public static final String interestRatePeriodFrequencyTypeParamName = "interestRatePeriodFrequencyType";
public static final String minRequiredOpeningBalanceParamName = "minRequiredOpeningBalance";
public static final String lockinPeriodFrequencyParamName = "lockinPeriodFrequency";
public static final String lockinPeriodFrequencyTypeParamName = "lockinPeriodFrequencyType";
public static final Set<String> SAVINGS_PRODUCT_REQUEST_DATA_PARAMETERS = new HashSet<String>(Arrays.asList(localeParamName,
nameParamName, descriptionParamName, currencyCodeParamName, digitsAfterDecimalParamName, interestRateParamName,
interestRatePeriodFrequencyTypeParamName, minRequiredOpeningBalanceParamName, lockinPeriodFrequencyParamName,
lockinPeriodFrequencyTypeParamName));
/**
* These parameters will match the class level parameters of
* {@link SavingsProductData}. Where possible, we try to get response
* parameters to match those of request parameters.
*/
public static final Set<String> SAVINGS_PRODUCT_RESPONSE_DATA_PARAMETERS = new HashSet<String>(Arrays.asList(idParamName,
nameParamName, descriptionParamName, "currency", digitsAfterDecimalParamName, interestRateParamName,
interestRatePeriodFrequencyTypeParamName, minRequiredOpeningBalanceParamName, lockinPeriodFrequencyParamName,
lockinPeriodFrequencyTypeParamName, "currencyOptions", "interestRatePeriodFrequencyTypeOptions",
"lockinPeriodFrequencyTypeOptions"));
public static final Set<String> SAVINGS_ACCOUNT_REQUEST_DATA_PARAMETERS = new HashSet<String>(Arrays.asList(localeParamName,
accountNoParamName, externalIdParamName, clientIdParamName, groupIdParamName, productIdParamName, interestRateParamName,
interestRatePeriodFrequencyTypeParamName, minRequiredOpeningBalanceParamName, lockinPeriodFrequencyParamName,
lockinPeriodFrequencyTypeParamName));
/**
* These parameters will match the class level parameters of
* {@link SavingsAccountData}. Where possible, we try to get response
* parameters to match those of request parameters.
*/
public static final Set<String> SAVINGS_ACCOUNT_RESPONSE_DATA_PARAMETERS = new HashSet<String>(Arrays.asList(idParamName,
accountNoParamName, externalIdParamName, clientIdParamName, "clientName", groupIdParamName, "groupName", "savingsProductId",
"savingsProductName", "currency", interestRateParamName, interestRatePeriodFrequencyTypeParamName, "annualInterestRate",
minRequiredOpeningBalanceParamName, lockinPeriodFrequencyParamName, lockinPeriodFrequencyTypeParamName, "productOptions",
"interestRatePeriodFrequencyTypeOptions", "lockinPeriodFrequencyTypeOptions"));
}
@@ -3,13 +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.savingsdepositproduct.api;
package org.mifosplatform.portfolio.savings.api;
import java.util.Arrays;
import java.util.Collection;
import java.util.HashSet;
import java.util.List;
import java.util.Set;
import javax.ws.rs.Consumes;
import javax.ws.rs.DELETE;
@@ -35,44 +31,38 @@ 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.loanproduct.domain.PeriodFrequencyType;
import org.mifosplatform.portfolio.savingsaccountproduct.service.SavingsDepositEnumerations;
import org.mifosplatform.portfolio.savingsdepositproduct.data.DepositProductData;
import org.mifosplatform.portfolio.savingsdepositproduct.service.DepositProductReadPlatformService;
import org.mifosplatform.portfolio.savings.data.SavingsProductData;
import org.mifosplatform.portfolio.savings.service.SavingsDropdownReadPlatformService;
import org.mifosplatform.portfolio.savings.service.SavingsEnumerations;
import org.mifosplatform.portfolio.savings.service.SavingsProductReadPlatformService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Scope;
import org.springframework.stereotype.Component;
@Path("/depositproducts")
@Path("/savingsproducts")
@Component
@Scope("singleton")
public class DepositProductsApiResource {
public class SavingsProductsApiResource {
private final Set<String> DEPOSIT_PRODUCT_DATA_PARAMETERS = new HashSet<String>(Arrays.asList("id", "externalId", "name",
"description", "currencyCode", "digitsAfterDecimal", "minDeposit", "defaultDeposit", "maxDeposit", "tenureInMonths",
"defaultInterestRate", "minInterestRate", "maxInterestRate", "interestCompoundedEvery",
"interestCompoundedEveryPeriodType", "renewalAllowed", "preClosureAllowed", "preClosureInterestRate",
"interestCompoundingAllowed", "isLockinPeriodAllowed", "lockinPeriod", "lockinPeriodType", "currency", "currencyOptions",
"interestCompoundedEveryPeriodTypeOptions"));
private final String entityType = "DEPOSITPRODUCT";
private final PlatformSecurityContext context;
private final DepositProductReadPlatformService depositProductReadPlatformService;
private final SavingsProductReadPlatformService savingProductReadPlatformService;
private final SavingsDropdownReadPlatformService dropdownReadPlatformService;
private final CurrencyReadPlatformService currencyReadPlatformService;
private final DefaultToApiJsonSerializer<DepositProductData> toApiJsonSerializer;
private final PlatformSecurityContext context;
private final DefaultToApiJsonSerializer<SavingsProductData> toApiJsonSerializer;
private final PortfolioCommandSourceWritePlatformService commandsSourceWritePlatformService;
private final ApiRequestParameterHelper apiRequestParameterHelper;
@Autowired
public DepositProductsApiResource(final PlatformSecurityContext context,
final DepositProductReadPlatformService depositProductReadPlatformService,
final CurrencyReadPlatformService currencyReadPlatformService,
final DefaultToApiJsonSerializer<DepositProductData> toApiJsonSerializer,
public SavingsProductsApiResource(final SavingsProductReadPlatformService savingProductReadPlatformService,
final SavingsDropdownReadPlatformService dropdownReadPlatformService,
final CurrencyReadPlatformService currencyReadPlatformService, final PlatformSecurityContext context,
final DefaultToApiJsonSerializer<SavingsProductData> toApiJsonSerializer,
final PortfolioCommandSourceWritePlatformService commandsSourceWritePlatformService,
final ApiRequestParameterHelper apiRequestParameterHelper) {
this.context = context;
this.depositProductReadPlatformService = depositProductReadPlatformService;
this.savingProductReadPlatformService = savingProductReadPlatformService;
this.dropdownReadPlatformService = dropdownReadPlatformService;
this.currencyReadPlatformService = currencyReadPlatformService;
this.context = context;
this.toApiJsonSerializer = toApiJsonSerializer;
this.commandsSourceWritePlatformService = commandsSourceWritePlatformService;
this.apiRequestParameterHelper = apiRequestParameterHelper;
@@ -81,9 +71,9 @@ public class DepositProductsApiResource {
@POST
@Consumes({ MediaType.APPLICATION_JSON })
@Produces({ MediaType.APPLICATION_JSON })
public String createDepositProduct(final String apiRequestBodyAsJson) {
public String create(final String apiRequestBodyAsJson) {
final CommandWrapper commandRequest = new CommandWrapperBuilder().createDepositProduct().withJson(apiRequestBodyAsJson).build();
final CommandWrapper commandRequest = new CommandWrapperBuilder().createSavingProduct().withJson(apiRequestBodyAsJson).build();
final CommandProcessingResult result = this.commandsSourceWritePlatformService.logCommandSource(commandRequest);
@@ -94,79 +84,97 @@ public class DepositProductsApiResource {
@Path("{productId}")
@Consumes({ MediaType.APPLICATION_JSON })
@Produces({ MediaType.APPLICATION_JSON })
public String updateDepositProduct(@PathParam("productId") final Long productId, final String apiRequestBodyAsJson) {
public String update(@PathParam("productId") final Long productId, final String apiRequestBodyAsJson) {
final CommandWrapper commandRequest = new CommandWrapperBuilder().updateDepositProduct(productId).withJson(apiRequestBodyAsJson)
final CommandWrapper commandRequest = new CommandWrapperBuilder().updateSavingProduct(productId).withJson(apiRequestBodyAsJson)
.build();
final CommandProcessingResult result = this.commandsSourceWritePlatformService.logCommandSource(commandRequest);
return this.toApiJsonSerializer.serialize(result);
}
@DELETE
@Path("{productId}")
@Consumes({ MediaType.APPLICATION_JSON })
@Produces({ MediaType.APPLICATION_JSON })
public String deleteDepositProduct(@PathParam("productId") final Long productId) {
final CommandWrapper commandRequest = new CommandWrapperBuilder().deleteDepositProduct(productId).build();
final CommandProcessingResult result = this.commandsSourceWritePlatformService.logCommandSource(commandRequest);
return this.toApiJsonSerializer.serialize(result);
}
@GET
@Consumes({ MediaType.APPLICATION_JSON })
@Produces({ MediaType.APPLICATION_JSON })
public String retrieveAllDepositProducts(@Context final UriInfo uriInfo) {
context.authenticatedUser().validateHasReadPermission(entityType);
Collection<DepositProductData> products = this.depositProductReadPlatformService.retrieveAllDepositProducts();
public String retrieveAll(@Context final UriInfo uriInfo) {
context.authenticatedUser().validateHasReadPermission(SavingsApiConstants.SAVINGS_PRODUCT_RESOURCE_NAME);
final Collection<SavingsProductData> products = this.savingProductReadPlatformService.retrieveAll();
final ApiRequestJsonSerializationSettings settings = apiRequestParameterHelper.process(uriInfo.getQueryParameters());
return this.toApiJsonSerializer.serialize(settings, products, DEPOSIT_PRODUCT_DATA_PARAMETERS);
return this.toApiJsonSerializer.serialize(settings, products, SavingsApiConstants.SAVINGS_PRODUCT_RESPONSE_DATA_PARAMETERS);
}
@GET
@Path("{productId}")
@Consumes({ MediaType.APPLICATION_JSON })
@Produces({ MediaType.APPLICATION_JSON })
public String retrieveDepositProductDetails(@PathParam("productId") final Long productId, @Context final UriInfo uriInfo) {
public String retrieveOne(@PathParam("productId") final Long productId, @Context final UriInfo uriInfo) {
context.authenticatedUser().validateHasReadPermission(SavingsApiConstants.SAVINGS_PRODUCT_RESOURCE_NAME);
SavingsProductData savingProduct = this.savingProductReadPlatformService.retrieveOne(productId);
context.authenticatedUser().validateHasReadPermission(entityType);
DepositProductData productData = this.depositProductReadPlatformService.retrieveDepositProductData(productId);
final ApiRequestJsonSerializationSettings settings = apiRequestParameterHelper.process(uriInfo.getQueryParameters());
if (settings.isTemplate()) {
productData = handleTemplateRelatedData(productData);
savingProduct = handleTemplateRelatedData(savingProduct);
}
return this.toApiJsonSerializer.serialize(settings, productData, DEPOSIT_PRODUCT_DATA_PARAMETERS);
return this.toApiJsonSerializer.serialize(settings, savingProduct, SavingsApiConstants.SAVINGS_PRODUCT_RESPONSE_DATA_PARAMETERS);
}
@GET
@Path("template")
@Consumes({ MediaType.APPLICATION_JSON })
@Produces({ MediaType.APPLICATION_JSON })
public String retrieveNewDepositProductDetails(@Context final UriInfo uriInfo) {
public String retrieveTemplate(@Context final UriInfo uriInfo) {
context.authenticatedUser().validateHasReadPermission(entityType);
context.authenticatedUser().validateHasReadPermission(SavingsApiConstants.SAVINGS_PRODUCT_RESOURCE_NAME);
DepositProductData depositProduct = this.depositProductReadPlatformService.retrieveNewDepositProductDetails();
depositProduct = handleTemplateRelatedData(depositProduct);
SavingsProductData savingProduct = handleTemplateRelatedData(null);
final ApiRequestJsonSerializationSettings settings = apiRequestParameterHelper.process(uriInfo.getQueryParameters());
return this.toApiJsonSerializer.serialize(settings, depositProduct, DEPOSIT_PRODUCT_DATA_PARAMETERS);
return this.toApiJsonSerializer.serialize(settings, savingProduct, SavingsApiConstants.SAVINGS_PRODUCT_RESPONSE_DATA_PARAMETERS);
}
private DepositProductData handleTemplateRelatedData(final DepositProductData productData) {
private SavingsProductData handleTemplateRelatedData(final SavingsProductData savingsProduct) {
Collection<CurrencyData> allowedCurrencies = this.currencyReadPlatformService.retrieveAllowedCurrencies();
final EnumOptionData interestRatePeriodFrequencyType = SavingsEnumerations
.interestRatePeriodFrequencyType(PeriodFrequencyType.YEARS);
EnumOptionData monthly = SavingsDepositEnumerations.interestCompoundingPeriodType(PeriodFrequencyType.MONTHS);
List<EnumOptionData> interestCompoundedEveryPeriodTypeOptions = Arrays.asList(monthly);
final Collection<CurrencyData> currencyOptions = this.currencyReadPlatformService.retrieveAllowedCurrencies();
final Collection<EnumOptionData> interestRatePeriodFrequencyTypeOptions = this.dropdownReadPlatformService
.retrieveInterestRatePeriodFrequencyTypeOptions();
final Collection<EnumOptionData> lockinPeriodFrequencyTypeOptions = this.dropdownReadPlatformService
.retrieveLockinPeriodFrequencyTypeOptions();
SavingsProductData savingsProductToReturn = null;
if (savingsProduct != null) {
savingsProductToReturn = SavingsProductData.withTemplate(savingsProduct, currencyOptions,
interestRatePeriodFrequencyTypeOptions, lockinPeriodFrequencyTypeOptions);
} else {
savingsProductToReturn = SavingsProductData.template(CurrencyData.blank(), interestRatePeriodFrequencyType, currencyOptions,
interestRatePeriodFrequencyTypeOptions, lockinPeriodFrequencyTypeOptions);
}
return savingsProductToReturn;
}
@DELETE
@Path("{productId}")
@Consumes({ MediaType.APPLICATION_JSON })
@Produces({ MediaType.APPLICATION_JSON })
public String delete(@PathParam("productId") final Long productId) {
final CommandWrapper commandRequest = new CommandWrapperBuilder().deleteSavingProduct(productId).build();
final CommandProcessingResult result = this.commandsSourceWritePlatformService.logCommandSource(commandRequest);
return this.toApiJsonSerializer.serialize(result);
return new DepositProductData(productData, allowedCurrencies, interestCompoundedEveryPeriodTypeOptions);
}
}
@@ -0,0 +1,123 @@
/**
* 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 java.math.BigDecimal;
import java.util.Collection;
import org.mifosplatform.infrastructure.core.data.EnumOptionData;
import org.mifosplatform.organisation.monetary.data.CurrencyData;
/**
* Immutable data object representing a savings account.
*/
@SuppressWarnings("unused")
public class SavingsAccountData {
private final Long id;
private final String accountNo;
private final String externalId;
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 CurrencyData currency;
private final BigDecimal interestRate;
private final EnumOptionData interestRatePeriodFrequencyType;
private final BigDecimal annualInterestRate;
private final BigDecimal minRequiredOpeningBalance;
private final Integer lockinPeriodFrequency;
private final EnumOptionData lockinPeriodFrequencyType;
// template
private final Collection<SavingsProductData> productOptions;
private final Collection<EnumOptionData> interestRatePeriodFrequencyTypeOptions;
private final Collection<EnumOptionData> lockinPeriodFrequencyTypeOptions;
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 CurrencyData currency, final BigDecimal interestRate, final EnumOptionData interestRatePeriodFrequencyType,
final BigDecimal annualInterestRate, final BigDecimal minRequiredOpeningBalance, final Integer lockinPeriodFrequency,
final EnumOptionData lockinPeriodFrequencyType) {
final Collection<SavingsProductData> productOptions = null;
final Collection<EnumOptionData> interestRatePeriodFrequencyTypeOptions = null;
final Collection<EnumOptionData> lockinPeriodFrequencyTypeOptions = null;
return new SavingsAccountData(id, accountNo, externalId, groupId, groupName, clientId, clientName, productId, productName,
currency, interestRate, interestRatePeriodFrequencyType, annualInterestRate, minRequiredOpeningBalance,
lockinPeriodFrequency, lockinPeriodFrequencyType, productOptions, interestRatePeriodFrequencyTypeOptions,
lockinPeriodFrequencyTypeOptions);
}
public static SavingsAccountData withTemplateOptions(final SavingsAccountData account,
final Collection<SavingsProductData> productOptions, final Collection<EnumOptionData> interestRatePeriodFrequencyTypeOptions,
final Collection<EnumOptionData> lockinPeriodFrequencyTypeOptions) {
return new SavingsAccountData(account.id, account.accountNo, account.externalId, account.groupId, account.groupName,
account.clientId, account.clientName, account.savingsProductId, account.savingsProductName, account.currency,
account.interestRate, account.interestRatePeriodFrequencyType, account.annualInterestRate,
account.minRequiredOpeningBalance, account.lockinPeriodFrequency, account.lockinPeriodFrequencyType, productOptions,
interestRatePeriodFrequencyTypeOptions, lockinPeriodFrequencyTypeOptions);
}
public static SavingsAccountData withClientTemplate(final Long clientId, final String clientName, final Long groupId,
final String groupName) {
final Long id = null;
final String accountNo = null;
final String externalId = null;
final Long productId = null;
final String productName = null;
final CurrencyData currency = null;
final BigDecimal interestRate = null;
final EnumOptionData interestRatePeriodFrequencyType = null;
final BigDecimal annualInterestRate = null;
final BigDecimal minRequiredOpeningBalance = null;
final Integer lockinPeriodFrequency = null;
final EnumOptionData lockinPeriodFrequencyType = null;
final Collection<SavingsProductData> productOptions = null;
final Collection<CurrencyData> currencyOptions = null;
final Collection<EnumOptionData> interestRatePeriodFrequencyTypeOptions = null;
final Collection<EnumOptionData> lockinPeriodFrequencyTypeOptions = null;
return new SavingsAccountData(id, accountNo, externalId, groupId, groupName, clientId, clientName, productId, productName,
currency, interestRate, interestRatePeriodFrequencyType, annualInterestRate, minRequiredOpeningBalance,
lockinPeriodFrequency, lockinPeriodFrequencyType, productOptions, interestRatePeriodFrequencyTypeOptions,
lockinPeriodFrequencyTypeOptions);
}
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 CurrencyData currency,
final BigDecimal interestRate, final EnumOptionData interestRatePeriodFrequencyType, final BigDecimal annualInterestRate,
final BigDecimal minRequiredOpeningBalance, final Integer lockinPeriodFrequency,
final EnumOptionData lockinPeriodFrequencyType, final Collection<SavingsProductData> productOptions,
final Collection<EnumOptionData> interestRatePeriodFrequencyTypeOptions,
final Collection<EnumOptionData> lockinPeriodFrequencyTypeOptions) {
this.id = id;
this.accountNo = accountNo;
this.externalId = externalId;
this.groupId = groupId;
this.groupName = groupName;
this.clientId = clientId;
this.clientName = clientName;
this.savingsProductId = productId;
this.savingsProductName = productName;
this.currency = currency;
this.interestRate = interestRate;
this.interestRatePeriodFrequencyType = interestRatePeriodFrequencyType;
this.annualInterestRate = annualInterestRate;
this.minRequiredOpeningBalance = minRequiredOpeningBalance;
this.lockinPeriodFrequency = lockinPeriodFrequency;
this.lockinPeriodFrequencyType = lockinPeriodFrequencyType;
this.productOptions = productOptions;
this.interestRatePeriodFrequencyTypeOptions = interestRatePeriodFrequencyTypeOptions;
this.lockinPeriodFrequencyTypeOptions = lockinPeriodFrequencyTypeOptions;
}
}
@@ -0,0 +1,244 @@
package org.mifosplatform.portfolio.savings.data;
import static org.mifosplatform.portfolio.savings.api.SavingsApiConstants.accountNoParamName;
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.interestRateParamName;
import static org.mifosplatform.portfolio.savings.api.SavingsApiConstants.interestRatePeriodFrequencyTypeParamName;
import static org.mifosplatform.portfolio.savings.api.SavingsApiConstants.lockinPeriodFrequencyParamName;
import static org.mifosplatform.portfolio.savings.api.SavingsApiConstants.lockinPeriodFrequencyTypeParamName;
import static org.mifosplatform.portfolio.savings.api.SavingsApiConstants.minRequiredOpeningBalanceParamName;
import static org.mifosplatform.portfolio.savings.api.SavingsApiConstants.productIdParamName;
import java.lang.reflect.Type;
import java.math.BigDecimal;
import java.util.ArrayList;
import java.util.List;
import java.util.Map;
import org.apache.commons.lang.StringUtils;
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.mifosplatform.portfolio.savings.api.SavingsApiConstants;
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 class SavingsAccountDataValidator {
private final FromJsonHelper fromApiJsonHelper;
@Autowired
public SavingsAccountDataValidator(final FromJsonHelper fromApiJsonHelper) {
this.fromApiJsonHelper = fromApiJsonHelper;
}
public void validateForCreate(final String json) {
if (StringUtils.isBlank(json)) { throw new InvalidJsonException(); }
final Type typeOfMap = new TypeToken<Map<String, Object>>() {}.getType();
fromApiJsonHelper.checkForUnsupportedParameters(typeOfMap, json, SavingsApiConstants.SAVINGS_ACCOUNT_REQUEST_DATA_PARAMETERS);
final List<ApiParameterError> dataValidationErrors = new ArrayList<ApiParameterError>();
final DataValidatorBuilder baseDataValidator = new DataValidatorBuilder(dataValidationErrors)
.resource(SavingsApiConstants.SAVINGS_ACCOUNT_RESOURCE_NAME);
final JsonElement element = fromApiJsonHelper.parse(json);
final Long clientId = fromApiJsonHelper.extractLongNamed(clientIdParamName, element);
if (clientId != null) {
baseDataValidator.reset().parameter(clientIdParamName).value(clientId).longGreaterThanZero();
}
final Long groupId = fromApiJsonHelper.extractLongNamed(groupIdParamName, element);
if (groupId != null) {
baseDataValidator.reset().parameter(groupIdParamName).value(groupId).longGreaterThanZero();
}
if (clientId == null && groupId == null) {
baseDataValidator.reset().parameter(clientIdParamName).value(clientId).notNull().integerGreaterThanZero();
}
final Long productId = fromApiJsonHelper.extractLongNamed(productIdParamName, element);
baseDataValidator.reset().parameter(productIdParamName).value(productId).notNull().integerGreaterThanZero();
if (fromApiJsonHelper.parameterExists(accountNoParamName, element)) {
final String accountNo = fromApiJsonHelper.extractStringNamed(accountNoParamName, element);
baseDataValidator.reset().parameter(accountNoParamName).value(accountNo).notBlank().notExceedingLengthOf(20);
}
if (fromApiJsonHelper.parameterExists(externalIdParamName, element)) {
final String externalId = fromApiJsonHelper.extractStringNamed(externalIdParamName, element);
baseDataValidator.reset().parameter(externalIdParamName).value(externalId).notExceedingLengthOf(100);
}
if (fromApiJsonHelper.parameterExists(interestRateParamName, element)) {
final BigDecimal interestRate = fromApiJsonHelper.extractBigDecimalWithLocaleNamed(interestRateParamName, element);
baseDataValidator.reset().parameter(interestRateParamName).value(interestRate).notNull().zeroOrPositiveAmount();
}
if (fromApiJsonHelper.parameterExists(interestRatePeriodFrequencyTypeParamName, element)) {
final Integer interestRatePeriodFrequencyType = fromApiJsonHelper.extractIntegerSansLocaleNamed(
interestRatePeriodFrequencyTypeParamName, element);
baseDataValidator.reset().parameter(interestRatePeriodFrequencyTypeParamName).value(interestRatePeriodFrequencyType).notNull()
.inMinMaxRange(1, 3);
}
if (this.fromApiJsonHelper.parameterExists(minRequiredOpeningBalanceParamName, element)) {
final BigDecimal minOpeningBalance = fromApiJsonHelper.extractBigDecimalWithLocaleNamed(minRequiredOpeningBalanceParamName,
element);
baseDataValidator.reset().parameter(minRequiredOpeningBalanceParamName).value(minOpeningBalance).positiveAmount();
}
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);
}
}
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();
}
}
throwExceptionIfValidationWarningsExist(dataValidationErrors);
}
public void validateForUpdate(final String json) {
if (StringUtils.isBlank(json)) { throw new InvalidJsonException(); }
final Type typeOfMap = new TypeToken<Map<String, Object>>() {}.getType();
fromApiJsonHelper.checkForUnsupportedParameters(typeOfMap, json, SavingsApiConstants.SAVINGS_ACCOUNT_REQUEST_DATA_PARAMETERS);
final List<ApiParameterError> dataValidationErrors = new ArrayList<ApiParameterError>();
final DataValidatorBuilder baseDataValidator = new DataValidatorBuilder(dataValidationErrors)
.resource(SavingsApiConstants.SAVINGS_ACCOUNT_RESOURCE_NAME);
final JsonElement element = fromApiJsonHelper.parse(json);
Long clientId = null;
if (fromApiJsonHelper.parameterExists(clientIdParamName, element)) {
clientId = fromApiJsonHelper.extractLongNamed(clientIdParamName, element);
baseDataValidator.reset().parameter(clientIdParamName).value(clientId).ignoreIfNull().longGreaterThanZero();
Long groupId = null;
if (fromApiJsonHelper.parameterExists(productIdParamName, element)) {
groupId = fromApiJsonHelper.extractLongNamed(groupIdParamName, element);
baseDataValidator.reset().parameter(groupIdParamName).value(groupId).ignoreIfNull().longGreaterThanZero();
}
if (clientId == null && groupId == null) {
// either clientId or groupId must exists if param passed for
// update.
baseDataValidator.reset().parameter(clientIdParamName).value(clientId).notNull().integerGreaterThanZero();
}
}
Long groupId = null;
if (fromApiJsonHelper.parameterExists(groupIdParamName, element)) {
groupId = fromApiJsonHelper.extractLongNamed(groupIdParamName, element);
baseDataValidator.reset().parameter(groupIdParamName).value(groupId).ignoreIfNull().longGreaterThanZero();
if (fromApiJsonHelper.parameterExists(clientIdParamName, element)) {
clientId = fromApiJsonHelper.extractLongNamed(clientIdParamName, element);
baseDataValidator.reset().parameter(clientIdParamName).value(clientId).ignoreIfNull().longGreaterThanZero();
}
if (clientId == null && groupId == null) {
// either clientId or groupId must exists if param passed for
// update.
baseDataValidator.reset().parameter(clientIdParamName).value(clientId).notNull().integerGreaterThanZero();
}
}
if (fromApiJsonHelper.parameterExists(productIdParamName, element)) {
final Long productId = fromApiJsonHelper.extractLongNamed(productIdParamName, element);
baseDataValidator.reset().parameter(productIdParamName).value(productId).notNull().integerGreaterThanZero();
}
if (fromApiJsonHelper.parameterExists(accountNoParamName, element)) {
final String accountNo = fromApiJsonHelper.extractStringNamed(accountNoParamName, element);
baseDataValidator.reset().parameter(accountNoParamName).value(accountNo).notBlank().notExceedingLengthOf(20);
}
if (fromApiJsonHelper.parameterExists(externalIdParamName, element)) {
final String externalId = fromApiJsonHelper.extractStringNamed(externalIdParamName, element);
baseDataValidator.reset().parameter(externalIdParamName).value(externalId).notExceedingLengthOf(100);
}
if (fromApiJsonHelper.parameterExists(interestRateParamName, element)) {
final BigDecimal interestRate = fromApiJsonHelper.extractBigDecimalWithLocaleNamed(interestRateParamName, element);
baseDataValidator.reset().parameter(interestRateParamName).value(interestRate).notNull().zeroOrPositiveAmount();
}
if (fromApiJsonHelper.parameterExists(interestRatePeriodFrequencyTypeParamName, element)) {
final Integer interestRatePeriodFrequencyType = fromApiJsonHelper.extractIntegerSansLocaleNamed(
interestRatePeriodFrequencyTypeParamName, element);
baseDataValidator.reset().parameter(interestRatePeriodFrequencyTypeParamName).value(interestRatePeriodFrequencyType).notNull()
.inMinMaxRange(1, 3);
}
if (this.fromApiJsonHelper.parameterExists(minRequiredOpeningBalanceParamName, element)) {
final BigDecimal minOpeningBalance = fromApiJsonHelper.extractBigDecimalWithLocaleNamed(minRequiredOpeningBalanceParamName,
element);
baseDataValidator.reset().parameter(minRequiredOpeningBalanceParamName).value(minOpeningBalance).positiveAmount();
}
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);
}
}
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();
}
}
throwExceptionIfValidationWarningsExist(dataValidationErrors);
}
private void throwExceptionIfValidationWarningsExist(final List<ApiParameterError> dataValidationErrors) {
if (!dataValidationErrors.isEmpty()) { throw new PlatformApiDataValidationException("validation.msg.validation.errors.exist",
"Validation errors exist.", dataValidationErrors); }
}
}
@@ -0,0 +1,119 @@
/**
* 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 java.math.BigDecimal;
import java.util.Collection;
import org.mifosplatform.infrastructure.core.data.EnumOptionData;
import org.mifosplatform.organisation.monetary.data.CurrencyData;
/**
* Immutable data object represent a savings product.
*/
@SuppressWarnings("unused")
public class SavingsProductData {
private final Long id;
private final String name;
private final String description;
private final CurrencyData currency;
private final BigDecimal interestRate;
private final EnumOptionData interestRatePeriodFrequencyType;
private final BigDecimal minRequiredOpeningBalance;
private final Integer lockinPeriodFrequency;
private final EnumOptionData lockinPeriodFrequencyType;
// template
private final Collection<CurrencyData> currencyOptions;
private final Collection<EnumOptionData> interestRatePeriodFrequencyTypeOptions;
private final Collection<EnumOptionData> lockinPeriodFrequencyTypeOptions;
public static SavingsProductData template(final CurrencyData currency, final EnumOptionData interestRatePeriodFrequencyType,
final Collection<CurrencyData> currencyOptions, final Collection<EnumOptionData> interestRatePeriodFrequencyTypeOptions,
final Collection<EnumOptionData> lockinPeriodFrequencyTypeOptions) {
final Long id = null;
final String name = null;
final String description = null;
final Integer digitsAfterDecimal = null;
final BigDecimal interestRate = null;
final BigDecimal minRequiredOpeningBalance = null;
final Integer lockinPeriodFrequency = null;
final EnumOptionData lockinPeriodFrequencyType = null;
return new SavingsProductData(id, name, description, currency, interestRate, interestRatePeriodFrequencyType,
minRequiredOpeningBalance, lockinPeriodFrequency, lockinPeriodFrequencyType, currencyOptions,
interestRatePeriodFrequencyTypeOptions, lockinPeriodFrequencyTypeOptions);
}
/**
* Returns a {@link SavingsProductData} that contains and exist
* {@link SavingsProductData} data with further template data for dropdowns.
*/
public static SavingsProductData withTemplate(final SavingsProductData existingProduct, final Collection<CurrencyData> currencyOptions,
final Collection<EnumOptionData> interestRatePeriodFrequencyTypeOptions,
final Collection<EnumOptionData> lockinPeriodFrequencyTypeOptions) {
return new SavingsProductData(existingProduct.id, existingProduct.name, existingProduct.description, existingProduct.currency,
existingProduct.interestRate, existingProduct.interestRatePeriodFrequencyType, existingProduct.minRequiredOpeningBalance,
existingProduct.lockinPeriodFrequency, existingProduct.lockinPeriodFrequencyType, currencyOptions,
interestRatePeriodFrequencyTypeOptions, lockinPeriodFrequencyTypeOptions);
}
public static SavingsProductData instance(final Long id, final String name, final String description, final CurrencyData currency,
final BigDecimal interestRate, final EnumOptionData interestRatePeriodFrequencyType,
final BigDecimal minRequiredOpeningBalance, final Integer lockinPeriodFrequency, final EnumOptionData lockinPeriodFrequencyType) {
final Collection<CurrencyData> currencyOptions = null;
final Collection<EnumOptionData> interestRatePeriodFrequencyTypeOptions = null;
final Collection<EnumOptionData> lockinPeriodFrequencyTypeOptions = null;
return new SavingsProductData(id, name, description, currency, interestRate, interestRatePeriodFrequencyType,
minRequiredOpeningBalance, lockinPeriodFrequency, lockinPeriodFrequencyType, currencyOptions,
interestRatePeriodFrequencyTypeOptions, lockinPeriodFrequencyTypeOptions);
}
public static SavingsProductData lookup(final Long id, final String name) {
final CurrencyData currency = null;
final String description = null;
final BigDecimal interestRate = null;
final EnumOptionData interestRatePeriodFrequencyType = null;
final BigDecimal minRequiredOpeningBalance = null;
final Integer lockinPeriodFrequency = null;
final EnumOptionData lockinPeriodFrequencyType = null;
final Collection<CurrencyData> currencyOptions = null;
final Collection<EnumOptionData> interestRatePeriodFrequencyTypeOptions = null;
final Collection<EnumOptionData> lockinPeriodFrequencyTypeOptions = null;
return new SavingsProductData(id, name, description, currency, interestRate, interestRatePeriodFrequencyType,
minRequiredOpeningBalance, lockinPeriodFrequency, lockinPeriodFrequencyType, currencyOptions,
interestRatePeriodFrequencyTypeOptions, lockinPeriodFrequencyTypeOptions);
}
private SavingsProductData(final Long id, final String name, final String description, final CurrencyData currency,
final BigDecimal interestRate, final EnumOptionData interestRatePeriodFrequencyType,
final BigDecimal minRequiredOpeningBalance, final Integer lockinPeriodFrequency,
final EnumOptionData lockinPeriodFrequencyType, final Collection<CurrencyData> currencyOptions,
final Collection<EnumOptionData> interestRatePeriodFrequencyTypeOptions,
final Collection<EnumOptionData> lockinPeriodFrequencyTypeOptions) {
this.id = id;
this.name = name;
this.description = description;
this.currency = currency;
this.interestRate = interestRate;
this.interestRatePeriodFrequencyType = interestRatePeriodFrequencyType;
this.minRequiredOpeningBalance = minRequiredOpeningBalance;
this.lockinPeriodFrequency = lockinPeriodFrequency;
this.lockinPeriodFrequencyType = lockinPeriodFrequencyType;
this.currencyOptions = currencyOptions;
this.interestRatePeriodFrequencyTypeOptions = interestRatePeriodFrequencyTypeOptions;
this.lockinPeriodFrequencyTypeOptions = lockinPeriodFrequencyTypeOptions;
}
}
@@ -0,0 +1,172 @@
package org.mifosplatform.portfolio.savings.data;
import static org.mifosplatform.portfolio.savings.api.SavingsApiConstants.SAVINGS_PRODUCT_RESOURCE_NAME;
import static org.mifosplatform.portfolio.savings.api.SavingsApiConstants.SAVINGS_PRODUCT_REQUEST_DATA_PARAMETERS;
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.interestRateParamName;
import static org.mifosplatform.portfolio.savings.api.SavingsApiConstants.interestRatePeriodFrequencyTypeParamName;
import static org.mifosplatform.portfolio.savings.api.SavingsApiConstants.lockinPeriodFrequencyParamName;
import static org.mifosplatform.portfolio.savings.api.SavingsApiConstants.lockinPeriodFrequencyTypeParamName;
import static org.mifosplatform.portfolio.savings.api.SavingsApiConstants.minRequiredOpeningBalanceParamName;
import static org.mifosplatform.portfolio.savings.api.SavingsApiConstants.nameParamName;
import java.lang.reflect.Type;
import java.math.BigDecimal;
import java.util.ArrayList;
import java.util.List;
import java.util.Map;
import org.apache.commons.lang.StringUtils;
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 class SavingsProductDataValidator {
private final FromJsonHelper fromApiJsonHelper;
@Autowired
public SavingsProductDataValidator(final FromJsonHelper fromApiJsonHelper) {
this.fromApiJsonHelper = fromApiJsonHelper;
}
public void validateForCreate(final String json) {
if (StringUtils.isBlank(json)) { throw new InvalidJsonException(); }
final Type typeOfMap = new TypeToken<Map<String, Object>>() {}.getType();
fromApiJsonHelper.checkForUnsupportedParameters(typeOfMap, json, SAVINGS_PRODUCT_REQUEST_DATA_PARAMETERS);
final List<ApiParameterError> dataValidationErrors = new ArrayList<ApiParameterError>();
final DataValidatorBuilder baseDataValidator = new DataValidatorBuilder(dataValidationErrors).resource(SAVINGS_PRODUCT_RESOURCE_NAME);
final JsonElement element = fromApiJsonHelper.parse(json);
final String name = fromApiJsonHelper.extractStringNamed(nameParamName, element);
baseDataValidator.reset().parameter(nameParamName).value(name).notBlank().notExceedingLengthOf(100);
final String description = fromApiJsonHelper.extractStringNamed(descriptionParamName, element);
baseDataValidator.reset().parameter(descriptionParamName).value(description).notBlank().notExceedingLengthOf(500);
final String currencyCode = fromApiJsonHelper.extractStringNamed(currencyCodeParamName, element);
baseDataValidator.reset().parameter(currencyCodeParamName).value(currencyCode).notBlank();
final Integer digitsAfterDecimal = fromApiJsonHelper.extractIntegerSansLocaleNamed(digitsAfterDecimalParamName, element);
baseDataValidator.reset().parameter(digitsAfterDecimalParamName).value(digitsAfterDecimal).notNull().inMinMaxRange(0, 6);
final BigDecimal interestRate = fromApiJsonHelper.extractBigDecimalWithLocaleNamed(interestRateParamName, element);
baseDataValidator.reset().parameter(interestRateParamName).value(interestRate).notNull().zeroOrPositiveAmount();
final Integer interestRatePeriodFrequencyType = fromApiJsonHelper.extractIntegerSansLocaleNamed(
interestRatePeriodFrequencyTypeParamName, element);
baseDataValidator.reset().parameter(interestRatePeriodFrequencyTypeParamName).value(interestRatePeriodFrequencyType).notNull()
.inMinMaxRange(1, 3);
if (this.fromApiJsonHelper.parameterExists(minRequiredOpeningBalanceParamName, element)) {
final BigDecimal minOpeningBalance = fromApiJsonHelper.extractBigDecimalWithLocaleNamed(minRequiredOpeningBalanceParamName,
element);
baseDataValidator.reset().parameter(minRequiredOpeningBalanceParamName).value(minOpeningBalance).positiveAmount();
}
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);
}
}
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();
}
}
throwExceptionIfValidationWarningsExist(dataValidationErrors);
}
public void validateForUpdate(final String json) {
if (StringUtils.isBlank(json)) { throw new InvalidJsonException(); }
final Type typeOfMap = new TypeToken<Map<String, Object>>() {}.getType();
fromApiJsonHelper.checkForUnsupportedParameters(typeOfMap, json, SAVINGS_PRODUCT_REQUEST_DATA_PARAMETERS);
final List<ApiParameterError> dataValidationErrors = new ArrayList<ApiParameterError>();
final DataValidatorBuilder baseDataValidator = new DataValidatorBuilder(dataValidationErrors).resource(SAVINGS_PRODUCT_RESOURCE_NAME);
final JsonElement element = fromApiJsonHelper.parse(json);
if (this.fromApiJsonHelper.parameterExists(nameParamName, element)) {
final String name = fromApiJsonHelper.extractStringNamed(nameParamName, element);
baseDataValidator.reset().parameter(nameParamName).value(name).notBlank().notExceedingLengthOf(100);
}
if (this.fromApiJsonHelper.parameterExists(descriptionParamName, element)) {
final String description = fromApiJsonHelper.extractStringNamed(descriptionParamName, element);
baseDataValidator.reset().parameter(descriptionParamName).value(description).notBlank().notExceedingLengthOf(500);
}
if (this.fromApiJsonHelper.parameterExists(currencyCodeParamName, element)) {
final String currencyCode = fromApiJsonHelper.extractStringNamed(currencyCodeParamName, element);
baseDataValidator.reset().parameter(currencyCodeParamName).value(currencyCode).notBlank();
}
if (this.fromApiJsonHelper.parameterExists(digitsAfterDecimalParamName, element)) {
final Integer digitsAfterDecimal = fromApiJsonHelper.extractIntegerSansLocaleNamed(digitsAfterDecimalParamName, element);
baseDataValidator.reset().parameter(digitsAfterDecimalParamName).value(digitsAfterDecimal).notNull().inMinMaxRange(0, 6);
}
if (this.fromApiJsonHelper.parameterExists(interestRateParamName, element)) {
final BigDecimal interestRate = fromApiJsonHelper.extractBigDecimalWithLocaleNamed(interestRateParamName, element);
baseDataValidator.reset().parameter(interestRateParamName).value(interestRate).notNull().zeroOrPositiveAmount();
}
if (this.fromApiJsonHelper.parameterExists(interestRatePeriodFrequencyTypeParamName, element)) {
final Integer interestRatePeriodFrequencyType = fromApiJsonHelper.extractIntegerSansLocaleNamed(
interestRatePeriodFrequencyTypeParamName, element);
baseDataValidator.reset().parameter(interestRatePeriodFrequencyTypeParamName).value(interestRatePeriodFrequencyType).notNull()
.inMinMaxRange(1, 3);
}
if (this.fromApiJsonHelper.parameterExists(lockinPeriodFrequencyParamName, element)) {
final Integer lockinPeriodFrequency = fromApiJsonHelper.extractIntegerWithLocaleNamed(lockinPeriodFrequencyParamName, element);
baseDataValidator.reset().parameter(lockinPeriodFrequencyParamName).value(lockinPeriodFrequency).ignoreIfNull()
.positiveAmount();
}
if (this.fromApiJsonHelper.parameterExists(lockinPeriodFrequencyTypeParamName, element)) {
final Integer lockinPeriodFrequencyType = fromApiJsonHelper.extractIntegerSansLocaleNamed(lockinPeriodFrequencyTypeParamName,
element);
baseDataValidator.reset().parameter(lockinPeriodFrequencyTypeParamName).value(lockinPeriodFrequencyType).inMinMaxRange(1, 3);
}
throwExceptionIfValidationWarningsExist(dataValidationErrors);
}
private void throwExceptionIfValidationWarningsExist(final List<ApiParameterError> dataValidationErrors) {
if (!dataValidationErrors.isEmpty()) { throw new PlatformApiDataValidationException("validation.msg.validation.errors.exist",
"Validation errors exist.", dataValidationErrors); }
}
}
@@ -0,0 +1,235 @@
/**
* 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.Map;
import javax.persistence.Column;
import javax.persistence.Embedded;
import javax.persistence.Entity;
import javax.persistence.JoinColumn;
import javax.persistence.ManyToOne;
import javax.persistence.Table;
import javax.persistence.Transient;
import javax.persistence.UniqueConstraint;
import org.apache.commons.lang.StringUtils;
import org.mifosplatform.infrastructure.core.api.JsonCommand;
import org.mifosplatform.infrastructure.security.service.RandomPasswordGenerator;
import org.mifosplatform.organisation.monetary.domain.MonetaryCurrency;
import org.mifosplatform.organisation.monetary.domain.Money;
import org.mifosplatform.portfolio.client.domain.Client;
import org.mifosplatform.portfolio.group.domain.Group;
import org.mifosplatform.portfolio.loanproduct.domain.PeriodFrequencyType;
import org.mifosplatform.portfolio.savings.api.SavingsApiConstants;
import org.springframework.data.jpa.domain.AbstractPersistable;
@Entity
@Table(name = "m_savings_account", uniqueConstraints = { @UniqueConstraint(columnNames = { "account_no" }, name = "sa_account_no_UNIQUE"),
@UniqueConstraint(columnNames = { "external_id" }, name = "sa_external_id_UNIQUE") })
public class SavingsAccount extends AbstractPersistable<Long> {
@Column(name = "account_no", length = 20, unique = true, nullable = false)
private String accountNumber;
@Column(name = "external_id")
private String externalId;
@ManyToOne(optional = true)
@JoinColumn(name = "client_id", nullable = true)
private Client client;
@ManyToOne(optional = true)
@JoinColumn(name = "group_id", nullable = true)
private Group group;
@ManyToOne
@JoinColumn(name = "product_id", nullable = false)
private SavingsProduct product;
@Embedded
private MonetaryCurrency currency;
@Column(name = "nominal_interest_rate_per_period", scale = 6, precision = 19, nullable = false)
private BigDecimal interestRate;
@Column(name = "nominal_interest_rate_period_frequency_enum", nullable = false)
private Integer interestRatePeriodFrequencyType;
@SuppressWarnings("unused")
@Column(name = "annual_nominal_interest_rate", scale = 6, precision = 19, nullable = false)
private BigDecimal annualInterestRate;
@Column(name = "min_required_opening_balance", scale = 6, precision = 19, nullable = false)
private BigDecimal minRequiredOpeningBalance;
@Column(name = "lockin_period_frequency", nullable = false)
private Integer lockinPeriodFrequency;
@Column(name = "lockin_period_frequency_enum", nullable = false)
private Integer lockinPeriodFrequencyType;
@Transient
private boolean accountNumberRequiresAutoGeneration = false;
protected SavingsAccount() {
//
}
public static SavingsAccount createNewAccount(final Client client, final Group group, final SavingsProduct product,
final String accountNo, final String externalId, final BigDecimal interestRate,
final PeriodFrequencyType interestRatePeriodFrequencyType, final BigDecimal annualInterestRate,
final BigDecimal minRequiredOpeningBalance, final Integer lockinPeriodFrequency,
final PeriodFrequencyType lockinPeriodFrequencyType) {
return new SavingsAccount(client, group, product, accountNo, externalId, interestRate, interestRatePeriodFrequencyType,
annualInterestRate, minRequiredOpeningBalance, lockinPeriodFrequency, lockinPeriodFrequencyType);
}
private SavingsAccount(final Client client, final Group group, final SavingsProduct product, final String accountNo,
final String externalId, final BigDecimal interestRate, final PeriodFrequencyType interestRatePeriodFrequencyType,
final BigDecimal annualInterestRate, final BigDecimal minRequiredOpeningBalance, final Integer lockinPeriodFrequency,
final PeriodFrequencyType lockinPeriodFrequencyType) {
this.client = client;
this.group = group;
this.product = product;
if (StringUtils.isBlank(accountNo)) {
this.accountNumber = new RandomPasswordGenerator(19).generate();
this.accountNumberRequiresAutoGeneration = true;
} else {
this.accountNumber = accountNo;
}
this.currency = product.currency();
this.externalId = externalId;
this.interestRate = interestRate;
this.interestRatePeriodFrequencyType = interestRatePeriodFrequencyType.getValue();
this.annualInterestRate = annualInterestRate;
this.minRequiredOpeningBalance = minRequiredOpeningBalance;
this.lockinPeriodFrequency = lockinPeriodFrequency;
if (lockinPeriodFrequencyType != null) {
this.lockinPeriodFrequencyType = lockinPeriodFrequencyType.getValue();
}
}
public void update(final JsonCommand command, final Map<String, Object> actualChanges) {
final String localeAsInput = command.locale();
if (command.isChangeInStringParameterNamed(SavingsApiConstants.accountNoParamName, this.accountNumber)) {
final String newValue = command.stringValueOfParameterNamed(SavingsApiConstants.accountNoParamName);
actualChanges.put(SavingsApiConstants.accountNoParamName, newValue);
this.accountNumber = StringUtils.defaultIfEmpty(newValue, null);
}
if (command.isChangeInStringParameterNamed(SavingsApiConstants.externalIdParamName, this.externalId)) {
final String newValue = command.stringValueOfParameterNamed(SavingsApiConstants.externalIdParamName);
actualChanges.put(SavingsApiConstants.externalIdParamName, newValue);
this.externalId = StringUtils.defaultIfEmpty(newValue, null);
}
if (command.isChangeInLongParameterNamed(SavingsApiConstants.clientIdParamName, clientId())) {
final Long newValue = command.longValueOfParameterNamed(SavingsApiConstants.clientIdParamName);
actualChanges.put(SavingsApiConstants.clientIdParamName, newValue);
}
if (command.isChangeInLongParameterNamed(SavingsApiConstants.groupIdParamName, groupId())) {
final Long newValue = command.longValueOfParameterNamed(SavingsApiConstants.groupIdParamName);
actualChanges.put(SavingsApiConstants.groupIdParamName, newValue);
}
if (command.isChangeInLongParameterNamed(SavingsApiConstants.productIdParamName, this.product.getId())) {
final Long newValue = command.longValueOfParameterNamed(SavingsApiConstants.productIdParamName);
actualChanges.put(SavingsApiConstants.productIdParamName, newValue);
}
if (command.isChangeInBigDecimalParameterNamed(SavingsApiConstants.interestRateParamName, this.interestRate)) {
final BigDecimal newValue = command.bigDecimalValueOfParameterNamed(SavingsApiConstants.interestRateParamName);
actualChanges.put(SavingsApiConstants.interestRateParamName, newValue);
actualChanges.put("locale", localeAsInput);
this.interestRate = newValue;
}
if (command.isChangeInIntegerParameterNamed(SavingsApiConstants.interestRatePeriodFrequencyTypeParamName,
this.interestRatePeriodFrequencyType)) {
final Integer newValue = command.integerValueOfParameterNamed(SavingsApiConstants.interestRatePeriodFrequencyTypeParamName);
actualChanges.put(SavingsApiConstants.interestRatePeriodFrequencyTypeParamName, newValue);
this.interestRatePeriodFrequencyType = PeriodFrequencyType.fromInt(newValue).getValue();
}
if (command.isChangeInBigDecimalParameterNamed(SavingsApiConstants.minRequiredOpeningBalanceParamName,
this.minRequiredOpeningBalance)) {
final BigDecimal newValue = command.bigDecimalValueOfParameterNamed(SavingsApiConstants.minRequiredOpeningBalanceParamName);
actualChanges.put(SavingsApiConstants.minRequiredOpeningBalanceParamName, newValue);
actualChanges.put("locale", localeAsInput);
this.minRequiredOpeningBalance = Money.of(this.currency, newValue).getAmount();
}
if (command.isChangeInIntegerParameterNamed(SavingsApiConstants.lockinPeriodFrequencyParamName, this.lockinPeriodFrequency)) {
final Integer newValue = command.integerValueOfParameterNamed(SavingsApiConstants.lockinPeriodFrequencyParamName);
actualChanges.put(SavingsApiConstants.lockinPeriodFrequencyParamName, newValue);
actualChanges.put("locale", localeAsInput);
this.lockinPeriodFrequency = newValue;
}
if (command.isChangeInIntegerParameterNamed(SavingsApiConstants.lockinPeriodFrequencyTypeParamName, this.lockinPeriodFrequencyType)) {
final Integer newValue = command.integerValueOfParameterNamed(SavingsApiConstants.lockinPeriodFrequencyTypeParamName);
actualChanges.put(SavingsApiConstants.lockinPeriodFrequencyTypeParamName, newValue);
if (newValue != null) {
this.lockinPeriodFrequencyType = PeriodFrequencyType.fromInt(newValue).getValue();
} else {
this.lockinPeriodFrequencyType = null;
}
}
}
public void update(final Client client) {
this.client = client;
}
public void update(final Group group) {
this.group = group;
}
public void update(final SavingsProduct product) {
this.product = product;
}
public void updateAccountNo(final String newAccountNo) {
this.accountNumber = newAccountNo;
this.accountNumberRequiresAutoGeneration = false;
}
public boolean isAccountNumberRequiresAutoGeneration() {
return this.accountNumberRequiresAutoGeneration;
}
public Long officeId() {
Long officeId = null;
if (this.client != null) {
officeId = this.client.officeId();
} else {
officeId = this.group.officeId();
}
return officeId;
}
public Long clientId() {
Long id = null;
if (this.client != null) {
id = this.client.getId();
}
return id;
}
public Long groupId() {
Long id = null;
if (this.group != null) {
id = this.group.getId();
}
return id;
}
}
@@ -0,0 +1,132 @@
/**
* 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 static org.mifosplatform.portfolio.savings.api.SavingsApiConstants.interestRateParamName;
import static org.mifosplatform.portfolio.savings.api.SavingsApiConstants.interestRatePeriodFrequencyTypeParamName;
import static org.mifosplatform.portfolio.savings.api.SavingsApiConstants.lockinPeriodFrequencyParamName;
import static org.mifosplatform.portfolio.savings.api.SavingsApiConstants.lockinPeriodFrequencyTypeParamName;
import static org.mifosplatform.portfolio.savings.api.SavingsApiConstants.minRequiredOpeningBalanceParamName;
import java.math.BigDecimal;
import org.mifosplatform.infrastructure.core.api.JsonCommand;
import org.mifosplatform.infrastructure.core.serialization.FromJsonHelper;
import org.mifosplatform.portfolio.client.domain.Client;
import org.mifosplatform.portfolio.client.domain.ClientRepository;
import org.mifosplatform.portfolio.client.exception.ClientNotFoundException;
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.loanaccount.loanschedule.domain.AprCalculator;
import org.mifosplatform.portfolio.loanproduct.domain.PeriodFrequencyType;
import org.mifosplatform.portfolio.savings.exception.SavingsProductNotFoundException;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import com.google.gson.JsonElement;
@Service
public class SavingsAccountAssembler {
private final ClientRepository clientRepository;
private final GroupRepository groupRepository;
private final SavingsProductRepository savingProductRepository;
private final FromJsonHelper fromApiJsonHelper;
private final AprCalculator aprCalculator;
@Autowired
public SavingsAccountAssembler(final ClientRepository clientRepository, final GroupRepository groupRepository,
final SavingsProductRepository savingProductRepository, final AprCalculator aprCalculator,
final FromJsonHelper fromApiJsonHelper) {
this.clientRepository = clientRepository;
this.groupRepository = groupRepository;
this.savingProductRepository = savingProductRepository;
this.aprCalculator = aprCalculator;
this.fromApiJsonHelper = fromApiJsonHelper;
}
/**
* Assembles a new {@link SavingsAccount} from JSON details passed in
* request inheriting details where relevant from chosen
* {@link SavingsProduct}.
*/
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 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;
if (clientId != null) {
client = this.clientRepository.findOne(clientId);
if (client == null || client.isDeleted()) { throw new ClientNotFoundException(clientId); }
}
if (groupId != null) {
group = this.groupRepository.findOne(groupId);
if (group == null || group.isDeleted()) { throw new GroupNotFoundException(groupId); }
}
BigDecimal interestRate = null;
if (command.parameterExists(interestRateParamName)) {
interestRate = command.bigDecimalValueOfParameterNamed(interestRateParamName);
} else {
interestRate = product.interestRate();
}
PeriodFrequencyType interestRatePeriodFrequencyType = null;
Integer interestRatePeriodFrequencyTypeValue = null;
if (command.parameterExists(interestRatePeriodFrequencyTypeParamName)) {
interestRatePeriodFrequencyTypeValue = command.integerValueOfParameterNamed(interestRatePeriodFrequencyTypeParamName);
if (interestRatePeriodFrequencyTypeValue != null) {
interestRatePeriodFrequencyType = PeriodFrequencyType.fromInt(interestRatePeriodFrequencyTypeValue);
}
} else {
interestRatePeriodFrequencyType = product.interestRatePeriodFrequencyType();
}
final BigDecimal annualInterestRate = this.aprCalculator.calculateFrom(interestRatePeriodFrequencyType, interestRate);
BigDecimal minRequiredOpeningBalance = null;
if (command.parameterExists(minRequiredOpeningBalanceParamName)) {
minRequiredOpeningBalance = command.bigDecimalValueOfParameterNamed(minRequiredOpeningBalanceParamName);
} else {
minRequiredOpeningBalance = product.minRequiredOpeningBalance();
}
Integer lockinPeriodFrequency = null;
if (command.parameterExists(lockinPeriodFrequencyParamName)) {
lockinPeriodFrequency = command.integerValueOfParameterNamed(lockinPeriodFrequencyParamName);
} else {
lockinPeriodFrequency = product.lockinPeriodFrequency();
}
PeriodFrequencyType lockinPeriodFrequencyType = null;
Integer lockinPeriodFrequencyTypeValue = null;
if (command.parameterExists(lockinPeriodFrequencyTypeParamName)) {
lockinPeriodFrequencyTypeValue = command.integerValueOfParameterNamed(lockinPeriodFrequencyTypeParamName);
if (lockinPeriodFrequencyTypeValue != null) {
lockinPeriodFrequencyType = PeriodFrequencyType.fromInt(lockinPeriodFrequencyTypeValue);
}
} else {
lockinPeriodFrequencyType = product.lockinPeriodFrequencyType();
}
return SavingsAccount.createNewAccount(client, group, product, accountNo, externalId, interestRate,
interestRatePeriodFrequencyType, annualInterestRate, minRequiredOpeningBalance, lockinPeriodFrequency,
lockinPeriodFrequencyType);
}
}
@@ -3,11 +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.savingsaccount.domain;
package org.mifosplatform.portfolio.savings.domain;
import org.springframework.data.jpa.repository.JpaRepository;
import org.springframework.data.jpa.repository.JpaSpecificationExecutor;
public interface SavingAccountRepository extends JpaRepository<SavingAccount, Long>, JpaSpecificationExecutor<SavingAccount> {
public interface SavingsAccountRepository extends JpaRepository<SavingsAccount, Long>, JpaSpecificationExecutor<SavingsAccount> {
}
@@ -0,0 +1,215 @@
/**
* 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 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.interestRateParamName;
import static org.mifosplatform.portfolio.savings.api.SavingsApiConstants.interestRatePeriodFrequencyTypeParamName;
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 java.math.BigDecimal;
import java.util.LinkedHashMap;
import java.util.Map;
import javax.persistence.Column;
import javax.persistence.Embedded;
import javax.persistence.Entity;
import javax.persistence.Table;
import org.mifosplatform.infrastructure.core.api.JsonCommand;
import org.mifosplatform.organisation.monetary.domain.MonetaryCurrency;
import org.mifosplatform.organisation.monetary.domain.Money;
import org.mifosplatform.portfolio.loanproduct.domain.PeriodFrequencyType;
import org.mifosplatform.portfolio.savings.exception.InvalidSavingsProductSettingsException;
import org.springframework.data.jpa.domain.AbstractPersistable;
@Entity
@Table(name = "m_savings_product")
public class SavingsProduct extends AbstractPersistable<Long> {
@Column(name = "name", nullable = false)
private String name;
@Column(name = "description", length = 500, nullable = false)
private String description;
@Embedded
private MonetaryCurrency currency;
@Column(name = "nominal_interest_rate_per_period", scale = 6, precision = 19, nullable = false)
private BigDecimal interestRate;
@Column(name = "nominal_interest_rate_period_frequency_enum", nullable = false)
private Integer interestRatePeriodFrequencyType;
@Column(name = "min_required_opening_balance", scale = 6, precision = 19, nullable = false)
private BigDecimal minRequiredOpeningBalance;
@Column(name = "lockin_period_frequency", nullable = false)
private Integer lockinPeriodFrequency;
@Column(name = "lockin_period_frequency_enum", nullable = false)
private Integer lockinPeriodFrequencyType;
public static SavingsProduct createNew(final String name, final String description, final MonetaryCurrency currency,
final BigDecimal interestRate, final PeriodFrequencyType interestRatePeriodFrequencyType,
final BigDecimal minRequiredOpeningBalance, final Integer lockinPeriodFrequency,
final PeriodFrequencyType lockinPeriodFrequencyType) {
return new SavingsProduct(name, description, currency, interestRate, interestRatePeriodFrequencyType, minRequiredOpeningBalance,
lockinPeriodFrequency, lockinPeriodFrequencyType);
}
protected SavingsProduct() {
this.name = null;
this.description = null;
}
private SavingsProduct(final String name, final String description, final MonetaryCurrency currency, final BigDecimal interestRate,
final PeriodFrequencyType interestRatePeriodFrequencyType, final BigDecimal minRequiredOpeningBalance,
final Integer lockinPeriodFrequency, final PeriodFrequencyType lockinPeriodFrequencyType) {
this.name = name;
this.description = description;
this.currency = currency;
this.interestRate = interestRate;
this.interestRatePeriodFrequencyType = interestRatePeriodFrequencyType.getValue();
if (minRequiredOpeningBalance != null) {
this.minRequiredOpeningBalance = Money.of(currency, minRequiredOpeningBalance).getAmount();
}
this.lockinPeriodFrequency = lockinPeriodFrequency;
if (lockinPeriodFrequencyType != null) {
this.lockinPeriodFrequencyType = lockinPeriodFrequencyType.getValue();
}
validateLockinDetails();
}
public MonetaryCurrency currency() {
return this.currency.copy();
}
public BigDecimal interestRate() {
return Money.of(this.currency, this.interestRate).getAmount();
}
public PeriodFrequencyType interestRatePeriodFrequencyType() {
PeriodFrequencyType type = null;
if (this.interestRatePeriodFrequencyType != null) {
type = PeriodFrequencyType.fromInt(this.interestRatePeriodFrequencyType);
}
return type;
}
public BigDecimal minRequiredOpeningBalance() {
return this.minRequiredOpeningBalance;
}
public Integer lockinPeriodFrequency() {
return this.lockinPeriodFrequency;
}
public PeriodFrequencyType lockinPeriodFrequencyType() {
PeriodFrequencyType type = null;
if (this.lockinPeriodFrequencyType != null) {
type = PeriodFrequencyType.fromInt(this.lockinPeriodFrequencyType);
}
return type;
}
public Map<String, Object> update(final JsonCommand command) {
final Map<String, Object> actualChanges = new LinkedHashMap<String, Object>(10);
final String localeAsInput = command.locale();
if (command.isChangeInStringParameterNamed(nameParamName, this.name)) {
final String newValue = command.stringValueOfParameterNamed(nameParamName);
actualChanges.put(nameParamName, newValue);
this.name = newValue;
}
if (command.isChangeInStringParameterNamed(descriptionParamName, this.description)) {
final String newValue = command.stringValueOfParameterNamed(descriptionParamName);
actualChanges.put(descriptionParamName, newValue);
this.description = newValue;
}
Integer digitsAfterDecimal = this.currency.getDigitsAfterDecimal();
if (command.isChangeInIntegerParameterNamed(digitsAfterDecimalParamName, digitsAfterDecimal)) {
final Integer newValue = command.integerValueOfParameterNamed(digitsAfterDecimalParamName);
actualChanges.put(digitsAfterDecimalParamName, newValue);
actualChanges.put(localeParamName, localeAsInput);
digitsAfterDecimal = newValue;
this.currency = new MonetaryCurrency(this.currency.getCode(), digitsAfterDecimal);
}
String currencyCode = this.currency.getCode();
if (command.isChangeInStringParameterNamed(currencyCodeParamName, currencyCode)) {
final String newValue = command.stringValueOfParameterNamed(currencyCodeParamName);
actualChanges.put(currencyCodeParamName, newValue);
currencyCode = newValue;
this.currency = new MonetaryCurrency(currencyCode, this.currency.getDigitsAfterDecimal());
}
if (command.isChangeInBigDecimalParameterNamed(interestRateParamName, this.interestRate)) {
final BigDecimal newValue = command.bigDecimalValueOfParameterNamed(interestRateParamName);
actualChanges.put(interestRateParamName, newValue);
actualChanges.put(localeParamName, localeAsInput);
this.interestRate = newValue;
}
if (command.isChangeInIntegerParameterNamed(interestRatePeriodFrequencyTypeParamName, this.interestRatePeriodFrequencyType)) {
final Integer newValue = command.integerValueOfParameterNamed(interestRatePeriodFrequencyTypeParamName);
actualChanges.put(interestRatePeriodFrequencyTypeParamName, newValue);
this.interestRatePeriodFrequencyType = PeriodFrequencyType.fromInt(newValue).getValue();
}
if (command.isChangeInBigDecimalParameterNamed(minRequiredOpeningBalanceParamName, this.minRequiredOpeningBalance)) {
final BigDecimal newValue = command.bigDecimalValueOfParameterNamed(minRequiredOpeningBalanceParamName);
actualChanges.put(minRequiredOpeningBalanceParamName, newValue);
actualChanges.put(localeParamName, localeAsInput);
this.minRequiredOpeningBalance = newValue;
}
if (command.isChangeInIntegerParameterNamed(lockinPeriodFrequencyParamName, this.lockinPeriodFrequency)) {
final Integer newValue = command.integerValueOfParameterNamed(lockinPeriodFrequencyParamName);
actualChanges.put(lockinPeriodFrequencyParamName, newValue);
actualChanges.put(localeParamName, localeAsInput);
this.lockinPeriodFrequency = newValue;
}
if (command.isChangeInIntegerParameterNamed(lockinPeriodFrequencyTypeParamName, this.lockinPeriodFrequencyType)) {
final Integer newValue = command.integerValueOfParameterNamed(lockinPeriodFrequencyTypeParamName);
actualChanges.put(lockinPeriodFrequencyTypeParamName, newValue);
this.lockinPeriodFrequencyType = PeriodFrequencyType.fromInt(newValue).getValue();
}
validateLockinDetails();
return actualChanges;
}
private void validateLockinDetails() {
if (isInvalidConfigurationOfLockinSettings()) { throw new InvalidSavingsProductSettingsException(
"error.msg.product.savings.invalid.lockin.settings", "Invalid configuration of lock in settings.",
lockinPeriodFrequencyParamName); }
}
private boolean isInvalidConfigurationOfLockinSettings() {
return (this.lockinPeriodFrequency == null && this.lockinPeriodFrequencyType != null)
|| (this.lockinPeriodFrequencyType == null && this.lockinPeriodFrequency != null);
}
}
@@ -0,0 +1,51 @@
package org.mifosplatform.portfolio.savings.domain;
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.interestRateParamName;
import static org.mifosplatform.portfolio.savings.api.SavingsApiConstants.interestRatePeriodFrequencyTypeParamName;
import static org.mifosplatform.portfolio.savings.api.SavingsApiConstants.lockinPeriodFrequencyParamName;
import static org.mifosplatform.portfolio.savings.api.SavingsApiConstants.lockinPeriodFrequencyTypeParamName;
import static org.mifosplatform.portfolio.savings.api.SavingsApiConstants.minRequiredOpeningBalanceParamName;
import static org.mifosplatform.portfolio.savings.api.SavingsApiConstants.nameParamName;
import java.math.BigDecimal;
import org.mifosplatform.infrastructure.core.api.JsonCommand;
import org.mifosplatform.organisation.monetary.domain.MonetaryCurrency;
import org.mifosplatform.portfolio.loanproduct.domain.PeriodFrequencyType;
import org.springframework.stereotype.Component;
@Component
public class SavingsProductAssembler {
public SavingsProduct assemble(final JsonCommand command) {
final String name = command.stringValueOfParameterNamed(nameParamName);
final String description = command.stringValueOfParameterNamed(descriptionParamName);
final String currencyCode = command.stringValueOfParameterNamed(currencyCodeParamName);
final Integer digitsAfterDecimal = command.integerValueOfParameterNamed(digitsAfterDecimalParamName);
MonetaryCurrency currency = new MonetaryCurrency(currencyCode, digitsAfterDecimal);
final BigDecimal interestRate = command.bigDecimalValueOfParameterNamed(interestRateParamName);
PeriodFrequencyType interestRatePeriodFrequencyType = null;
final Integer interestRatePeriodFrequencyTypeValue = command.integerValueOfParameterNamed(interestRatePeriodFrequencyTypeParamName);
if (interestRatePeriodFrequencyTypeValue != null) {
interestRatePeriodFrequencyType = PeriodFrequencyType.fromInt(interestRatePeriodFrequencyTypeValue);
}
final BigDecimal minRequiredOpeningBalance = command.bigDecimalValueOfParameterNamed(minRequiredOpeningBalanceParamName);
final Integer lockinPeriodFrequency = command.integerValueOfParameterNamed(lockinPeriodFrequencyParamName);
PeriodFrequencyType lockinPeriodFrequencyType = null;
final Integer lockinPeriodFrequencyTypeValue = command.integerValueOfParameterNamed(lockinPeriodFrequencyTypeParamName);
if (lockinPeriodFrequencyTypeValue != null) {
lockinPeriodFrequencyType = PeriodFrequencyType.fromInt(lockinPeriodFrequencyTypeValue);
}
return SavingsProduct.createNew(name, description, currency, interestRate, interestRatePeriodFrequencyType,
minRequiredOpeningBalance, lockinPeriodFrequency, lockinPeriodFrequencyType);
}
}
@@ -3,11 +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.savingsdepositaccount.domain;
package org.mifosplatform.portfolio.savings.domain;
import org.springframework.data.jpa.repository.JpaRepository;
import org.springframework.data.jpa.repository.JpaSpecificationExecutor;
public interface DepositAccountRepository extends JpaRepository<DepositAccount, Long>, JpaSpecificationExecutor<DepositAccount> {
public interface SavingsProductRepository extends JpaRepository<SavingsProduct, Long>, JpaSpecificationExecutor<SavingsProduct> {
//
}
@@ -0,0 +1,10 @@
package org.mifosplatform.portfolio.savings.exception;
import org.mifosplatform.infrastructure.core.exception.AbstractPlatformDomainRuleException;
public class InvalidSavingsProductSettingsException extends AbstractPlatformDomainRuleException {
public InvalidSavingsProductSettingsException(final String errorCode, final String defaultMessage, final String paramName) {
super(errorCode, defaultMessage, paramName);
}
}
@@ -3,13 +3,13 @@
* 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.savingsdepositaccount.exception;
package org.mifosplatform.portfolio.savings.exception;
import org.mifosplatform.infrastructure.core.exception.AbstractPlatformResourceNotFoundException;
public class DepositAccountNotFoundException extends AbstractPlatformResourceNotFoundException {
public class SavingsAccountNotFoundException extends AbstractPlatformResourceNotFoundException {
public DepositAccountNotFoundException(final Long id) {
super("error.msg.deposit.account.id.invalid", "Deposit account with identifier " + id + " does not exist", id);
public SavingsAccountNotFoundException(final Long id) {
super("error.msg.saving.account.id.invalid", "Savings account with identifier " + id + " does not exist", id);
}
}
@@ -3,13 +3,13 @@
* 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.savingsaccountproduct.exception;
package org.mifosplatform.portfolio.savings.exception;
import org.mifosplatform.infrastructure.core.exception.AbstractPlatformResourceNotFoundException;
public class SavingProductNotFoundException extends AbstractPlatformResourceNotFoundException {
public class SavingsProductNotFoundException extends AbstractPlatformResourceNotFoundException {
public SavingProductNotFoundException(final Long id) {
public SavingsProductNotFoundException(final Long id) {
super("error.msg.savingproduct.id.invalid", "Saving product with identifier " + id + " does not exist", id);
}
}
@@ -0,0 +1,26 @@
package org.mifosplatform.portfolio.savings.handler;
import org.mifosplatform.commands.handler.NewCommandSourceHandler;
import org.mifosplatform.infrastructure.core.api.JsonCommand;
import org.mifosplatform.infrastructure.core.data.CommandProcessingResult;
import org.mifosplatform.portfolio.savings.service.SavingsAccountWritePlatformService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
@Service
public class CreateSavingsAccountCommandHandler implements NewCommandSourceHandler {
private final SavingsAccountWritePlatformService savingAccountWritePlatformService;
@Autowired
public CreateSavingsAccountCommandHandler(final SavingsAccountWritePlatformService savingAccountWritePlatformService) {
this.savingAccountWritePlatformService = savingAccountWritePlatformService;
}
@Transactional
@Override
public CommandProcessingResult processCommand(final JsonCommand command) {
return this.savingAccountWritePlatformService.createSavingAccount(command);
}
}
@@ -0,0 +1,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.SavingsProductWritePlatformService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
@Service
public class CreateSavingsProductCommandHandler implements NewCommandSourceHandler {
private final SavingsProductWritePlatformService writePlatformService;
@Autowired
public CreateSavingsProductCommandHandler(final SavingsProductWritePlatformService writePlatformService) {
this.writePlatformService = writePlatformService;
}
@Override
public CommandProcessingResult processCommand(final JsonCommand command) {
return this.writePlatformService.create(command);
}
}
@@ -0,0 +1,27 @@
package org.mifosplatform.portfolio.savings.handler;
import org.mifosplatform.commands.handler.NewCommandSourceHandler;
import org.mifosplatform.infrastructure.core.api.JsonCommand;
import org.mifosplatform.infrastructure.core.data.CommandProcessingResult;
import org.mifosplatform.portfolio.savings.service.SavingsAccountWritePlatformService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
@Service
public class DeleteSavingsAccountCommandHandler implements NewCommandSourceHandler {
private final SavingsAccountWritePlatformService savingAccountWritePlatformService;
@Autowired
public DeleteSavingsAccountCommandHandler(final SavingsAccountWritePlatformService savingAccountWritePlatformService) {
this.savingAccountWritePlatformService = savingAccountWritePlatformService;
}
@Transactional
@Override
public CommandProcessingResult processCommand(final JsonCommand command) {
return this.savingAccountWritePlatformService.deleteSavingAccount(command.entityId());
}
}
@@ -1,24 +1,24 @@
package org.mifosplatform.portfolio.savingsaccountproduct.handler;
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.savingsaccountproduct.service.SavingProductWritePlatformService;
import org.mifosplatform.portfolio.savings.service.SavingsProductWritePlatformService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
@Service
public class CreateSavingProductCommandHandler implements NewCommandSourceHandler {
public class DeleteSavingsProductCommandHandler implements NewCommandSourceHandler {
private final SavingProductWritePlatformService savingProductWritePlatformService;
private final SavingsProductWritePlatformService savingProductWritePlatformService;
@Autowired
public CreateSavingProductCommandHandler(final SavingProductWritePlatformService savingProductWritePlatformService) {
public DeleteSavingsProductCommandHandler(final SavingsProductWritePlatformService savingProductWritePlatformService) {
this.savingProductWritePlatformService = savingProductWritePlatformService;
}
@Override
public CommandProcessingResult processCommand(final JsonCommand command) {
return this.savingProductWritePlatformService.createSavingProduct(command);
return this.savingProductWritePlatformService.delete(command.entityId());
}
}
@@ -0,0 +1,27 @@
package org.mifosplatform.portfolio.savings.handler;
import org.mifosplatform.commands.handler.NewCommandSourceHandler;
import org.mifosplatform.infrastructure.core.api.JsonCommand;
import org.mifosplatform.infrastructure.core.data.CommandProcessingResult;
import org.mifosplatform.portfolio.savings.service.SavingsAccountWritePlatformService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
@Service
public class UpdateSavingsAccountCommandHandler implements NewCommandSourceHandler {
private final SavingsAccountWritePlatformService savingAccountWritePlatformService;
@Autowired
public UpdateSavingsAccountCommandHandler(final SavingsAccountWritePlatformService savingAccountWritePlatformService) {
this.savingAccountWritePlatformService = savingAccountWritePlatformService;
}
@Transactional
@Override
public CommandProcessingResult processCommand(final JsonCommand command) {
return this.savingAccountWritePlatformService.updateSavingAccount(command.entityId(), command);
}
}
@@ -1,24 +1,24 @@
package org.mifosplatform.portfolio.savingsaccountproduct.handler;
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.savingsaccountproduct.service.SavingProductWritePlatformService;
import org.mifosplatform.portfolio.savings.service.SavingsProductWritePlatformService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
@Service
public class DeleteSavingProductCommandHandler implements NewCommandSourceHandler {
public class UpdateSavingsProductCommandHandler implements NewCommandSourceHandler {
private final SavingProductWritePlatformService savingProductWritePlatformService;
private final SavingsProductWritePlatformService savingProductWritePlatformService;
@Autowired
public DeleteSavingProductCommandHandler(final SavingProductWritePlatformService savingProductWritePlatformService) {
public UpdateSavingsProductCommandHandler(final SavingsProductWritePlatformService savingProductWritePlatformService) {
this.savingProductWritePlatformService = savingProductWritePlatformService;
}
@Override
public CommandProcessingResult processCommand(final JsonCommand command) {
return this.savingProductWritePlatformService.deleteSavingProduct(command.entityId());
return this.savingProductWritePlatformService.update(command.entityId(), command);
}
}
@@ -0,0 +1,19 @@
/**
* 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.Collection;
import org.mifosplatform.portfolio.savings.data.SavingsAccountData;
public interface SavingsAccountReadPlatformService {
Collection<SavingsAccountData> retrieveAll();
SavingsAccountData retrieveOne(Long accountId);
SavingsAccountData retrieveTemplate(Long clientId, Long groupId, Long productId);
}
@@ -0,0 +1,289 @@
/**
* 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.math.BigDecimal;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.util.Collection;
import org.mifosplatform.infrastructure.core.data.EnumOptionData;
import org.mifosplatform.infrastructure.core.domain.JdbcSupport;
import org.mifosplatform.infrastructure.core.service.TenantAwareRoutingDataSource;
import org.mifosplatform.infrastructure.security.service.PlatformSecurityContext;
import org.mifosplatform.organisation.monetary.data.CurrencyData;
import org.mifosplatform.portfolio.client.data.ClientData;
import org.mifosplatform.portfolio.client.service.ClientReadPlatformService;
import org.mifosplatform.portfolio.group.data.GroupData;
import org.mifosplatform.portfolio.group.service.GroupReadPlatformService;
import org.mifosplatform.portfolio.loanproduct.domain.PeriodFrequencyType;
import org.mifosplatform.portfolio.savings.data.SavingsAccountData;
import org.mifosplatform.portfolio.savings.data.SavingsProductData;
import org.mifosplatform.portfolio.savings.exception.SavingsAccountNotFoundException;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.dao.EmptyResultDataAccessException;
import org.springframework.jdbc.core.JdbcTemplate;
import org.springframework.jdbc.core.RowMapper;
import org.springframework.stereotype.Service;
@Service
public class SavingsAccountReadPlatformServiceImpl implements SavingsAccountReadPlatformService {
private final PlatformSecurityContext context;
private final JdbcTemplate jdbcTemplate;
private final ClientReadPlatformService clientReadPlatformService;
private final GroupReadPlatformService groupReadPlatformService;
private final SavingsProductReadPlatformService savingsProductReadPlatformService;
private final SavingsDropdownReadPlatformService dropdownReadPlatformService;
@Autowired
public SavingsAccountReadPlatformServiceImpl(final PlatformSecurityContext context, final TenantAwareRoutingDataSource dataSource,
final ClientReadPlatformService clientReadPlatformService, final GroupReadPlatformService groupReadPlatformService,
final SavingsProductReadPlatformService savingProductReadPlatformService,
final SavingsDropdownReadPlatformService dropdownReadPlatformService) {
this.context = context;
this.jdbcTemplate = new JdbcTemplate(dataSource);
this.clientReadPlatformService = clientReadPlatformService;
this.groupReadPlatformService = groupReadPlatformService;
this.savingsProductReadPlatformService = savingProductReadPlatformService;
this.dropdownReadPlatformService = dropdownReadPlatformService;
}
@Override
public Collection<SavingsAccountData> retrieveAll() {
this.context.authenticatedUser();
final SavingAccountMapper mapper = new SavingAccountMapper();
final String sql = "select " + mapper.schema();
return this.jdbcTemplate.query(sql, mapper, new Object[] {});
}
@Override
public SavingsAccountData retrieveOne(final Long accountId) {
try {
this.context.authenticatedUser();
final SavingAccountMapper mapper = new SavingAccountMapper();
final String sql = "select " + mapper.schema() + " where sa.id = ?";
return this.jdbcTemplate.queryForObject(sql, mapper, new Object[] { accountId });
} catch (EmptyResultDataAccessException e) {
throw new SavingsAccountNotFoundException(accountId);
}
}
private static final class SavingAccountMapper implements RowMapper<SavingsAccountData> {
private final String schemaSql;
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("c.id as clientId, c.display_name as clientName, ");
sqlBuilder.append("g.id as groupId, g.name as groupName, ");
sqlBuilder.append("sp.id as productId, sp.name as productName, ");
sqlBuilder.append("sa.currency_code as currencyCode, sa.currency_digits as currencyDigits, ");
sqlBuilder
.append("curr.name as currencyName, curr.internationalized_name_code as currencyNameCode, curr.display_symbol as currencyDisplaySymbol, ");
sqlBuilder
.append("sa.nominal_interest_rate_per_period as interestRate, sa.nominal_interest_rate_period_frequency_enum as interestRatePeriodFrequencyType, ");
sqlBuilder.append("sa.annual_nominal_interest_rate as annualInterestRate, ");
sqlBuilder.append("sa.min_required_opening_balance as minRequiredOpeningBalance, ");
sqlBuilder
.append("sa.lockin_period_frequency as lockinPeriodFrequency, sa.lockin_period_frequency_enum as lockinPeriodFrequencyType ");
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 ");
this.schemaSql = sqlBuilder.toString();
}
public String schema() {
return this.schemaSql;
}
@Override
public SavingsAccountData mapRow(final ResultSet rs, @SuppressWarnings("unused") final int rowNum) throws SQLException {
final Long id = rs.getLong("id");
final String accountNo = rs.getString("accountNo");
final String externalId = rs.getString("externalId");
final Long groupId = rs.getLong("groupId");
final String groupName = rs.getString("groupName");
final Long clientId = rs.getLong("clientId");
final String clientName = rs.getString("clientName");
final Long productId = rs.getLong("productId");
final String productName = rs.getString("productName");
final String currencyCode = rs.getString("currencyCode");
final String currencyName = rs.getString("currencyName");
final String currencyNameCode = rs.getString("currencyNameCode");
final String currencyDisplaySymbol = rs.getString("currencyDisplaySymbol");
final Integer currencyDigits = JdbcSupport.getInteger(rs, "currencyDigits");
final CurrencyData currency = new CurrencyData(currencyCode, currencyName, currencyDigits, currencyDisplaySymbol,
currencyNameCode);
final BigDecimal interestRate = rs.getBigDecimal("interestRate");
final EnumOptionData interestRatePeriodFrequencyType = SavingsEnumerations.interestRatePeriodFrequencyType(PeriodFrequencyType
.fromInt(JdbcSupport.getInteger(rs, "interestRatePeriodFrequencyType")));
final BigDecimal annualInterestRate = rs.getBigDecimal("annualInterestRate");
final BigDecimal minRequiredOpeningBalance = rs.getBigDecimal("minRequiredOpeningBalance");
final Integer lockinPeriodFrequency = JdbcSupport.getInteger(rs, "lockinPeriodFrequency");
EnumOptionData lockinPeriodFrequencyType = null;
final Integer lockinPeriodFrequencyTypeValue = JdbcSupport.getInteger(rs, "lockinPeriodFrequencyType");
if (lockinPeriodFrequencyTypeValue != null) {
lockinPeriodFrequencyType = SavingsEnumerations.interestRatePeriodFrequencyType(PeriodFrequencyType
.fromInt(lockinPeriodFrequencyTypeValue));
}
return SavingsAccountData.instance(id, accountNo, externalId, groupId, groupName, clientId, clientName, productId, productName,
currency, interestRate, interestRatePeriodFrequencyType, annualInterestRate, minRequiredOpeningBalance,
lockinPeriodFrequency, lockinPeriodFrequencyType);
}
}
@Override
public SavingsAccountData retrieveTemplate(final Long clientId, final Long groupId, final Long productId) {
context.authenticatedUser();
ClientData client = null;
if (clientId != null) {
client = this.clientReadPlatformService.retrieveIndividualClient(clientId);
}
GroupData group = null;
if (groupId != null) {
group = this.groupReadPlatformService.retrieveGroup(groupId);
}
final Collection<SavingsProductData> productOptions = this.savingsProductReadPlatformService.retrieveAllForLookup();
SavingsAccountData template = null;
if (productId != null) {
SavingAccountTemplateMapper mapper = new SavingAccountTemplateMapper(client, group);
final String sql = "select " + mapper.schema() + " where sp.id = ?";
template = this.jdbcTemplate.queryForObject(sql, mapper, new Object[] { productId });
final Collection<EnumOptionData> interestRatePeriodFrequencyTypeOptions = this.dropdownReadPlatformService
.retrieveInterestRatePeriodFrequencyTypeOptions();
final Collection<EnumOptionData> lockinPeriodFrequencyTypeOptions = this.dropdownReadPlatformService
.retrieveLockinPeriodFrequencyTypeOptions();
template = SavingsAccountData.withTemplateOptions(template, productOptions, interestRatePeriodFrequencyTypeOptions,
lockinPeriodFrequencyTypeOptions);
} else {
String clientName = null;
if (client != null) {
clientName = client.displayName();
}
String groupName = null;
if (group != null) {
groupName = group.getName();
}
template = SavingsAccountData.withClientTemplate(clientId, clientName, groupId, groupName);
final Collection<EnumOptionData> interestRatePeriodFrequencyTypeOptions = null;
final Collection<EnumOptionData> lockinPeriodFrequencyTypeOptions = null;
template = SavingsAccountData.withTemplateOptions(template, productOptions, interestRatePeriodFrequencyTypeOptions,
lockinPeriodFrequencyTypeOptions);
}
return template;
}
private static final class SavingAccountTemplateMapper implements RowMapper<SavingsAccountData> {
private final ClientData client;
private final GroupData group;
private final String schemaSql;
public SavingAccountTemplateMapper(final ClientData client, final GroupData group) {
this.client = client;
this.group = group;
final StringBuilder sqlBuilder = new StringBuilder(400);
sqlBuilder.append("sp.id as productId, sp.name as productName, ");
sqlBuilder.append("sp.currency_code as currencyCode, sp.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("sp.nominal_interest_rate_per_period as interestRate, ");
sqlBuilder.append("sp.nominal_interest_rate_period_frequency_enum as interestRatePeriodFrequencyType, ");
sqlBuilder.append("sp.min_required_opening_balance as minRequiredOpeningBalance, ");
sqlBuilder.append("sp.lockin_period_frequency as lockinPeriodFrequency, ");
sqlBuilder.append("sp.lockin_period_frequency_enum as lockinPeriodFrequencyType ");
sqlBuilder.append("from m_savings_product sp ");
sqlBuilder.append("join m_currency curr on curr.code = sp.currency_code ");
this.schemaSql = sqlBuilder.toString();
}
public String schema() {
return this.schemaSql;
}
@Override
public SavingsAccountData mapRow(final ResultSet rs, @SuppressWarnings("unused") final int rowNum) throws SQLException {
final Long productId = rs.getLong("productId");
final String productName = rs.getString("productName");
final String currencyCode = rs.getString("currencyCode");
final String currencyName = rs.getString("currencyName");
final String currencyNameCode = rs.getString("currencyNameCode");
final String currencyDisplaySymbol = rs.getString("currencyDisplaySymbol");
final Integer currencyDigits = JdbcSupport.getInteger(rs, "currencyDigits");
final CurrencyData currency = new CurrencyData(currencyCode, currencyName, currencyDigits, currencyDisplaySymbol,
currencyNameCode);
final BigDecimal interestRate = rs.getBigDecimal("interestRate");
final EnumOptionData interestRatePeriodFrequencyType = SavingsEnumerations.interestRatePeriodFrequencyType(PeriodFrequencyType
.fromInt(JdbcSupport.getInteger(rs, "interestRatePeriodFrequencyType")));
final BigDecimal annualInterestRate = null;
final BigDecimal minRequiredOpeningBalance = rs.getBigDecimal("minRequiredOpeningBalance");
final Integer lockinPeriodFrequency = JdbcSupport.getInteger(rs, "lockinPeriodFrequency");
EnumOptionData lockinPeriodFrequencyType = null;
final Integer lockinPeriodFrequencyTypeValue = JdbcSupport.getInteger(rs, "lockinPeriodFrequencyType");
if (lockinPeriodFrequencyTypeValue != null) {
lockinPeriodFrequencyType = SavingsEnumerations.interestRatePeriodFrequencyType(PeriodFrequencyType
.fromInt(lockinPeriodFrequencyTypeValue));
}
Long clientId = null;
String clientName = null;
if (client != null) {
clientId = client.id();
clientName = client.displayName();
}
Long groupId = null;
String groupName = null;
if (group != null) {
groupId = group.getId();
groupName = group.getName();
}
return SavingsAccountData.instance(null, null, null, groupId, groupName, clientId, clientName, productId, productName,
currency, interestRate, interestRatePeriodFrequencyType, annualInterestRate, minRequiredOpeningBalance,
lockinPeriodFrequency, lockinPeriodFrequencyType);
}
}
}
@@ -0,0 +1,22 @@
/**
* 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 SavingsAccountWritePlatformService {
CommandProcessingResult createSavingAccount(JsonCommand command);
CommandProcessingResult updateSavingAccount(Long accountId, JsonCommand command);
CommandProcessingResult deposit(JsonCommand command);
CommandProcessingResult withdraw(JsonCommand command);
CommandProcessingResult deleteSavingAccount(Long accountId);
}
@@ -0,0 +1,253 @@
/**
* 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.LinkedHashMap;
import java.util.Map;
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.security.service.PlatformSecurityContext;
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.ClientRepository;
import org.mifosplatform.portfolio.client.exception.ClientNotFoundException;
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.savings.api.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.SavingsAccountRepository;
import org.mifosplatform.portfolio.savings.domain.SavingsProduct;
import org.mifosplatform.portfolio.savings.domain.SavingsProductRepository;
import org.mifosplatform.portfolio.savings.exception.SavingsAccountNotFoundException;
import org.mifosplatform.portfolio.savings.exception.SavingsProductNotFoundException;
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 SavingsAccountWritePlatformServiceJpaRepositoryImpl implements SavingsAccountWritePlatformService {
private final static Logger logger = LoggerFactory.getLogger(SavingsAccountWritePlatformServiceJpaRepositoryImpl.class);
private final PlatformSecurityContext context;
private final SavingsAccountRepository savingAccountRepository;
private final SavingsAccountAssembler savingAccountAssembler;
private final SavingsAccountDataValidator savingsAccountDataValidator;
private final AccountNumberGeneratorFactory accountIdentifierGeneratorFactory;
private final ClientRepository clientRepository;
private final GroupRepository groupRepository;
private final SavingsProductRepository savingsProductRepository;
@Autowired
public SavingsAccountWritePlatformServiceJpaRepositoryImpl(final PlatformSecurityContext context,
final SavingsAccountRepository savingAccountRepository, final SavingsAccountAssembler savingAccountAssembler,
final SavingsAccountDataValidator savingsAccountDataValidator,
final AccountNumberGeneratorFactory accountIdentifierGeneratorFactory, final ClientRepository clientRepository,
final GroupRepository groupRepository, final SavingsProductRepository savingsProductRepository) {
this.context = context;
this.savingAccountRepository = savingAccountRepository;
this.savingAccountAssembler = savingAccountAssembler;
this.accountIdentifierGeneratorFactory = accountIdentifierGeneratorFactory;
this.savingsAccountDataValidator = savingsAccountDataValidator;
this.clientRepository = clientRepository;
this.groupRepository = groupRepository;
this.savingsProductRepository = savingsProductRepository;
}
/*
* 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 SavingsAccount account = this.savingAccountAssembler.assembleFrom(command);
this.savingAccountRepository.save(account);
if (account.isAccountNumberRequiresAutoGeneration()) {
final AccountNumberGenerator accountNoGenerator = this.accountIdentifierGeneratorFactory
.determineLoanAccountNoGenerator(account.getId());
account.updateAccountNo(accountNoGenerator.generate());
this.savingAccountRepository.save(account);
}
return new CommandProcessingResultBuilder() //
.withCommandId(command.commandId()) //
.withEntityId(account.getId()) //
.withOfficeId(account.officeId()) //
.withClientId(account.clientId()) //
.withGroupId(account.groupId()) //
.build();
} catch (DataAccessException dve) {
handleDataIntegrityIssues(command, dve);
return new CommandProcessingResult(Long.valueOf(-1));
}
}
@Transactional
@Override
public CommandProcessingResult updateSavingAccount(final Long accountId, 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.findOne(accountId);
if (account == null) { throw new SavingsAccountNotFoundException(accountId); }
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.findOne(clientId);
if (client == null || client.isDeleted()) { throw new ClientNotFoundException(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 || group.isDeleted()) { 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(account.getId()) //
.withOfficeId(account.officeId()) //
.withClientId(account.clientId()) //
.withGroupId(account.groupId()) //
.with(changes) //
.build();
} catch (DataAccessException dve) {
handleDataIntegrityIssues(command, dve);
return new CommandProcessingResult(Long.valueOf(-1));
}
}
@Transactional
@Override
public CommandProcessingResult deposit(final JsonCommand command) {
this.context.authenticatedUser();
SavingsAccount account = this.savingAccountRepository.findOne(command.entityId());
if (account == null) { throw new SavingsAccountNotFoundException(command.entityId()); }
// FIXME - add basic support for deposits
return new CommandProcessingResultBuilder() //
.withEntityId(account.getId()) //
.withOfficeId(account.officeId()) //
.withClientId(account.clientId()) //
.withGroupId(account.groupId()) //
.build();
}
@Transactional
@Override
public CommandProcessingResult withdraw(final JsonCommand command) {
this.context.authenticatedUser();
final SavingsAccount account = this.savingAccountRepository.findOne(command.entityId());
if (account == null) { throw new SavingsAccountNotFoundException(command.entityId()); }
// FIXME - add basic support for withdrawals
this.savingAccountRepository.save(account);
return new CommandProcessingResultBuilder() //
.withEntityId(account.getId()) //
.withOfficeId(account.officeId()) //
.withClientId(account.clientId()) //
.withGroupId(account.groupId()) //
.build();
}
@Transactional
@Override
public CommandProcessingResult deleteSavingAccount(final Long accountId) {
this.context.authenticatedUser();
final SavingsAccount account = this.savingAccountRepository.findOne(accountId);
if (account == null) { throw new SavingsAccountNotFoundException(accountId); }
this.savingAccountRepository.delete(account);
return new CommandProcessingResultBuilder() //
.withEntityId(accountId) //
.withOfficeId(account.officeId()) //
.withClientId(account.clientId()) //
.withGroupId(account.groupId()) //
.build();
}
}
@@ -0,0 +1,12 @@
package org.mifosplatform.portfolio.savings.service;
import java.util.Collection;
import org.mifosplatform.infrastructure.core.data.EnumOptionData;
public interface SavingsDropdownReadPlatformService {
Collection<EnumOptionData> retrieveInterestRatePeriodFrequencyTypeOptions();
Collection<EnumOptionData> retrieveLockinPeriodFrequencyTypeOptions();
}
@@ -0,0 +1,34 @@
package org.mifosplatform.portfolio.savings.service;
import java.util.Arrays;
import java.util.List;
import org.mifosplatform.infrastructure.core.data.EnumOptionData;
import org.mifosplatform.portfolio.loanproduct.domain.PeriodFrequencyType;
import org.springframework.stereotype.Service;
@Service
public class SavingsDropdownReadPlatformServiceImpl implements SavingsDropdownReadPlatformService {
@Override
public List<EnumOptionData> retrieveInterestRatePeriodFrequencyTypeOptions() {
List<EnumOptionData> allowedInterestRatePeriodFrequencyTypeOptions = Arrays.asList( //
SavingsEnumerations.interestRatePeriodFrequencyType(PeriodFrequencyType.MONTHS), //
SavingsEnumerations.interestRatePeriodFrequencyType(PeriodFrequencyType.YEARS) //
);
return allowedInterestRatePeriodFrequencyTypeOptions;
}
@Override
public List<EnumOptionData> retrieveLockinPeriodFrequencyTypeOptions() {
List<EnumOptionData> allowedLockinPeriodFrequencyTypeOptions = Arrays.asList( //
SavingsEnumerations.lockinPeriodFrequencyType(PeriodFrequencyType.DAYS), //
SavingsEnumerations.lockinPeriodFrequencyType(PeriodFrequencyType.WEEKS), //
SavingsEnumerations.lockinPeriodFrequencyType(PeriodFrequencyType.MONTHS), //
SavingsEnumerations.lockinPeriodFrequencyType(PeriodFrequencyType.YEARS) //
);
return allowedLockinPeriodFrequencyTypeOptions;
}
}
@@ -0,0 +1,74 @@
/**
* 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.data.EnumOptionData;
import org.mifosplatform.portfolio.loanproduct.domain.PeriodFrequencyType;
public class SavingsEnumerations {
public static EnumOptionData interestRatePeriodFrequencyType(final int id) {
return interestRatePeriodFrequencyType(PeriodFrequencyType.fromInt(id));
}
public static EnumOptionData interestRatePeriodFrequencyType(final PeriodFrequencyType type) {
final String codePrefix = "savings.interest.rate.";
EnumOptionData optionData = new EnumOptionData(PeriodFrequencyType.INVALID.getValue().longValue(),
PeriodFrequencyType.INVALID.getCode(), "Invalid");
switch (type) {
case INVALID:
break;
case DAYS:
optionData = new EnumOptionData(PeriodFrequencyType.DAYS.getValue().longValue(), codePrefix
+ PeriodFrequencyType.DAYS.getCode(), "Per day");
break;
case WEEKS:
optionData = new EnumOptionData(PeriodFrequencyType.WEEKS.getValue().longValue(), codePrefix
+ PeriodFrequencyType.WEEKS.getCode(), "Per week");
break;
case MONTHS:
optionData = new EnumOptionData(PeriodFrequencyType.MONTHS.getValue().longValue(), codePrefix
+ PeriodFrequencyType.MONTHS.getCode(), "Per month");
break;
case YEARS:
optionData = new EnumOptionData(PeriodFrequencyType.YEARS.getValue().longValue(), codePrefix
+ PeriodFrequencyType.YEARS.getCode(), "Per year");
break;
}
return optionData;
}
public static EnumOptionData lockinPeriodFrequencyType(final int id) {
return lockinPeriodFrequencyType(PeriodFrequencyType.fromInt(id));
}
public static EnumOptionData lockinPeriodFrequencyType(final PeriodFrequencyType type) {
final String codePrefix = "savings.lockin.";
EnumOptionData optionData = new EnumOptionData(PeriodFrequencyType.INVALID.getValue().longValue(),
PeriodFrequencyType.INVALID.getCode(), "Invalid");
switch (type) {
case INVALID:
break;
case DAYS:
optionData = new EnumOptionData(PeriodFrequencyType.DAYS.getValue().longValue(), codePrefix
+ PeriodFrequencyType.DAYS.getCode(), "Days");
break;
case WEEKS:
optionData = new EnumOptionData(PeriodFrequencyType.WEEKS.getValue().longValue(), codePrefix
+ PeriodFrequencyType.WEEKS.getCode(), "Weeks");
break;
case MONTHS:
optionData = new EnumOptionData(PeriodFrequencyType.MONTHS.getValue().longValue(), codePrefix
+ PeriodFrequencyType.MONTHS.getCode(), "Months");
break;
case YEARS:
optionData = new EnumOptionData(PeriodFrequencyType.YEARS.getValue().longValue(), codePrefix
+ PeriodFrequencyType.YEARS.getCode(), "Years");
break;
}
return optionData;
}
}
@@ -0,0 +1,20 @@
/**
* 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.Collection;
import org.mifosplatform.portfolio.savings.data.SavingsProductData;
public interface SavingsProductReadPlatformService {
Collection<SavingsProductData> retrieveAll();
Collection<SavingsProductData> retrieveAllForLookup();
SavingsProductData retrieveOne(Long productId);
}
@@ -0,0 +1,132 @@
/**
* 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.math.BigDecimal;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.util.Collection;
import org.mifosplatform.infrastructure.core.data.EnumOptionData;
import org.mifosplatform.infrastructure.core.domain.JdbcSupport;
import org.mifosplatform.infrastructure.core.service.TenantAwareRoutingDataSource;
import org.mifosplatform.infrastructure.security.service.PlatformSecurityContext;
import org.mifosplatform.organisation.monetary.data.CurrencyData;
import org.mifosplatform.portfolio.loanproduct.domain.PeriodFrequencyType;
import org.mifosplatform.portfolio.savings.data.SavingsProductData;
import org.mifosplatform.portfolio.savings.exception.SavingsProductNotFoundException;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.dao.EmptyResultDataAccessException;
import org.springframework.jdbc.core.JdbcTemplate;
import org.springframework.jdbc.core.RowMapper;
import org.springframework.stereotype.Service;
@Service
public class SavingsProductReadPlatformServiceImpl implements SavingsProductReadPlatformService {
private final PlatformSecurityContext context;
private final JdbcTemplate jdbcTemplate;
private final SavingProductMapper savingsProductRowMapper = new SavingProductMapper();
private final SavingProductLookupMapper savingsProductLookupsRowMapper = new SavingProductLookupMapper();
@Autowired
public SavingsProductReadPlatformServiceImpl(final PlatformSecurityContext context, final TenantAwareRoutingDataSource dataSource) {
this.context = context;
jdbcTemplate = new JdbcTemplate(dataSource);
}
@Override
public Collection<SavingsProductData> retrieveAll() {
this.context.authenticatedUser();
final String sql = "select " + savingsProductRowMapper.schema();
return this.jdbcTemplate.query(sql, savingsProductRowMapper);
}
@Override
public Collection<SavingsProductData> retrieveAllForLookup() {
final String sql = "select " + savingsProductLookupsRowMapper.schema();
return this.jdbcTemplate.query(sql, savingsProductLookupsRowMapper);
}
@Override
public SavingsProductData retrieveOne(final Long savingProductId) {
try {
this.context.authenticatedUser();
final String sql = "select " + savingsProductRowMapper.schema() + " where sp.id = ?";
return this.jdbcTemplate.queryForObject(sql, savingsProductRowMapper, new Object[] { savingProductId });
} catch (EmptyResultDataAccessException e) {
throw new SavingsProductNotFoundException(savingProductId);
}
}
private static final class SavingProductMapper implements RowMapper<SavingsProductData> {
public String schema() {
return "sp.id as id,sp.name as name, sp.description as description, "
+ "sp.currency_code as currencyCode, sp.currency_digits as currencyDigits, "
+ "curr.name as currencyName, curr.internationalized_name_code as currencyNameCode, curr.display_symbol as currencyDisplaySymbol, "
+ "sp.nominal_interest_rate_per_period as interestRate, sp.nominal_interest_rate_period_frequency_enum as interestRatePeriodFrequencyType, "
+ "sp.min_required_opening_balance as minRequiredOpeningBalance, "
+ "sp.lockin_period_frequency as lockinPeriodFrequency, sp.lockin_period_frequency_enum as lockinPeriodFrequencyType " //
+ "from m_savings_product sp " //
+ "join m_currency curr on curr.code = sp.currency_code";
}
@Override
public SavingsProductData mapRow(final ResultSet rs, @SuppressWarnings("unused") final int rowNum) throws SQLException {
Long id = rs.getLong("id");
String name = rs.getString("name");
String description = rs.getString("description");
String currencyCode = rs.getString("currencyCode");
String currencyName = rs.getString("currencyName");
String currencyNameCode = rs.getString("currencyNameCode");
String currencyDisplaySymbol = rs.getString("currencyDisplaySymbol");
Integer currencyDigits = JdbcSupport.getInteger(rs, "currencyDigits");
final CurrencyData currency = new CurrencyData(currencyCode, currencyName, currencyDigits, currencyDisplaySymbol,
currencyNameCode);
BigDecimal interestRate = rs.getBigDecimal("interestRate");
EnumOptionData interestRatePeriodFrequencyType = SavingsEnumerations.interestRatePeriodFrequencyType(PeriodFrequencyType
.fromInt(JdbcSupport.getInteger(rs, "interestRatePeriodFrequencyType")));
final BigDecimal minRequiredOpeningBalance = rs.getBigDecimal("minRequiredOpeningBalance");
Integer lockinPeriodFrequency = JdbcSupport.getInteger(rs, "lockinPeriodFrequency");
EnumOptionData lockinPeriodFrequencyType = null;
final Integer lockinPeriodFrequencyTypeValue = JdbcSupport.getInteger(rs, "lockinPeriodFrequencyType");
if (lockinPeriodFrequencyTypeValue != null) {
lockinPeriodFrequencyType = SavingsEnumerations.interestRatePeriodFrequencyType(PeriodFrequencyType
.fromInt(lockinPeriodFrequencyTypeValue));
}
return SavingsProductData.instance(id, name, description, currency, interestRate, interestRatePeriodFrequencyType,
minRequiredOpeningBalance, lockinPeriodFrequency, lockinPeriodFrequencyType);
}
}
private static final class SavingProductLookupMapper implements RowMapper<SavingsProductData> {
public String schema() {
return " sp.id as id, sp.name as name from m_savings_product sp";
}
@Override
public SavingsProductData mapRow(final ResultSet rs, @SuppressWarnings("unused") final int rowNum) throws SQLException {
final Long id = rs.getLong("id");
final String name = rs.getString("name");
return SavingsProductData.lookup(id, name);
}
}
}
@@ -3,16 +3,16 @@
* 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.savingsaccountproduct.service;
package org.mifosplatform.portfolio.savings.service;
import org.mifosplatform.infrastructure.core.api.JsonCommand;
import org.mifosplatform.infrastructure.core.data.CommandProcessingResult;
public interface SavingProductWritePlatformService {
public interface SavingsProductWritePlatformService {
CommandProcessingResult createSavingProduct(JsonCommand command);
CommandProcessingResult create(JsonCommand command);
CommandProcessingResult updateSavingProduct(Long productId, JsonCommand command);
CommandProcessingResult update(Long productId, JsonCommand command);
CommandProcessingResult deleteSavingProduct(Long productId);
CommandProcessingResult delete(Long productId);
}
@@ -0,0 +1,131 @@
/**
* 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.Map;
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.security.service.PlatformSecurityContext;
import org.mifosplatform.portfolio.savings.data.SavingsProductDataValidator;
import org.mifosplatform.portfolio.savings.domain.SavingsProduct;
import org.mifosplatform.portfolio.savings.domain.SavingsProductAssembler;
import org.mifosplatform.portfolio.savings.domain.SavingsProductRepository;
import org.mifosplatform.portfolio.savings.exception.SavingsProductNotFoundException;
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 SavingsProductWritePlatformServiceJpaRepositoryImpl implements SavingsProductWritePlatformService {
private final Logger logger;
private final PlatformSecurityContext context;
private final SavingsProductRepository savingProductRepository;
private final SavingsProductDataValidator fromApiJsonDataValidator;
private final SavingsProductAssembler savingsProductAssembler;
@Autowired
public SavingsProductWritePlatformServiceJpaRepositoryImpl(final PlatformSecurityContext context,
final SavingsProductRepository savingProductRepository, final SavingsProductDataValidator fromApiJsonDataValidator,
final SavingsProductAssembler savingsProductAssembler) {
this.context = context;
this.savingProductRepository = savingProductRepository;
this.fromApiJsonDataValidator = fromApiJsonDataValidator;
this.savingsProductAssembler = savingsProductAssembler;
this.logger = LoggerFactory.getLogger(SavingsProductWritePlatformServiceJpaRepositoryImpl.class);
}
/*
* Guaranteed to throw an exception no matter what the data integrity issue
* is.
*/
private void handleDataIntegrityIssues(final JsonCommand command, final DataAccessException dae) {
final Throwable realCause = dae.getMostSpecificCause();
if (realCause.getMessage().contains("sp_unq_name")) {
final String name = command.stringValueOfParameterNamed("name");
throw new PlatformDataIntegrityException("error.msg.product.savings.duplicate.name", "Savings product with name `" + name
+ "` already exists", "name", name);
}
logAsErrorUnexpectedDataIntegrityException(dae);
throw new PlatformDataIntegrityException("error.msg.savingsproduct.unknown.data.integrity.issue",
"Unknown data integrity issue with resource.");
}
private void logAsErrorUnexpectedDataIntegrityException(final DataAccessException dae) {
logger.error(dae.getMessage(), dae);
}
@Transactional
@Override
public CommandProcessingResult create(final JsonCommand command) {
try {
this.context.authenticatedUser();
this.fromApiJsonDataValidator.validateForCreate(command.json());
final SavingsProduct product = this.savingsProductAssembler.assemble(command);
this.savingProductRepository.save(product);
return new CommandProcessingResultBuilder() //
.withEntityId(product.getId()) //
.build();
} catch (DataAccessException e) {
handleDataIntegrityIssues(command, e);
return CommandProcessingResult.empty();
}
}
@Transactional
@Override
public CommandProcessingResult update(final Long productId, final JsonCommand command) {
try {
this.context.authenticatedUser();
this.fromApiJsonDataValidator.validateForUpdate(command.json());
final SavingsProduct product = this.savingProductRepository.findOne(productId);
if (product == null) { throw new SavingsProductNotFoundException(productId); }
final Map<String, Object> changes = product.update(command);
if (!changes.isEmpty()) {
this.savingProductRepository.saveAndFlush(product);
}
return new CommandProcessingResultBuilder() //
.withEntityId(product.getId()) //
.with(changes).build();
} catch (DataAccessException e) {
handleDataIntegrityIssues(command, e);
return CommandProcessingResult.empty();
}
}
@Transactional
@Override
public CommandProcessingResult delete(final Long productId) {
this.context.authenticatedUser();
final SavingsProduct product = this.savingProductRepository.findOne(productId);
if (product == null) { throw new SavingsProductNotFoundException(productId); }
this.savingProductRepository.delete(product);
return new CommandProcessingResultBuilder() //
.withEntityId(product.getId()) //
.build();
}
}
@@ -1,330 +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.savingsaccount.api;
import java.math.BigDecimal;
import java.util.Arrays;
import java.util.Collection;
import java.util.HashSet;
import java.util.List;
import java.util.Set;
import javax.ws.rs.Consumes;
import javax.ws.rs.DELETE;
import javax.ws.rs.GET;
import javax.ws.rs.POST;
import javax.ws.rs.PUT;
import javax.ws.rs.Path;
import javax.ws.rs.PathParam;
import javax.ws.rs.Produces;
import javax.ws.rs.QueryParam;
import javax.ws.rs.core.Context;
import javax.ws.rs.core.MediaType;
import javax.ws.rs.core.UriInfo;
import org.apache.commons.lang.StringUtils;
import org.mifosplatform.commands.domain.CommandWrapper;
import org.mifosplatform.commands.service.CommandWrapperBuilder;
import org.mifosplatform.commands.service.PortfolioCommandSourceWritePlatformService;
import org.mifosplatform.infrastructure.core.api.ApiParameterHelper;
import org.mifosplatform.infrastructure.core.api.ApiRequestParameterHelper;
import org.mifosplatform.infrastructure.core.api.JsonQuery;
import org.mifosplatform.infrastructure.core.data.CommandProcessingResult;
import org.mifosplatform.infrastructure.core.data.EnumOptionData;
import org.mifosplatform.infrastructure.core.exception.UnrecognizedQueryParamException;
import org.mifosplatform.infrastructure.core.serialization.ApiRequestJsonSerializationSettings;
import org.mifosplatform.infrastructure.core.serialization.DefaultToApiJsonSerializer;
import org.mifosplatform.infrastructure.core.serialization.FromJsonHelper;
import org.mifosplatform.infrastructure.core.serialization.ToApiJsonSerializer;
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.savingsaccount.data.SavingAccountData;
import org.mifosplatform.portfolio.savingsaccount.data.SavingAccountForLookup;
import org.mifosplatform.portfolio.savingsaccount.data.SavingAccountTransactionsData;
import org.mifosplatform.portfolio.savingsaccount.data.SavingPermissionData;
import org.mifosplatform.portfolio.savingsaccount.data.SavingScheduleData;
import org.mifosplatform.portfolio.savingsaccount.service.CalculateSavingSchedule;
import org.mifosplatform.portfolio.savingsaccount.service.SavingAccountReadPlatformService;
import org.mifosplatform.portfolio.savingsaccount.service.SavingAccountWritePlatformService;
import org.mifosplatform.portfolio.savingsaccountproduct.data.SavingProductLookup;
import org.mifosplatform.portfolio.savingsaccountproduct.domain.SavingFrequencyType;
import org.mifosplatform.portfolio.savingsaccountproduct.domain.SavingInterestCalculationMethod;
import org.mifosplatform.portfolio.savingsaccountproduct.domain.SavingProductType;
import org.mifosplatform.portfolio.savingsaccountproduct.domain.SavingsInterestType;
import org.mifosplatform.portfolio.savingsaccountproduct.domain.SavingsLockinPeriodEnum;
import org.mifosplatform.portfolio.savingsaccountproduct.service.SavingProductEnumerations;
import org.mifosplatform.portfolio.savingsaccountproduct.service.SavingProductReadPlatformService;
import org.mifosplatform.portfolio.savingsdepositproduct.domain.TenureTypeEnum;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Scope;
import org.springframework.stereotype.Component;
import com.google.gson.JsonElement;
@Path("/savingaccounts")
@Component
@Scope("singleton")
public class SavingsAccountApiResource {
private final Set<String> SAVINGS_ACCOUNTS_DATA_PARAMETERS = new HashSet<String>(Arrays.asList("id", "status", "externalId",
"clientId", "clientName", "productId", "productName", "productType", "currencyData", "savingsDepostiAmountPerPeriod",
"savingsFrequencyType", "totalDepositAmount", "reccuringInterestRate", "savingInterestRate", "interestType",
"interestCalculationMethod", "tenure", "tenureType", "projectedCommencementDate", "actualCommencementDate", "maturesOnDate",
"projectedInterestAccuredOnMaturity", "actualInterestAccured", "projectedMaturityAmount", "actualMaturityAmount",
"outstandingAmount", "preClosureAllowed", "preClosureInterestRate", "withdrawnonDate", "rejectedonDate", "closedonDate",
"isLockinPeriodAllowed", "lockinPeriod", "lockinPeriodType", "productOptions", "currencyOptions", "savingsProductTypeOptions",
"tenureTypeOptions", "savingFrequencyOptions", "savingsInterestTypeOptions", "lockinPeriodTypeOptions",
"interestCalculationOptions", "permissions", "savingScheduleDatas", "dueAmount", "savingScheduleData", "transactions",
"interestPostEvery", "interestPostFrequency"));
private final SavingAccountWritePlatformService savingAccountWritePlatformService;
private final SavingAccountReadPlatformService savingAccountReadPlatformService;
private final SavingProductReadPlatformService savingProductReadPlatformService;
private final CurrencyReadPlatformService currencyReadPlatformService;
private final String entityType = "SAVINGSACCOUNT";
private final PlatformSecurityContext context;
private final CalculateSavingSchedule calculateSavingSchedule;
private final ToApiJsonSerializer<SavingAccountData> toApiJsonSerializer;
private final ApiRequestParameterHelper apiRequestParameterHelper;
private final PortfolioCommandSourceWritePlatformService commandsSourceWritePlatformService;
private final FromJsonHelper fromJsonHelper;
private final DefaultToApiJsonSerializer<SavingScheduleData> savingScheduleToApiJsonSerializer;
@Autowired
public SavingsAccountApiResource(final SavingAccountWritePlatformService savingAccountWritePlatformService,
final SavingAccountReadPlatformService savingAccountReadPlatformService,
final SavingProductReadPlatformService savingProductReadPlatformService,
final CurrencyReadPlatformService currencyReadPlatformService, final PlatformSecurityContext context,
final CalculateSavingSchedule calculateSavingSchedule, final ToApiJsonSerializer<SavingAccountData> toApiJsonSerializer,
final ApiRequestParameterHelper apiRequestParameterHelper,
final PortfolioCommandSourceWritePlatformService commandsSourceWritePlatformService, final FromJsonHelper fromJsonHelper,
final DefaultToApiJsonSerializer<SavingScheduleData> savingScheduleToApiJsonSerializer) {
this.savingAccountWritePlatformService = savingAccountWritePlatformService;
this.savingAccountReadPlatformService = savingAccountReadPlatformService;
this.savingProductReadPlatformService = savingProductReadPlatformService;
this.currencyReadPlatformService = currencyReadPlatformService;
this.context = context;
this.calculateSavingSchedule = calculateSavingSchedule;
this.toApiJsonSerializer = toApiJsonSerializer;
this.apiRequestParameterHelper = apiRequestParameterHelper;
this.commandsSourceWritePlatformService = commandsSourceWritePlatformService;
this.fromJsonHelper = fromJsonHelper;
this.savingScheduleToApiJsonSerializer = savingScheduleToApiJsonSerializer;
}
@POST
@Consumes({ MediaType.APPLICATION_JSON })
@Produces({ MediaType.APPLICATION_JSON })
public String createSavingAccount(@QueryParam("command") final String commandParam, @Context final UriInfo uriInfo,
final String apiRequestBodyAsJson) {
if (is(commandParam, "calculateSavingSchedule")) {
final JsonElement parsedQuery = this.fromJsonHelper.parse(apiRequestBodyAsJson);
final JsonQuery query = JsonQuery.from(apiRequestBodyAsJson, parsedQuery, this.fromJsonHelper);
SavingScheduleData savingSchedule = this.calculateSavingSchedule.calculateSavingSchedule(query);
final ApiRequestJsonSerializationSettings settings = apiRequestParameterHelper.process(uriInfo.getQueryParameters());
return this.savingScheduleToApiJsonSerializer.serialize(settings, savingSchedule, new HashSet<String>());
}
final CommandWrapper commandRequest = new CommandWrapperBuilder().createSavingAccount().withJson(apiRequestBodyAsJson).build();
final CommandProcessingResult result = this.commandsSourceWritePlatformService.logCommandSource(commandRequest);
return this.toApiJsonSerializer.serialize(result);
}
@PUT
@Path("{accountId}")
@Consumes({ MediaType.APPLICATION_JSON })
@Produces({ MediaType.APPLICATION_JSON })
public String updateSavingAccount(@PathParam("accountId") final Long accountId, final String apiRequestBodyAsJson) {
final CommandWrapper commandRequest = new CommandWrapperBuilder().updateSavingAccount(accountId).withJson(apiRequestBodyAsJson)
.build();
final CommandProcessingResult result = this.commandsSourceWritePlatformService.logCommandSource(commandRequest);
return this.toApiJsonSerializer.serialize(result);
}
@GET
@Consumes({ MediaType.APPLICATION_JSON })
@Produces({ MediaType.APPLICATION_JSON })
public String retrieveAllDepositAccounts(@Context final UriInfo uriInfo) {
context.authenticatedUser().validateHasReadPermission(entityType);
Collection<SavingAccountData> accounts = this.savingAccountReadPlatformService.retrieveAllSavingsAccounts();
final ApiRequestJsonSerializationSettings settings = apiRequestParameterHelper.process(uriInfo.getQueryParameters());
return this.toApiJsonSerializer.serialize(settings, accounts, SAVINGS_ACCOUNTS_DATA_PARAMETERS);
}
@GET
@Path("{accountId}")
@Consumes({ MediaType.APPLICATION_JSON })
@Produces({ MediaType.APPLICATION_JSON })
public String retrieveDepositAccount(@PathParam("accountId") final Long accountId, @Context final UriInfo uriInfo) {
context.authenticatedUser().validateHasReadPermission(entityType);
SavingPermissionData permissions = null;
SavingScheduleData savingScheduleData = null;
Collection<SavingAccountTransactionsData> transactions = null;
SavingAccountData account = this.savingAccountReadPlatformService.retrieveSavingsAccount(accountId);
final ApiRequestJsonSerializationSettings settings = apiRequestParameterHelper.process(uriInfo.getQueryParameters());
if (settings.isTemplate()) {
account = handleTemplateRelatedData(account);
}
Set<String> associationParameters = ApiParameterHelper.extractAssociationsForResponseIfProvided(uriInfo.getQueryParameters());
if (!associationParameters.isEmpty()) {
if (associationParameters.contains("all")) {
associationParameters.addAll(Arrays.asList("savingScheduleData", "transactions"));
}
if (associationParameters.contains("savingScheduleData")) {
CurrencyData currencyData = account.getCurrencyData();
savingScheduleData = this.savingAccountReadPlatformService.retrieveSavingsAccountSchedule(accountId, currencyData);
account = new SavingAccountData(account, savingScheduleData);
}
if (associationParameters.contains("transactions")) {
transactions = this.savingAccountReadPlatformService.retrieveSavingsAccountTransactions(accountId);
account = new SavingAccountData(account, transactions);
}
permissions = this.savingAccountReadPlatformService.retrieveSavingAccountPermissions(account);
account = new SavingAccountData(account, permissions);
}
return this.toApiJsonSerializer.serialize(settings, account, SAVINGS_ACCOUNTS_DATA_PARAMETERS);
}
@GET
@Path("template")
@Consumes({ MediaType.APPLICATION_JSON })
@Produces({ MediaType.APPLICATION_JSON })
public String retrieveNewDepositAccountDetails(@QueryParam("clientId") final Long clientId,
@QueryParam("productId") final Long productId, @Context final UriInfo uriInfo) {
context.authenticatedUser().validateHasReadPermission(entityType);
SavingAccountData account = this.savingAccountReadPlatformService.retrieveNewSavingsAccountDetails(clientId, productId);
account = handleTemplateRelatedData(account);
final ApiRequestJsonSerializationSettings settings = apiRequestParameterHelper.process(uriInfo.getQueryParameters());
return this.toApiJsonSerializer.serialize(settings, account, SAVINGS_ACCOUNTS_DATA_PARAMETERS);
}
private SavingAccountData handleTemplateRelatedData(final SavingAccountData account) {
Collection<SavingProductLookup> productOptions = savingProductReadPlatformService.retrieveAllSavingProductsForLookup();
Collection<CurrencyData> currencyOptions = this.currencyReadPlatformService.retrieveAllowedCurrencies();
EnumOptionData recurring = SavingProductEnumerations.savingProductType(SavingProductType.RECURRING);
EnumOptionData regular = SavingProductEnumerations.savingProductType(SavingProductType.REGULAR);
List<EnumOptionData> savingsProductTypeOptions = Arrays.asList(recurring, regular);
EnumOptionData fixed = SavingProductEnumerations.tenureTypeEnum(TenureTypeEnum.FIXED_PERIOD);
EnumOptionData perpetual = SavingProductEnumerations.tenureTypeEnum(TenureTypeEnum.PERPETUAL);
List<EnumOptionData> tenureTypeOptions = Arrays.asList(fixed, perpetual);
EnumOptionData monthly = SavingProductEnumerations.interestFrequencyType(SavingFrequencyType.MONTHLY);
List<EnumOptionData> savingFrequencyOptions = Arrays.asList(monthly);
EnumOptionData simple = SavingProductEnumerations.savingInterestType(SavingsInterestType.SIMPLE);
EnumOptionData compounding = SavingProductEnumerations.savingInterestType(SavingsInterestType.COMPOUNDING);
List<EnumOptionData> savingsInterestTypeOptions = Arrays.asList(simple, compounding);
EnumOptionData months = SavingProductEnumerations.savingsLockinPeriod(SavingsLockinPeriodEnum.MONTHS);
List<EnumOptionData> lockinPeriodTypeOptions = Arrays.asList(months);
EnumOptionData averagebal = SavingProductEnumerations.savingInterestCalculationMethod(SavingInterestCalculationMethod.AVERAGEBAL);
// EnumOptionData minbal =
// SavingProductEnumerations.savingInterestCalculationMethod(SavingInterestCalculationMethod.MINBAL);
EnumOptionData monthlyCollection = SavingProductEnumerations
.savingInterestCalculationMethod(SavingInterestCalculationMethod.MONTHLYCOLLECTION);
List<EnumOptionData> interestCalculationOptions = Arrays.asList(averagebal, monthlyCollection);
BigDecimal dueAmount = this.savingAccountReadPlatformService.deriveSavingDueAmount(account);
return new SavingAccountData(account, productOptions, currencyOptions, savingsProductTypeOptions, tenureTypeOptions,
savingFrequencyOptions, savingsInterestTypeOptions, lockinPeriodTypeOptions, interestCalculationOptions, dueAmount);
}
private boolean is(final String commandParam, final String commandValue) {
return StringUtils.isNotBlank(commandParam) && commandParam.trim().equalsIgnoreCase(commandValue);
}
@POST
@Path("{accountId}")
@Consumes({ MediaType.APPLICATION_JSON })
@Produces({ MediaType.APPLICATION_JSON })
public String savingStateTransitions(@PathParam("accountId") final Long accountId, @QueryParam("command") final String commandParam,
final String apiRequestBodyAsJson) {
CommandWrapperBuilder builder = new CommandWrapperBuilder().withJson(apiRequestBodyAsJson);
CommandProcessingResult result = null;
if (is(commandParam, "approve")) {
final CommandWrapper commandRequest = builder.approveSavingAccountApplication(accountId).build();
result = this.commandsSourceWritePlatformService.logCommandSource(commandRequest);
} else if (is(commandParam, "depositmoney")) {
final CommandWrapper commandRequest = builder.depositOfSavingAmount(accountId).build();
result = this.commandsSourceWritePlatformService.logCommandSource(commandRequest);
} else if (is(commandParam, "withdraw")) {
final CommandWrapper commandRequest = builder.withdrawSavingAmount(accountId).build();
result = this.commandsSourceWritePlatformService.logCommandSource(commandRequest);
} else if (is(commandParam, "reject")) {
final CommandWrapper commandRequest = builder.rejectSavingApplication(accountId).build();
result = this.commandsSourceWritePlatformService.logCommandSource(commandRequest);
} else if (is(commandParam, "withdrewbyclient")) {
final CommandWrapper commandRequest = builder.withdrawSavingApplication(accountId).build();
result = this.commandsSourceWritePlatformService.logCommandSource(commandRequest);
} else if (is(commandParam, "undoapproval")) {
final CommandWrapper commandRequest = builder.undoApprovalOfSavingApplication(accountId).build();
result = this.commandsSourceWritePlatformService.logCommandSource(commandRequest);
} else {
throw new UnrecognizedQueryParamException("command", commandParam);
}
return this.toApiJsonSerializer.serialize(result);
}
@DELETE
@Path("{accountId}")
@Consumes({ MediaType.APPLICATION_JSON })
@Produces({ MediaType.APPLICATION_JSON })
public String deleteSavingAccount(@PathParam("accountId") final Long accountId) {
final CommandWrapper commandRequest = new CommandWrapperBuilder().deleteSavingAccount(accountId).build();
final CommandProcessingResult result = this.commandsSourceWritePlatformService.logCommandSource(commandRequest);
return this.toApiJsonSerializer.serialize(result);
}
@POST
@Path("postinterest")
@Consumes({ MediaType.APPLICATION_JSON })
@Produces({ MediaType.APPLICATION_JSON })
public String postInterest() {
Collection<SavingAccountForLookup> savingAccounts = this.savingAccountReadPlatformService.retrieveSavingAccountsForLookUp();
CommandProcessingResult entityIdentifier = this.savingAccountWritePlatformService.postInterest(savingAccounts);
return this.toApiJsonSerializer.serialize(entityIdentifier);
}
}
@@ -1,511 +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.savingsaccount.data;
import java.math.BigDecimal;
import java.util.ArrayList;
import java.util.Collection;
import java.util.List;
import org.joda.time.LocalDate;
import org.mifosplatform.infrastructure.core.data.EnumOptionData;
import org.mifosplatform.organisation.monetary.data.CurrencyData;
import org.mifosplatform.portfolio.savingsaccountproduct.data.SavingProductLookup;
/**
* Immutable data object representing a savings account.
*/
public class SavingAccountData {
private final Long id;
private final EnumOptionData status;
private final String externalId;
private final Long clientId;
private final String clientName;
private final Long productId;
private final String productName;
private final EnumOptionData productType;
private final CurrencyData currencyData;
private final BigDecimal savingsDepositAmountPerPeriod;
private final EnumOptionData savingsFrequencyType;
private final BigDecimal totalDepositAmount;
private final BigDecimal recurringInterestRate;
private final BigDecimal savingInterestRate;
private final EnumOptionData interestType;
private final EnumOptionData interestCalculationMethod;
private final Integer tenure;
private final EnumOptionData tenureType;
private final LocalDate projectedCommencementDate;
private final LocalDate actualCommencementDate;
private final LocalDate maturesOnDate;
private final BigDecimal projectedInterestAccuredOnMaturity;
private final BigDecimal actualInterestAccured;
private final BigDecimal projectedMaturityAmount;
private final BigDecimal actualMaturityAmount;
private final boolean preClosureAllowed;
private final BigDecimal preClosureInterestRate;
private final LocalDate withdrawnonDate;
private final LocalDate rejectedonDate;
private final LocalDate closedonDate;
private final boolean isLockinPeriodAllowed;
private final Integer lockinPeriod;
private final EnumOptionData lockinPeriodType;
private final Integer depositEvery;
private final List<SavingProductLookup> productOptions;
private final Collection<CurrencyData> currencyOptions;
private final List<EnumOptionData> savingsProductTypeOptions;
private final List<EnumOptionData> tenureTypeOptions;
private final List<EnumOptionData> savingFrequencyOptions;
private final List<EnumOptionData> savingsInterestTypeOptions;
private final List<EnumOptionData> lockinPeriodTypeOptions;
private final List<EnumOptionData> interestCalculationOptions;
private final Collection<SavingScheduleData> savingScheduleDatas;
private final SavingPermissionData permissions;
private final BigDecimal outstandingAmount;
private final BigDecimal dueAmount;
private final SavingScheduleData savingScheduleData;
private final Collection<SavingAccountTransactionsData> transactions;
private final Integer interestPostEvery;
private final EnumOptionData interestPostFrequency;
public static SavingAccountData createFrom(final Long clientId, final String clientDisplayName) {
return new SavingAccountData(clientId, clientDisplayName);
}
public SavingAccountData(final Long id, final EnumOptionData status, final String externalId, final Long clientId,
final String clientName, final Long productId, final String productName, final EnumOptionData productType,
final CurrencyData currencyData, final BigDecimal savingsDepositAmountPerPeriod, final EnumOptionData savingsFrequencyType,
final BigDecimal totalDepositAmount, final BigDecimal recurringInterestRate, final BigDecimal savingInterestRate,
final EnumOptionData interestType, final EnumOptionData interestCalculationMethod, final Integer tenure,
final EnumOptionData tenureType, final LocalDate projectedCommencementDate, final LocalDate actualCommencementDate,
final LocalDate maturesOnDate, final BigDecimal projectedInterestAccuredOnMaturity, final BigDecimal actualInterestAccured,
final BigDecimal projectedMaturityAmount, final BigDecimal actualMaturityAmount, final boolean preClosureAllowed,
final BigDecimal preClosureInterestRate, final LocalDate withdrawnonDate, final LocalDate rejectedonDate,
final LocalDate closedonDate, final boolean isLockinPeriodAllowed, final Integer lockinPeriod,
final EnumOptionData lockinPeriodType, final Integer depositEvery, final BigDecimal outstandingAmount,
final Integer interestPostEvery, final EnumOptionData interestPostFrequency) {
this.id = id;
this.status = status;
this.externalId = externalId;
this.clientId = clientId;
this.clientName = clientName;
this.productId = productId;
this.productName = productName;
this.productType = productType;
this.currencyData = currencyData;
this.savingsDepositAmountPerPeriod = savingsDepositAmountPerPeriod;
this.savingsFrequencyType = savingsFrequencyType;
this.totalDepositAmount = totalDepositAmount;
this.recurringInterestRate = recurringInterestRate;
this.savingInterestRate = savingInterestRate;
this.interestType = interestType;
this.interestCalculationMethod = interestCalculationMethod;
this.tenure = tenure;
this.tenureType = tenureType;
this.projectedCommencementDate = projectedCommencementDate;
this.actualCommencementDate = actualCommencementDate;
this.maturesOnDate = maturesOnDate;
this.projectedInterestAccuredOnMaturity = projectedInterestAccuredOnMaturity;
this.actualInterestAccured = actualInterestAccured;
this.projectedMaturityAmount = projectedMaturityAmount;
this.actualMaturityAmount = actualMaturityAmount;
this.preClosureAllowed = preClosureAllowed;
this.preClosureInterestRate = preClosureInterestRate;
this.withdrawnonDate = withdrawnonDate;
this.rejectedonDate = rejectedonDate;
this.closedonDate = closedonDate;
this.isLockinPeriodAllowed = isLockinPeriodAllowed;
this.lockinPeriod = lockinPeriod;
this.lockinPeriodType = lockinPeriodType;
this.depositEvery = depositEvery;
this.productOptions = new ArrayList<SavingProductLookup>();
this.currencyOptions = null;
this.savingsProductTypeOptions = null;
this.tenureTypeOptions = null;
this.savingFrequencyOptions = null;
this.savingsInterestTypeOptions = null;
this.lockinPeriodTypeOptions = null;
this.interestCalculationOptions = null;
this.savingScheduleDatas = null;
this.permissions = null;
this.outstandingAmount = outstandingAmount;
this.dueAmount = BigDecimal.ZERO;
this.savingScheduleData = null;
this.transactions = null;
this.interestPostEvery = interestPostEvery;
this.interestPostFrequency = interestPostFrequency;
}
public SavingAccountData(final Long clientId, final String clientName) {
this.id = null;
this.status = null;
this.externalId = null;
this.clientId = clientId;
this.clientName = clientName;
this.productId = null;
this.productName = null;
this.productType = null;
this.currencyData = new CurrencyData("USD", "US Dollar", 2, "$", "currency.USD");
this.savingsDepositAmountPerPeriod = null;
this.savingsFrequencyType = null;
this.totalDepositAmount = null;
this.recurringInterestRate = null;
this.savingInterestRate = null;
this.interestType = null;
this.interestCalculationMethod = null;
this.tenure = null;
this.tenureType = null;
this.projectedCommencementDate = null;
this.actualCommencementDate = null;
this.maturesOnDate = null;
this.projectedInterestAccuredOnMaturity = null;
this.actualInterestAccured = null;
this.projectedMaturityAmount = null;
this.actualMaturityAmount = null;
this.preClosureAllowed = false;
this.preClosureInterestRate = null;
this.withdrawnonDate = null;
this.rejectedonDate = null;
this.closedonDate = null;
this.isLockinPeriodAllowed = false;
this.lockinPeriod = null;
this.lockinPeriodType = null;
this.depositEvery = null;
this.productOptions = new ArrayList<SavingProductLookup>();
this.currencyOptions = null;
this.savingsProductTypeOptions = null;
this.tenureTypeOptions = null;
this.savingFrequencyOptions = null;
this.savingsInterestTypeOptions = null;
this.lockinPeriodTypeOptions = null;
this.interestCalculationOptions = null;
this.savingScheduleDatas = null;
this.permissions = null;
this.outstandingAmount = BigDecimal.ZERO;
this.dueAmount = BigDecimal.ZERO;
this.savingScheduleData = null;
this.transactions = null;
this.interestPostEvery = null;
this.interestPostFrequency = null;
}
public SavingAccountData(final SavingAccountData account, final Collection<SavingProductLookup> productOptions,
final Collection<CurrencyData> currencyOptions, final List<EnumOptionData> savingsProductTypeOptions,
final List<EnumOptionData> tenureTypeOptions, final List<EnumOptionData> savingFrequencyOptions,
final List<EnumOptionData> savingsInterestTypeOptions, final List<EnumOptionData> lockinPeriodTypeOptions,
final List<EnumOptionData> interestCalculationOptions, final BigDecimal dueAmount) {
this.id = account.id;
this.status = account.status;
this.externalId = account.externalId;
this.clientId = account.clientId;
this.clientName = account.clientName;
this.productId = account.productId;
this.productName = account.productName;
this.productType = account.productType;
this.currencyData = account.currencyData;
this.savingsDepositAmountPerPeriod = account.savingsDepositAmountPerPeriod;
this.savingsFrequencyType = account.savingsFrequencyType;
this.totalDepositAmount = account.totalDepositAmount;
this.recurringInterestRate = account.recurringInterestRate;
this.savingInterestRate = account.savingInterestRate;
this.interestType = account.interestType;
this.interestCalculationMethod = account.interestCalculationMethod;
this.tenure = account.tenure;
this.tenureType = account.tenureType;
this.projectedCommencementDate = account.projectedCommencementDate;
this.actualCommencementDate = account.actualCommencementDate;
this.maturesOnDate = account.maturesOnDate;
this.projectedInterestAccuredOnMaturity = account.projectedInterestAccuredOnMaturity;
this.actualInterestAccured = account.actualInterestAccured;
this.projectedMaturityAmount = account.projectedMaturityAmount;
this.actualMaturityAmount = account.actualMaturityAmount;
this.preClosureAllowed = account.preClosureAllowed;
this.preClosureInterestRate = account.preClosureInterestRate;
this.withdrawnonDate = account.withdrawnonDate;
this.rejectedonDate = account.rejectedonDate;
this.closedonDate = account.closedonDate;
this.isLockinPeriodAllowed = account.isLockinPeriodAllowed;
this.lockinPeriod = account.lockinPeriod;
this.lockinPeriodType = account.lockinPeriodType;
this.depositEvery = account.depositEvery;
this.productOptions = (List<SavingProductLookup>) productOptions;
this.currencyOptions = currencyOptions;
this.savingsProductTypeOptions = savingsProductTypeOptions;
this.tenureTypeOptions = tenureTypeOptions;
this.savingFrequencyOptions = savingFrequencyOptions;
this.savingsInterestTypeOptions = savingsInterestTypeOptions;
this.lockinPeriodTypeOptions = lockinPeriodTypeOptions;
this.interestCalculationOptions = interestCalculationOptions;
this.dueAmount = dueAmount;
this.savingScheduleDatas = account.savingScheduleDatas;
this.permissions = account.permissions;
this.outstandingAmount = account.outstandingAmount;
this.savingScheduleData = account.savingScheduleData;
this.transactions = account.transactions;
this.interestPostEvery = account.interestPostEvery;
this.interestPostFrequency = account.interestPostFrequency;
}
public SavingAccountData(final Long clientId, final String clientName, final Long productId, final String productName,
final CurrencyData currency, final BigDecimal interestRate, final BigDecimal savingsDepositAmountPerPeriod,
final EnumOptionData productType, final EnumOptionData tenureType, final Integer tenure,
final EnumOptionData savingsFrequencyType, final EnumOptionData interestType, final EnumOptionData interestCalculationMethod,
final boolean lockinPeriodAllowed, final Integer lockinPeriod, final EnumOptionData lockinPeriodType, final Integer depositEvery) {
this.id = null;
this.status = null;
this.externalId = null;
this.clientId = clientId;
this.clientName = clientName;
this.productId = productId;
this.productName = productName;
this.productType = productType;
this.currencyData = currency;
this.savingsDepositAmountPerPeriod = savingsDepositAmountPerPeriod;
this.savingsFrequencyType = savingsFrequencyType;
this.totalDepositAmount = null;
this.recurringInterestRate = interestRate;
this.savingInterestRate = interestRate;
this.interestType = interestType;
this.interestCalculationMethod = interestCalculationMethod;
this.tenure = tenure;
this.tenureType = tenureType;
this.projectedCommencementDate = new LocalDate();
this.actualCommencementDate = null;
this.maturesOnDate = null;
this.projectedInterestAccuredOnMaturity = null;
this.actualInterestAccured = null;
this.projectedMaturityAmount = null;
this.actualMaturityAmount = null;
this.preClosureAllowed = true;
this.preClosureInterestRate = null;
this.withdrawnonDate = null;
this.rejectedonDate = null;
this.closedonDate = null;
this.isLockinPeriodAllowed = lockinPeriodAllowed;
this.lockinPeriod = lockinPeriod;
this.lockinPeriodType = lockinPeriodType;
this.depositEvery = depositEvery;
this.productOptions = null;
this.currencyOptions = null;
this.savingsProductTypeOptions = null;
this.tenureTypeOptions = null;
this.savingFrequencyOptions = null;
this.savingsInterestTypeOptions = null;
this.lockinPeriodTypeOptions = null;
this.interestCalculationOptions = null;
this.savingScheduleDatas = null;
this.permissions = null;
this.outstandingAmount = BigDecimal.ZERO;
this.dueAmount = BigDecimal.ZERO;
this.savingScheduleData = null;
this.transactions = null;
this.interestPostEvery = 3;
this.interestPostFrequency = savingsFrequencyType;
}
public SavingAccountData(final SavingAccountData account, final SavingPermissionData permissions) {
this.id = account.id;
this.status = account.status;
this.externalId = account.externalId;
this.clientId = account.clientId;
this.clientName = account.clientName;
this.productId = account.productId;
this.productName = account.productName;
this.productType = account.productType;
this.currencyData = account.currencyData;
this.savingsDepositAmountPerPeriod = account.savingsDepositAmountPerPeriod;
this.savingsFrequencyType = account.savingsFrequencyType;
this.totalDepositAmount = account.totalDepositAmount;
this.recurringInterestRate = account.recurringInterestRate;
this.savingInterestRate = account.savingInterestRate;
this.interestType = account.interestType;
this.interestCalculationMethod = account.interestCalculationMethod;
this.tenure = account.tenure;
this.tenureType = account.tenureType;
this.projectedCommencementDate = account.projectedCommencementDate;
this.actualCommencementDate = account.actualCommencementDate;
this.maturesOnDate = account.maturesOnDate;
this.projectedInterestAccuredOnMaturity = account.projectedInterestAccuredOnMaturity;
this.actualInterestAccured = account.actualInterestAccured;
this.projectedMaturityAmount = account.projectedMaturityAmount;
this.actualMaturityAmount = account.actualMaturityAmount;
this.preClosureAllowed = account.preClosureAllowed;
this.preClosureInterestRate = account.preClosureInterestRate;
this.withdrawnonDate = account.withdrawnonDate;
this.rejectedonDate = account.rejectedonDate;
this.closedonDate = account.closedonDate;
this.isLockinPeriodAllowed = account.isLockinPeriodAllowed;
this.lockinPeriod = account.lockinPeriod;
this.lockinPeriodType = account.lockinPeriodType;
this.depositEvery = account.depositEvery;
this.productOptions = account.productOptions;
this.currencyOptions = account.currencyOptions;
this.savingsProductTypeOptions = account.savingsProductTypeOptions;
this.tenureTypeOptions = account.tenureTypeOptions;
this.savingFrequencyOptions = account.savingFrequencyOptions;
this.savingsInterestTypeOptions = account.savingsInterestTypeOptions;
this.lockinPeriodTypeOptions = account.lockinPeriodTypeOptions;
this.interestCalculationOptions = account.interestCalculationOptions;
this.savingScheduleDatas = account.savingScheduleDatas;
this.permissions = permissions;
this.outstandingAmount = account.outstandingAmount;
this.dueAmount = account.dueAmount;
this.savingScheduleData = account.savingScheduleData;
this.transactions = account.transactions;
this.interestPostEvery = account.interestPostEvery;
this.interestPostFrequency = account.interestPostFrequency;
}
public SavingAccountData(final SavingAccountData account, final SavingScheduleData savingScheduleData) {
this.id = account.id;
this.status = account.status;
this.externalId = account.externalId;
this.clientId = account.clientId;
this.clientName = account.clientName;
this.productId = account.productId;
this.productName = account.productName;
this.productType = account.productType;
this.currencyData = account.currencyData;
this.savingsDepositAmountPerPeriod = account.savingsDepositAmountPerPeriod;
this.savingsFrequencyType = account.savingsFrequencyType;
this.totalDepositAmount = account.totalDepositAmount;
this.recurringInterestRate = account.recurringInterestRate;
this.savingInterestRate = account.savingInterestRate;
this.interestType = account.interestType;
this.interestCalculationMethod = account.interestCalculationMethod;
this.tenure = account.tenure;
this.tenureType = account.tenureType;
this.projectedCommencementDate = account.projectedCommencementDate;
this.actualCommencementDate = account.actualCommencementDate;
this.maturesOnDate = account.maturesOnDate;
this.projectedInterestAccuredOnMaturity = account.projectedInterestAccuredOnMaturity;
this.actualInterestAccured = account.actualInterestAccured;
this.projectedMaturityAmount = account.projectedMaturityAmount;
this.actualMaturityAmount = account.actualMaturityAmount;
this.preClosureAllowed = account.preClosureAllowed;
this.preClosureInterestRate = account.preClosureInterestRate;
this.withdrawnonDate = account.withdrawnonDate;
this.rejectedonDate = account.rejectedonDate;
this.closedonDate = account.closedonDate;
this.isLockinPeriodAllowed = account.isLockinPeriodAllowed;
this.lockinPeriod = account.lockinPeriod;
this.lockinPeriodType = account.lockinPeriodType;
this.depositEvery = account.depositEvery;
this.productOptions = account.productOptions;
this.currencyOptions = account.currencyOptions;
this.savingsProductTypeOptions = account.savingsProductTypeOptions;
this.tenureTypeOptions = account.tenureTypeOptions;
this.savingFrequencyOptions = account.savingFrequencyOptions;
this.savingsInterestTypeOptions = account.savingsInterestTypeOptions;
this.lockinPeriodTypeOptions = account.lockinPeriodTypeOptions;
this.interestCalculationOptions = account.interestCalculationOptions;
this.savingScheduleDatas = account.savingScheduleDatas;
this.permissions = account.permissions;
this.outstandingAmount = account.outstandingAmount;
this.dueAmount = account.dueAmount;
this.savingScheduleData = savingScheduleData;
this.transactions = account.transactions;
this.interestPostEvery = account.interestPostEvery;
this.interestPostFrequency = account.interestPostFrequency;
}
public SavingAccountData(final SavingAccountData account, final Collection<SavingAccountTransactionsData> transactions) {
this.id = account.id;
this.status = account.status;
this.externalId = account.externalId;
this.clientId = account.clientId;
this.clientName = account.clientName;
this.productId = account.productId;
this.productName = account.productName;
this.productType = account.productType;
this.currencyData = account.currencyData;
this.savingsDepositAmountPerPeriod = account.savingsDepositAmountPerPeriod;
this.savingsFrequencyType = account.savingsFrequencyType;
this.totalDepositAmount = account.totalDepositAmount;
this.recurringInterestRate = account.recurringInterestRate;
this.savingInterestRate = account.savingInterestRate;
this.interestType = account.interestType;
this.interestCalculationMethod = account.interestCalculationMethod;
this.tenure = account.tenure;
this.tenureType = account.tenureType;
this.projectedCommencementDate = account.projectedCommencementDate;
this.actualCommencementDate = account.actualCommencementDate;
this.maturesOnDate = account.maturesOnDate;
this.projectedInterestAccuredOnMaturity = account.projectedInterestAccuredOnMaturity;
this.actualInterestAccured = account.actualInterestAccured;
this.projectedMaturityAmount = account.projectedMaturityAmount;
this.actualMaturityAmount = account.actualMaturityAmount;
this.preClosureAllowed = account.preClosureAllowed;
this.preClosureInterestRate = account.preClosureInterestRate;
this.withdrawnonDate = account.withdrawnonDate;
this.rejectedonDate = account.rejectedonDate;
this.closedonDate = account.closedonDate;
this.isLockinPeriodAllowed = account.isLockinPeriodAllowed;
this.lockinPeriod = account.lockinPeriod;
this.lockinPeriodType = account.lockinPeriodType;
this.depositEvery = account.depositEvery;
this.productOptions = account.productOptions;
this.currencyOptions = account.currencyOptions;
this.savingsProductTypeOptions = account.savingsProductTypeOptions;
this.tenureTypeOptions = account.tenureTypeOptions;
this.savingFrequencyOptions = account.savingFrequencyOptions;
this.savingsInterestTypeOptions = account.savingsInterestTypeOptions;
this.lockinPeriodTypeOptions = account.lockinPeriodTypeOptions;
this.interestCalculationOptions = account.interestCalculationOptions;
this.savingScheduleDatas = account.savingScheduleDatas;
this.permissions = account.permissions;
this.outstandingAmount = account.outstandingAmount;
this.dueAmount = account.dueAmount;
this.savingScheduleData = account.savingScheduleData;
this.transactions = transactions;
this.interestPostEvery = account.interestPostEvery;
this.interestPostFrequency = account.interestPostFrequency;
}
public EnumOptionData getStatus() {
return this.status;
}
public CurrencyData getCurrencyData() {
return this.currencyData;
}
public BigDecimal getSavingsDepostiAmountPerPeriod() {
return this.savingsDepositAmountPerPeriod;
}
public Integer getTenure() {
return this.tenure;
}
public EnumOptionData getTenureType() {
return this.tenureType;
}
public LocalDate getActualCommencementDate() {
return this.actualCommencementDate;
}
public LocalDate getMaturesOnDate() {
return this.maturesOnDate;
}
public Integer getDepositEvery() {
return this.depositEvery;
}
public BigDecimal getOutstandingAmount() {
return this.outstandingAmount;
}
}
@@ -1,20 +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.savingsaccount.data;
public class SavingAccountForLookup {
private final Long id;
public SavingAccountForLookup(final Long id) {
this.id = id;
}
public Long getId() {
return this.id;
}
}
@@ -1,38 +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.savingsaccount.data;
import java.math.BigDecimal;
import org.joda.time.LocalDate;
import org.mifosplatform.infrastructure.core.data.EnumOptionData;
public class SavingAccountTransactionsData {
@SuppressWarnings("unused")
private final Long id;
@SuppressWarnings("unused")
private final LocalDate transactionDate;
@SuppressWarnings("unused")
private final EnumOptionData transactionType;
@SuppressWarnings("unused")
private final BigDecimal amount;
public SavingAccountTransactionsData() {
this.id = null;
this.transactionDate = null;
this.transactionType = null;
this.amount = BigDecimal.ZERO;
}
public SavingAccountTransactionsData(final Long id, final LocalDate transactionDate, EnumOptionData transactionType, BigDecimal amount){
this.id = id;
this.transactionDate = transactionDate;
this.transactionType = transactionType;
this.amount = amount;
}
}
@@ -1,62 +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.savingsaccount.data;
public class SavingPermissionData {
private final boolean rejectAllowed;
private final boolean withdrawnByApplicantAllowed;
private final boolean undoApprovalAllowed;
private final boolean pendingApproval;
private final boolean renewelAllowed;
private final boolean isMaturedDepositAccount;
private final boolean anyActionOnAccountAllowed;
public SavingPermissionData(final boolean rejectAllowed, final boolean withdrawnByApplicantAllowed, final boolean undoApprovalAllowed,
final boolean pendingApproval, final boolean renewelAllowed, final boolean isMaturedDepositAccount) {
this.rejectAllowed = rejectAllowed;
this.withdrawnByApplicantAllowed = withdrawnByApplicantAllowed;
this.undoApprovalAllowed = undoApprovalAllowed;
this.pendingApproval = pendingApproval;
this.renewelAllowed = renewelAllowed;
this.isMaturedDepositAccount = isMaturedDepositAccount;
this.anyActionOnAccountAllowed = isRejectAllowed() || isPendingApproval() || isUndoApprovalAllowed()
|| isWithdrawnByApplicantAllowed() || isRenewelAllowed() || isMaturedDepositAccount();
}
public boolean isRejectAllowed() {
return rejectAllowed;
}
public boolean isWithdrawnByApplicantAllowed() {
return withdrawnByApplicantAllowed;
}
public boolean isUndoApprovalAllowed() {
return undoApprovalAllowed;
}
public boolean isPendingApproval() {
return pendingApproval;
}
public boolean isAnyActionOnAccountAllowed() {
return anyActionOnAccountAllowed;
}
public boolean isRenewelAllowed() {
return renewelAllowed;
}
public boolean isMaturedDepositAccount() {
return isMaturedDepositAccount;
}
}
@@ -1,51 +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.savingsaccount.data;
import java.math.BigDecimal;
import java.util.Collection;
import org.mifosplatform.organisation.monetary.data.CurrencyData;
public class SavingScheduleData {
private final CurrencyData currency;
private final BigDecimal cumulativeDepositDue;
private final BigDecimal cumulativeDepositPaid;
private final BigDecimal cummulativeInterestAccured;
private final Collection<SavingSchedulePeriodData> periods;
public SavingScheduleData(final CurrencyData currency, final BigDecimal cumulativeDepositDue, final BigDecimal cumulativeDepositPaid,
final BigDecimal cummulativeInterestAccured, final Collection<SavingSchedulePeriodData> periods) {
this.currency = currency;
this.cumulativeDepositDue = cumulativeDepositDue;
this.cumulativeDepositPaid = cumulativeDepositPaid;
this.cummulativeInterestAccured = cummulativeInterestAccured;
this.periods = periods;
}
public CurrencyData getCurrency() {
return this.currency;
}
public BigDecimal getCumulativeDepositDue() {
return this.cumulativeDepositDue;
}
public BigDecimal getCumulativeDepositPaid() {
return this.cumulativeDepositPaid;
}
public BigDecimal getCummulativeInterestAccured() {
return this.cummulativeInterestAccured;
}
public Collection<SavingSchedulePeriodData> getPeriods() {
return this.periods;
}
}
@@ -1,53 +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.savingsaccount.data;
import java.math.BigDecimal;
import org.joda.time.LocalDate;
public class SavingSchedulePeriodData {
private final Integer period;
private final LocalDate dueDate;
private final BigDecimal depositDue;
private final BigDecimal depositPaid;
private final BigDecimal interestAccured;
public SavingSchedulePeriodData(final Integer period, final LocalDate dueDate, final BigDecimal depositDue, final BigDecimal depositPaid, final BigDecimal interestAccured) {
this.period = period;
this.dueDate = dueDate;
this.depositDue = depositDue;
this.depositPaid = depositPaid;
this.interestAccured = interestAccured;
}
public static SavingSchedulePeriodData addScheduleInformation(int periodNumber, LocalDate scheduleDate,
BigDecimal depositAmountPerPeriod, BigDecimal interestAccured) {
return new SavingSchedulePeriodData(periodNumber, scheduleDate, depositAmountPerPeriod, BigDecimal.ZERO, interestAccured);
}
public Integer getPeriod() {
return this.period;
}
public LocalDate getDueDate() {
return this.dueDate;
}
public BigDecimal getDepositDue() {
return this.depositDue;
}
public BigDecimal getDepositPaid() {
return this.depositPaid;
}
public BigDecimal getInterestAccured() {
return this.interestAccured;
}
}
@@ -1,16 +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.savingsaccount.domain;
import java.util.List;
import org.joda.time.LocalDate;
import org.mifosplatform.portfolio.savingsaccountproduct.domain.SavingFrequencyType;
public interface DepositScheduleDateGenerator {
List<LocalDate> generate(LocalDate startDate, Integer paymentPeriods, Integer depositFrequency, SavingFrequencyType savingFrequencyType);
}
@@ -1,118 +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.savingsaccount.domain;
import java.math.BigDecimal;
import java.math.MathContext;
import java.math.RoundingMode;
import org.mifosplatform.organisation.monetary.domain.Money;
import org.mifosplatform.portfolio.savingsaccountproduct.domain.SavingFrequencyType;
import org.mifosplatform.portfolio.savingsaccountproduct.domain.SavingInterestCalculationMethod;
import org.springframework.stereotype.Service;
@Service
public class ReccuringDepositInterestCalculator {
private final Integer monthsInYear = 12;
public Money calculateInterestOnMaturityFor(final Money savingsDepositPerPeriod, final Integer tenure,
final BigDecimal reccuringInterestRate, final SavingFrequencyType savingFrequencyType,
final SavingInterestCalculationMethod savingInterestCalculationMethod, Integer depositEvery) {
BigDecimal finalAmount = BigDecimal.ZERO;
MathContext mc = new MathContext(8, RoundingMode.HALF_EVEN);
BigDecimal interestRateAsFraction = reccuringInterestRate.divide(BigDecimal.valueOf(100), mc);
Integer noofTimesInterestCompoundPerYear = determineIntValue(savingFrequencyType);
BigDecimal interestRatePerPeriod = BigDecimal.valueOf(interestRateAsFraction.doubleValue()
/ noofTimesInterestCompoundPerYear.doubleValue());
Integer noOfTimestobeCalculated = tenure / depositEvery;
if (savingInterestCalculationMethod.isAverageBalance()) {
BigDecimal termAmount = BigDecimal.ZERO;
BigDecimal totalInterest = BigDecimal.ZERO;
BigDecimal closingBalance = BigDecimal.ZERO;
BigDecimal amountPerPeriod = savingsDepositPerPeriod.getAmount();
Integer depositEveryOriginalValue = depositEvery;
BigDecimal amountPermonth = BigDecimal.valueOf(amountPerPeriod.doubleValue() / depositEvery.doubleValue());
while (noOfTimestobeCalculated > 0) {
while (depositEvery > 0) {
closingBalance = closingBalance.add(amountPermonth);
termAmount = termAmount.add(closingBalance);
depositEvery--;
}
BigDecimal averageAmount = BigDecimal.valueOf(termAmount.doubleValue() / depositEveryOriginalValue.doubleValue());
BigDecimal interestRatePerTerm = BigDecimal.valueOf(interestRateAsFraction.doubleValue() / monthsInYear.doubleValue()
* depositEveryOriginalValue.doubleValue());
BigDecimal interestperTerm = averageAmount.multiply(interestRatePerTerm);
totalInterest = totalInterest.add(interestperTerm);
depositEvery = depositEveryOriginalValue;
termAmount = BigDecimal.ZERO;
noOfTimestobeCalculated--;
}
finalAmount = closingBalance.add(totalInterest);
} else if (savingInterestCalculationMethod.isMonthlyCollection()) {
/*
* // Assuming tenure in months // see
* http://www.onemint.com/2012/04/03/
* how-to-calculate-interest-on-recurring-deposits/
*
* A=P(1+r/n)^nt
*
* A = final amount P = principal amount (initial investment) r =
* annual nominal interest rate (as a decimal, not in percentage) n
* = number of times the interest is compounded per year t = number
* of years
*/
BigDecimal onePlusInterestRatePerPeriod = BigDecimal.ONE.add(interestRatePerPeriod);
BigDecimal monthsExpressedInYears;
BigDecimal timeforOneCalculationPeriod;
BigDecimal amountPerPeriod;
Integer tempTenure = tenure;
while (noOfTimestobeCalculated > 0) {
monthsExpressedInYears = BigDecimal.valueOf(tempTenure.doubleValue() / monthsInYear.doubleValue());
timeforOneCalculationPeriod = BigDecimal.valueOf(noofTimesInterestCompoundPerYear * monthsExpressedInYears.doubleValue());
amountPerPeriod = savingsDepositPerPeriod.getAmount()
.multiply(
BigDecimal.valueOf(Math.pow(onePlusInterestRatePerPeriod.doubleValue(),
timeforOneCalculationPeriod.doubleValue())));
finalAmount = finalAmount.add(amountPerPeriod);
noOfTimestobeCalculated--;
tempTenure = tempTenure - depositEvery;
}
}
return Money.of(savingsDepositPerPeriod.getCurrency(), finalAmount);
}
private Integer determineIntValue(final SavingFrequencyType frequencyType) {
Integer noofTimesInterestCompoundPerYear = Integer.valueOf(0);
switch (frequencyType) {
case MONTHLY:
noofTimesInterestCompoundPerYear = monthsInYear;
break;
case QUATERLY:
noofTimesInterestCompoundPerYear = monthsInYear / 3;
break;
case HALFYEARLY:
noofTimesInterestCompoundPerYear = monthsInYear / 6;
break;
case YEARLY:
noofTimesInterestCompoundPerYear = monthsInYear / 12;
break;
default:
throw new RuntimeException("The specified frequency not supported");
}
return noofTimesInterestCompoundPerYear;
}
}
@@ -1,730 +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.savingsaccount.domain;
import java.math.BigDecimal;
import java.math.MathContext;
import java.math.RoundingMode;
import java.util.ArrayList;
import java.util.Date;
import java.util.List;
import javax.persistence.CascadeType;
import javax.persistence.Column;
import javax.persistence.Embedded;
import javax.persistence.Entity;
import javax.persistence.JoinColumn;
import javax.persistence.ManyToOne;
import javax.persistence.OneToMany;
import javax.persistence.OrderBy;
import javax.persistence.Table;
import javax.persistence.Temporal;
import javax.persistence.TemporalType;
import javax.persistence.UniqueConstraint;
import org.hibernate.annotations.LazyCollection;
import org.hibernate.annotations.LazyCollectionOption;
import org.joda.time.LocalDate;
import org.joda.time.Months;
import org.mifosplatform.infrastructure.core.api.JsonCommand;
import org.mifosplatform.infrastructure.core.domain.AbstractAuditableCustom;
import org.mifosplatform.organisation.monetary.domain.MonetaryCurrency;
import org.mifosplatform.organisation.monetary.domain.Money;
import org.mifosplatform.portfolio.client.domain.Client;
import org.mifosplatform.portfolio.loanproduct.domain.PeriodFrequencyType;
import org.mifosplatform.portfolio.savingsaccountproduct.domain.SavingFrequencyType;
import org.mifosplatform.portfolio.savingsaccountproduct.domain.SavingInterestCalculationMethod;
import org.mifosplatform.portfolio.savingsaccountproduct.domain.SavingProduct;
import org.mifosplatform.portfolio.savingsaccountproduct.domain.SavingProductType;
import org.mifosplatform.portfolio.savingsaccountproduct.domain.SavingsInterestType;
import org.mifosplatform.portfolio.savingsdepositaccount.domain.DepositAccountEvent;
import org.mifosplatform.portfolio.savingsdepositaccount.domain.DepositAccountStatus;
import org.mifosplatform.portfolio.savingsdepositaccount.domain.DepositLifecycleStateMachine;
import org.mifosplatform.portfolio.savingsdepositaccount.exception.InvalidDepositStateTransitionException;
import org.mifosplatform.portfolio.savingsdepositproduct.domain.TenureTypeEnum;
import org.mifosplatform.useradministration.domain.AppUser;
@Entity
@Table(name = "m_saving_account", uniqueConstraints = @UniqueConstraint(name = "saving_acc_external_id", columnNames = { "external_id" }))
public class SavingAccount extends AbstractAuditableCustom<AppUser, Long> {
@ManyToOne
@JoinColumn(name = "client_id", nullable = false)
private Client client;
@ManyToOne
@JoinColumn(name = "product_id")
private SavingProduct product;
@Column(name = "savings_product_type", nullable = false)
private Integer savingProductType;
@Column(name = "external_id")
private String externalId;
@Embedded
private MonetaryCurrency currency;
@Column(name = "deposit_amount_per_period", scale = 6, precision = 19, nullable = false)
private BigDecimal savingsDepositAmountPerPeriod;
@Column(name = "total_deposit_amount", scale = 6, precision = 19, nullable = false)
private BigDecimal totalSavingsAmount;
@Column(name = "reccuring_nominal_interest_rate", scale = 6, precision = 19, nullable = false)
private BigDecimal reccuringInterestRate;
@Column(name = "regular_saving_nominal_interest_rate", scale = 6, precision = 19, nullable = false)
private BigDecimal savingInterestRate;
@Column(name = "tenure", nullable = false)
private Integer tenure;
@Column(name = "tenure_type", nullable = false)
private Integer tenureType;
@Column(name = "frequency", nullable = false)
private Integer frequency;
@Column(name = "interest_type", nullable = false)
private Integer interestType;
@Column(name = "interest_calculation_method")
private Integer interestCalculationMethod;
@Temporal(TemporalType.DATE)
@Column(name = "projected_commencement_date")
private Date projectedCommencementDate;
@Temporal(TemporalType.DATE)
@Column(name = "actual_commencement_date")
private Date actualCommencementDate;
@SuppressWarnings("unused")
@Temporal(TemporalType.DATE)
@Column(name = "matures_on_date")
private Date maturesOnDate;
@SuppressWarnings("unused")
@Column(name = "projected_interest_accrued_on_maturity", scale = 6, precision = 19, nullable = false)
private BigDecimal projectedInterestAccruedOnMaturity;
@SuppressWarnings("unused")
@Column(name = "actual_interest_accrued", scale = 6, precision = 19, nullable = false)
private BigDecimal interestAccrued;
@SuppressWarnings("unused")
@Column(name = "projected_total_maturity_amount", scale = 6, precision = 19, nullable = false)
private BigDecimal projectedTotalOnMaturity;
@SuppressWarnings("unused")
@Column(name = "actual_total_amount", scale = 6, precision = 19, nullable = false)
private BigDecimal total;
@Column(name = "pre_closure_interest_rate", scale = 6, precision = 19, nullable = false)
private BigDecimal preClosureInterestRate;
@Column(name = "outstanding_amount", scale = 6, precision = 19, nullable = false)
private BigDecimal outstandingAmount;
@Column(name = "is_preclosure_allowed", nullable = false)
private final boolean preClosureAllowed = false;
@Column(name = "is_deleted", nullable = false)
private boolean deleted = false;
@Column(name = "status_enum", nullable = false)
private Integer accountStatus;
@SuppressWarnings("unused")
@Temporal(TemporalType.DATE)
@Column(name = "closedon_date")
private Date closedOnDate;
@SuppressWarnings("unused")
@Temporal(TemporalType.DATE)
@Column(name = "rejectedon_date")
private Date rejectedOnDate;
@Temporal(TemporalType.DATE)
@Column(name = "withdrawnon_date")
private Date withdrawnOnDate;
@Column(name = "is_lock_in_period_allowed", nullable = false)
private boolean isLockinPeriodAllowed = false;
@Column(name = "lock_in_period", nullable = false)
private Integer lockinPeriod;
@Column(name = "lock_in_period_type", nullable = false)
private Integer lockinPeriodType;
@Column(name = "deposit_every", nullable = false)
private Integer payEvery;
@Column(name = "interest_posting_every", nullable = false)
private Integer interestPostEvery;
@Column(name = "interest_posting_frequency", nullable = false)
private Integer interestPostFrequency;
@Column(name = "interest_posted_amount", scale = 6, precision = 19)
private BigDecimal interestPostedAmount;
@Temporal(TemporalType.DATE)
@Column(name = "last_interest_posted_date")
private Date lastInterestPostedDate;
@Temporal(TemporalType.DATE)
@Column(name = "next_interest_posting_date")
private Date nextInterestPostingDate;
// see
// http://stackoverflow.com/questions/4334970/hibernate-cannot-simultaneously-fetch-multiple-bags
@LazyCollection(LazyCollectionOption.FALSE)
@OneToMany(cascade = CascadeType.ALL, mappedBy = "savingAccount", orphanRemoval = true)
private final List<SavingScheduleInstallments> savingScheduleInstallments = new ArrayList<SavingScheduleInstallments>();
@OrderBy(value = "id")
@LazyCollection(LazyCollectionOption.FALSE)
@OneToMany(cascade = CascadeType.ALL, mappedBy = "savingAccount", orphanRemoval = true)
private final List<SavingAccountTransaction> savingAccountTransactions = new ArrayList<SavingAccountTransaction>();
protected SavingAccount() {
//
}
public static SavingAccount openNew(final Client client, final SavingProduct product, final String externalId,
final Money savingsDeposit, final BigDecimal reccuringInterestRate, final BigDecimal savingInterestRate, final Integer tenure,
final LocalDate commencementDate, final TenureTypeEnum tenureTypeEnum, final SavingProductType savingProductType,
final SavingFrequencyType savingFrequencyType, final SavingsInterestType interestType,
final SavingInterestCalculationMethod savingInterestCalculationMethod, final boolean isLockinPeriodAllowed,
final Integer lockinPeriod, final PeriodFrequencyType lockinPeriodType,
final ReccuringDepositInterestCalculator reccuringDepositInterestCalculator,
final DepositLifecycleStateMachine lifecycleStateMachine, final Integer depositEvery, final Integer interestPostEvery,
final Integer interestPostFrequency) {
Money futureValueOnMaturity = null;
if (savingProductType.isReccuring() && tenureTypeEnum.isFixedPeriod()) {
futureValueOnMaturity = reccuringDepositInterestCalculator.calculateInterestOnMaturityFor(savingsDeposit, tenure,
reccuringInterestRate, savingFrequencyType, savingInterestCalculationMethod, depositEvery);
} else if (savingProductType.isReccuring() && tenureTypeEnum.isPerpetual()) {
futureValueOnMaturity = savingsDeposit;
} else {
futureValueOnMaturity = savingsDeposit;
}
return new SavingAccount(client, externalId, product, savingsDeposit, reccuringInterestRate, savingInterestRate, tenure,
commencementDate, tenureTypeEnum, savingProductType, savingFrequencyType, interestType, savingInterestCalculationMethod,
isLockinPeriodAllowed, lockinPeriod, lockinPeriodType, futureValueOnMaturity, lifecycleStateMachine, depositEvery,
interestPostEvery, interestPostFrequency);
}
public SavingAccount(final Client client, final String externalId, final SavingProduct product, final Money savingsDeposit,
final BigDecimal reccuringInterestRate, final BigDecimal savingInterestRate, final Integer tenure,
final LocalDate commencementDate, final TenureTypeEnum tenureTypeEnum, final SavingProductType savingProductType,
final SavingFrequencyType savingFrequencyType, final SavingsInterestType interestType,
final SavingInterestCalculationMethod savingInterestCalculationMethod, final boolean isLockinPeriodAllowed,
final Integer lockinPeriod, final PeriodFrequencyType lockinPeriodType, final Money futureValueOnMaturity,
final DepositLifecycleStateMachine lifecycleStateMachine, final Integer payEvery, final Integer interestPostEvery,
final Integer interestPostFrequency) {
DepositAccountStatus from = null;
if (accountStatus != null) {
from = DepositAccountStatus.fromInt(accountStatus);
}
DepositAccountStatus statusEnum = lifecycleStateMachine.transition(DepositAccountEvent.DEPOSIT_CREATED, from);
accountStatus = statusEnum.getValue();
this.total = BigDecimal.ZERO;
this.preClosureInterestRate = BigDecimal.ZERO;
this.totalSavingsAmount = BigDecimal.ZERO;
this.interestAccrued = BigDecimal.ZERO;
this.client = client;
this.externalId = externalId;
this.product = product;
this.savingsDepositAmountPerPeriod = savingsDeposit.getAmount();
this.currency = savingsDeposit.getCurrency();
this.reccuringInterestRate = reccuringInterestRate;
this.savingInterestRate = savingInterestRate;
this.tenure = tenure;
this.projectedCommencementDate = commencementDate.toDate();
this.tenureType = tenureTypeEnum.getValue();
this.savingProductType = savingProductType.getValue();
this.frequency = savingFrequencyType.getValue();
this.interestType = interestType.getValue();
this.interestCalculationMethod = savingInterestCalculationMethod.getValue();
this.isLockinPeriodAllowed = isLockinPeriodAllowed;
this.lockinPeriod = lockinPeriod;
this.lockinPeriodType = lockinPeriodType.getValue();
this.projectedTotalOnMaturity = futureValueOnMaturity.getAmount();
BigDecimal projectedInterestForReccuring = futureValueOnMaturity.getAmount().subtract(
BigDecimal.valueOf(savingsDeposit.getAmount().doubleValue() * tenure.doubleValue() / payEvery)); // presently
// only
// for
// months
this.projectedInterestAccruedOnMaturity = savingProductType.isReccuring() && tenureTypeEnum.isFixedPeriod() ? projectedInterestForReccuring
: BigDecimal.ZERO;
this.payEvery = payEvery;
this.outstandingAmount = BigDecimal.ZERO;
this.interestPostEvery = interestPostEvery;
this.interestPostFrequency = interestPostFrequency;
}
public void modifyAccount(final SavingProduct product, final String externalId, final Money savingsDeposit,
final BigDecimal reccuringInterestRate, final BigDecimal savingInterestRate, final Integer tenure,
final LocalDate commencementDate, final TenureTypeEnum tenureTypeEnum, final SavingProductType savingProductType,
final SavingFrequencyType savingFrequencyType, final SavingInterestCalculationMethod savingInterestCalculationMethod,
final boolean isLockinPeriodAllowed, final Integer lockinPeriod, final PeriodFrequencyType lockinPeriodType,
final ReccuringDepositInterestCalculator reccuringDepositInterestCalculator, final Integer payEvery,
final SavingsInterestType interestType, final Integer interestPostEvery, final Integer interestPostFrequency) {
Money futureValueOnMaturity = null;
if (savingProductType.isReccuring() && tenureTypeEnum.isFixedPeriod()) {
futureValueOnMaturity = reccuringDepositInterestCalculator.calculateInterestOnMaturityFor(savingsDeposit, tenure,
reccuringInterestRate, savingFrequencyType, savingInterestCalculationMethod, payEvery);
} else if (savingProductType.isReccuring() && tenureTypeEnum.isPerpetual()) {
futureValueOnMaturity = savingsDeposit;
} else {
futureValueOnMaturity = savingsDeposit;
}
this.product = product;
this.externalId = externalId;
this.savingsDepositAmountPerPeriod = savingsDeposit.getAmount();
this.reccuringInterestRate = reccuringInterestRate;
this.savingInterestRate = savingInterestRate;
this.tenure = tenure;
this.projectedCommencementDate = commencementDate.toDate();
this.tenureType = tenureTypeEnum.getValue();
this.savingProductType = savingProductType.getValue();
this.frequency = savingFrequencyType.getValue();
this.interestType = interestType.getValue();
this.interestCalculationMethod = savingInterestCalculationMethod.getValue();
this.isLockinPeriodAllowed = isLockinPeriodAllowed;
this.lockinPeriod = lockinPeriod;
this.lockinPeriodType = lockinPeriodType.getValue();
this.payEvery = payEvery;
this.outstandingAmount = BigDecimal.ZERO;
this.interestPostEvery = interestPostEvery;
this.interestPostFrequency = interestPostFrequency;
this.savingScheduleInstallments.clear();
this.projectedTotalOnMaturity = futureValueOnMaturity.getAmount();
BigDecimal projectedInterestForReccuring = futureValueOnMaturity.getAmount().subtract(
BigDecimal.valueOf(savingsDeposit.getAmount().doubleValue() * tenure.doubleValue() / payEvery)); // presently
// only
// for
// months
this.projectedInterestAccruedOnMaturity = savingProductType.isReccuring() && tenureTypeEnum.isFixedPeriod() ? projectedInterestForReccuring
: BigDecimal.ZERO;
}
public boolean isDeleted() {
return this.deleted;
}
public boolean isPendingApproval() {
return this.accountStatus.equals(100);
}
public Client getClient() {
return client;
}
public SavingProduct getProduct() {
return product;
}
public Integer getSavingProductType() {
return savingProductType;
}
public String getExternalId() {
return externalId;
}
public BigDecimal getSavingsDepositAmountPerPeriod() {
return savingsDepositAmountPerPeriod;
}
public BigDecimal getReccuringInterestRate() {
return reccuringInterestRate;
}
public BigDecimal getSavingInterestRate() {
return savingInterestRate;
}
public Integer getTenure() {
return tenure;
}
public Integer getTenureType() {
return tenureType;
}
public Integer getFrequency() {
return frequency;
}
public Integer getInterestType() {
return interestType;
}
public Integer getInterestCalculationMethod() {
return interestCalculationMethod;
}
public Date getProjectedCommencementDate() {
return projectedCommencementDate;
}
public BigDecimal getPreClosureInterestRate() {
return preClosureInterestRate;
}
public boolean isPreClosureAllowed() {
return preClosureAllowed;
}
public Date getWithdrawnOnDate() {
return withdrawnOnDate;
}
public boolean isLockinPeriodAllowed() {
return isLockinPeriodAllowed;
}
public Integer getLockinPeriod() {
return lockinPeriod;
}
public Integer getLockinPeriodType() {
return lockinPeriodType;
}
public Integer getPayEvery() {
return this.payEvery;
}
public BigDecimal getOutstandingAmount() {
return this.outstandingAmount;
}
public Integer getInterestPostEvery() {
return this.interestPostEvery;
}
public Integer getInterestPostFrequency() {
return this.interestPostFrequency;
}
public List<SavingAccountTransaction> getSavingAccountTransactions() {
return this.savingAccountTransactions;
}
public void addSavingScheduleInstallment(final SavingScheduleInstallments installment) {
installment.updateAccount(this);
this.savingScheduleInstallments.add(installment);
}
public void reject(final LocalDate rejectedOn, final DepositLifecycleStateMachine depositLifecycleStateMachine) {
DepositAccountStatus statusEnum = depositLifecycleStateMachine.transition(DepositAccountEvent.DEPOSIT_REJECTED,
DepositAccountStatus.fromInt(this.accountStatus));
this.accountStatus = statusEnum.getValue();
this.maturesOnDate = null;
this.rejectedOnDate = rejectedOn.toDateTimeAtCurrentTime().toDate();
this.closedOnDate = rejectedOn.toDateTimeAtCurrentTime().toDate();
if (rejectedOn.isBefore(projectedCommencementDate())) {
final String errorMessage = "The date on which a saving account is rejected cannot be before its submittal date: "
+ projectedCommencementDate().toString();
throw new InvalidDepositStateTransitionException("reject", "cannot.be.before.submittal.date", errorMessage, rejectedOn,
projectedCommencementDate());
}
if (rejectedOn.isAfter(new LocalDate())) {
final String errorMessage = "The date on which a saving account is rejected cannot be in the future.";
throw new InvalidDepositStateTransitionException("reject", "cannot.be.a.future.date", errorMessage, rejectedOn);
}
}
public LocalDate projectedCommencementDate() {
LocalDate date = null;
if (this.projectedCommencementDate != null) {
date = new LocalDate(this.projectedCommencementDate);
}
return date;
}
public void withdrawnByApplicant(final LocalDate withdrawnOn, final DepositLifecycleStateMachine depositLifecycleStateMachine) {
DepositAccountStatus statusEnum = depositLifecycleStateMachine.transition(DepositAccountEvent.DEPOSIT_WITHDRAWN,
DepositAccountStatus.fromInt(this.accountStatus));
this.accountStatus = statusEnum.getValue();
this.maturesOnDate = null;
this.withdrawnOnDate = withdrawnOn.toDateTimeAtCurrentTime().toDate();
this.closedOnDate = withdrawnOn.toDateTimeAtCurrentTime().toDate();
this.savingScheduleInstallments.clear();
if (withdrawnOn.isBefore(projectedCommencementDate())) {
final String errorMessage = "The date on which a deposit is rejected cannot be before its submittal date: "
+ projectedCommencementDate().toString();
throw new InvalidDepositStateTransitionException("withdrawnbyclient", "cannot.be.before.submittal.date", errorMessage,
withdrawnOn, projectedCommencementDate());
}
if (withdrawnOn.isAfter(new LocalDate())) {
final String errorMessage = "The date on which a deposit is rejected cannot be in the future.";
throw new InvalidDepositStateTransitionException("withdrawnbyclient", "cannot.be.a.future.date", errorMessage, withdrawnOn);
}
}
public void undoSavingAccountApproval(final DepositLifecycleStateMachine depositLifecycleStateMachine) {
DepositAccountStatus statusEnum = depositLifecycleStateMachine.transition(DepositAccountEvent.DEPOSIT_APPROVAL_UNDO,
DepositAccountStatus.fromInt(this.accountStatus));
this.accountStatus = statusEnum.getValue();
this.savingScheduleInstallments.clear();
this.closedOnDate = new Date();
}
public void approveSavingAccount(final LocalDate approvalDate, final BigDecimal savingsDepositAmountPerPeriod,
final BigDecimal recurringInterestRate, final BigDecimal savingInterestRate, final Integer interestType, final Integer tenure,
final Integer tenureType, final Integer frequency, final Integer payEvery,
final DepositLifecycleStateMachine depositLifecycleStateMachine,
final ReccuringDepositInterestCalculator reccuringDepositInterestCalculator, final Integer interestPostEvery,
final Integer interestPostFrequency) {
DepositAccountStatus statusEnum = depositLifecycleStateMachine.transition(DepositAccountEvent.DEPOSIT_APPROVED,
DepositAccountStatus.fromInt(this.accountStatus));
this.accountStatus = statusEnum.getValue();
Money savingsAmountPerPeriod = Money.of(currency, savingsDepositAmountPerPeriod);
TenureTypeEnum tenureTypeEnum = TenureTypeEnum.fromInt(tenureType);
SavingFrequencyType savingFrequencyType = SavingFrequencyType.fromInt(frequency);
SavingInterestCalculationMethod interestCalculationMethod = SavingInterestCalculationMethod.fromInt(this.interestCalculationMethod);
Money futureValueOnMaturity = null;
if (SavingProductType.fromInt(this.savingProductType).isReccuring() && tenureTypeEnum.isFixedPeriod()) {
futureValueOnMaturity = reccuringDepositInterestCalculator.calculateInterestOnMaturityFor(savingsAmountPerPeriod, tenure,
recurringInterestRate, savingFrequencyType, interestCalculationMethod, payEvery);
} else if (SavingProductType.fromInt(this.savingProductType).isReccuring() && tenureTypeEnum.isPerpetual()) {
futureValueOnMaturity = savingsAmountPerPeriod;
} else {
futureValueOnMaturity = savingsAmountPerPeriod;
}
this.actualCommencementDate = approvalDate.toDate();
this.savingsDepositAmountPerPeriod = savingsDepositAmountPerPeriod;
this.reccuringInterestRate = recurringInterestRate;
this.savingInterestRate = savingInterestRate;
this.interestType = interestType;
this.tenure = tenure;
this.tenureType = tenureType;
this.frequency = frequency;
this.payEvery = payEvery;
this.savingScheduleInstallments.clear();
this.total = futureValueOnMaturity.getAmount();
BigDecimal interestForReccuring = futureValueOnMaturity.getAmount().subtract(
BigDecimal.valueOf(savingsDepositAmountPerPeriod.doubleValue() * tenure.doubleValue() / payEvery.doubleValue())); // presently
// only
// for
// months
this.interestAccrued = SavingProductType.fromInt(this.savingProductType).isReccuring() && tenureTypeEnum.isFixedPeriod() ? interestForReccuring
: BigDecimal.ZERO;
this.interestPostEvery = interestPostEvery;
this.interestPostFrequency = interestPostFrequency;
// for interest posting initializing
this.lastInterestPostedDate = this.actualCommencementDate;
this.nextInterestPostingDate = new LocalDate(this.lastInterestPostedDate).plusMonths(this.interestPostEvery).toDate();
this.interestPostedAmount = BigDecimal.ZERO;
}
public void depositMoney(final JsonCommand command) {
final BigDecimal depositAmountCommandValue = command.bigDecimalValueOfParameterNamed("savingsDepositAmountPerPeriod");
final LocalDate depositDateCommandValue = command.localDateValueOfParameterNamed("depositDate");
BigDecimal depositAmount = BigDecimal.ZERO;
BigDecimal remainAmountToBePaid = BigDecimal.ZERO;
BigDecimal commandRemainDepositAmount = depositAmountCommandValue;
SavingAccountTransaction savingAccountTransaction = SavingAccountTransaction.deposit(depositAmountCommandValue,
depositDateCommandValue);
savingAccountTransaction.updateAccount(this);
this.savingAccountTransactions.add(savingAccountTransaction);
this.outstandingAmount = this.outstandingAmount.add(depositAmountCommandValue);
this.totalSavingsAmount = this.totalSavingsAmount.add(depositAmountCommandValue);
if (SavingProductType.fromInt(this.savingProductType).isReccuring() && TenureTypeEnum.fromInt(tenureType).isFixedPeriod()) {
for (SavingScheduleInstallments savingScheduleInstallment : this.savingScheduleInstallments) {
if (!savingScheduleInstallment.isCompleted()) {
depositAmount = savingScheduleInstallment.getDeposit();
remainAmountToBePaid = depositAmount.subtract(savingScheduleInstallment.getDepositPaid());
if (remainAmountToBePaid.doubleValue() > 0) {
if (commandRemainDepositAmount.doubleValue() > 0) {
if (commandRemainDepositAmount.doubleValue() >= remainAmountToBePaid.doubleValue()) {
savingScheduleInstallment.setDepositPaid(remainAmountToBePaid.add(savingScheduleInstallment
.getDepositPaid()));
savingScheduleInstallment.setPaymentDate(depositDateCommandValue.toDate());
savingScheduleInstallment.setCompleted(true);
commandRemainDepositAmount = commandRemainDepositAmount.subtract(remainAmountToBePaid);
} else if (commandRemainDepositAmount.doubleValue() < remainAmountToBePaid.doubleValue()) {
savingScheduleInstallment.setDepositPaid(commandRemainDepositAmount.add(savingScheduleInstallment
.getDepositPaid()));
savingScheduleInstallment.setPaymentDate(depositDateCommandValue.toDate());
commandRemainDepositAmount = BigDecimal.ZERO;
}
}
}
}
}
} else {
for (SavingScheduleInstallments savingScheduleInstallment : this.savingScheduleInstallments) {
savingScheduleInstallment.setDepositPaid(remainAmountToBePaid.add(savingScheduleInstallment.getDepositPaid()));
savingScheduleInstallment.setPaymentDate(depositDateCommandValue.toDate());
}
}
}
public boolean isActive() {
return DepositAccountStatus.fromInt(this.accountStatus).isActive();
}
public void withdrawAmount(final BigDecimal amount, final LocalDate transactionDate) {
this.outstandingAmount = this.outstandingAmount.subtract(amount);
SavingAccountTransaction savingAccountTransaction = SavingAccountTransaction.withdraw(amount, transactionDate);
savingAccountTransaction.updateAccount(this);
this.savingAccountTransactions.add(savingAccountTransaction);
}
/**
* Delete is a <i>soft delete</i>. Updates flag on account so it wont appear
* in query/report results.
*
* Any fields with unique constraints and prepended with id of record.
*/
public void delete() {
this.deleted = true;
this.externalId = this.getId() + "_" + this.externalId;
}
public void postInterest() {
LocalDate lastInterestPostedDate = getLastInterestPostedDate();
// LocalDate nextInterestPostingDate = getNextInterestPostedDate();
// SavingInterestCalculationMethod savingInterestCalculationMethod =
// SavingInterestCalculationMethod
// .fromInt(this.interestCalculationMethod);
Integer monthsForInterestCalculation = Months.monthsBetween(lastInterestPostedDate, new LocalDate()).getMonths();
Integer postInterestItereations = monthsForInterestCalculation / this.interestPostEvery;
MathContext mc = new MathContext(8, RoundingMode.HALF_EVEN);
BigDecimal interestRateAsFraction = reccuringInterestRate.divide(BigDecimal.valueOf(100), mc);
final Integer monthsInYear = 12;
BigDecimal totalDepositedAmount = BigDecimal.ZERO;
BigDecimal totalWithdrawableAmount = BigDecimal.ZERO;
BigDecimal totalOutstandingAmount = BigDecimal.ZERO;
boolean isOutstandingAmountCalculated = false;
while (postInterestItereations > 0) {
lastInterestPostedDate = getLastInterestPostedDate();
// nextInterestPostingDate = getNextInterestPostedDate();
LocalDate transactionStartDate = lastInterestPostedDate;
BigDecimal termTotalAmount = BigDecimal.ZERO;
BigDecimal averageBalanceForTerm = BigDecimal.ZERO;
for (int i = 0; i < interestPostEvery; i++) {
// default for months here
LocalDate transactionEndDate = transactionStartDate.plusMonths(1);
BigDecimal depositedAmount = BigDecimal.ZERO;
BigDecimal withdrawableAmount = BigDecimal.ZERO;
BigDecimal outstandingAmount = BigDecimal.ZERO;
for (SavingAccountTransaction savingAccountTransaction : this.savingAccountTransactions) {
LocalDate actualTransactionDate = savingAccountTransaction.getTransactionDate();
if (actualTransactionDate != null
&& (actualTransactionDate.isAfter(transactionStartDate) || actualTransactionDate.isEqual(transactionStartDate))) {
if (actualTransactionDate.isBefore(transactionEndDate)) {
if (savingAccountTransaction.getTypeOf().isDeposit()) {
depositedAmount = depositedAmount.add(savingAccountTransaction.getAmount());
} else if (savingAccountTransaction.getTypeOf().isWithdraw()) {
withdrawableAmount = withdrawableAmount.add(savingAccountTransaction.getAmount());
}
}
} else if (actualTransactionDate != null && (actualTransactionDate.isBefore(transactionStartDate))) {
if (!isOutstandingAmountCalculated) {
if (savingAccountTransaction.getTypeOf().isDeposit()) {
depositedAmount = depositedAmount.add(savingAccountTransaction.getAmount());
} else if (savingAccountTransaction.getTypeOf().isWithdraw()) {
withdrawableAmount = withdrawableAmount.add(savingAccountTransaction.getAmount());
}
}
}
}
outstandingAmount = depositedAmount.subtract(withdrawableAmount);
totalDepositedAmount = totalDepositedAmount.add(depositedAmount);
totalWithdrawableAmount = totalWithdrawableAmount.add(withdrawableAmount);
totalOutstandingAmount = totalOutstandingAmount.add(outstandingAmount);
termTotalAmount = termTotalAmount.add(totalOutstandingAmount);
transactionStartDate = transactionEndDate;
isOutstandingAmountCalculated = true;
}
// TODO - HUGO - calculate interest on calculation method
// if (savingInterestCalculationMethod.isAverageBalance()) {
averageBalanceForTerm = BigDecimal.valueOf(termTotalAmount.doubleValue() / this.interestPostEvery);
BigDecimal interestRatePerTerm = BigDecimal.valueOf(interestRateAsFraction.doubleValue() / monthsInYear.doubleValue()
* this.interestPostEvery.doubleValue());
BigDecimal interestPerTerm = averageBalanceForTerm.multiply(interestRatePerTerm);
this.interestPostedAmount = this.interestPostedAmount.add(interestPerTerm);
totalOutstandingAmount = totalOutstandingAmount.add(interestPerTerm);
// } else if(savingInterestCalculationMethod.isMonthlyCollection()){
// }
this.outstandingAmount = this.outstandingAmount.add(interestPerTerm);
this.lastInterestPostedDate = getNextInterestPostedDate().toDate();
this.nextInterestPostingDate = getNextInterestPostedDate().plusMonths(this.interestPostEvery).toDate();
postInterestItereations--;
}
}
private final LocalDate getLastInterestPostedDate() {
LocalDate lastInterestPostedDate;
if (this.lastInterestPostedDate == null) {
lastInterestPostedDate = new LocalDate(this.actualCommencementDate);
} else {
lastInterestPostedDate = new LocalDate(this.lastInterestPostedDate);
}
return lastInterestPostedDate;
}
private final LocalDate getNextInterestPostedDate() {
LocalDate nextInterestPostingDate;
if (this.nextInterestPostingDate == null) {
nextInterestPostingDate = new LocalDate(this.nextInterestPostingDate).plusMonths(this.interestPostEvery);
} else {
nextInterestPostingDate = new LocalDate(this.nextInterestPostingDate);
}
return nextInterestPostingDate;
}
}
@@ -1,96 +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.savingsaccount.domain;
import java.math.BigDecimal;
import java.util.Date;
import javax.persistence.CascadeType;
import javax.persistence.Column;
import javax.persistence.Entity;
import javax.persistence.JoinColumn;
import javax.persistence.ManyToOne;
import javax.persistence.OneToOne;
import javax.persistence.Table;
import javax.persistence.Temporal;
import javax.persistence.TemporalType;
import org.joda.time.LocalDate;
import org.mifosplatform.infrastructure.core.domain.AbstractAuditableCustom;
import org.mifosplatform.portfolio.savingsdepositaccount.domain.DepositAccountTransactionType;
import org.mifosplatform.useradministration.domain.AppUser;
@Entity
@Table(name = "m_saving_account_transaction")
public class SavingAccountTransaction extends AbstractAuditableCustom<AppUser, Long> {
@SuppressWarnings("unused")
@ManyToOne(optional = false)
@JoinColumn(name = "saving_account_id", nullable = false)
private SavingAccount savingAccount;
@Column(name = "transaction_type_enum", nullable = false)
private Integer typeOf;
@SuppressWarnings("unused")
@OneToOne(optional = true, cascade = { CascadeType.PERSIST })
@JoinColumn(name = "contra_id")
private SavingAccountTransaction contra;
@Temporal(TemporalType.DATE)
@Column(name = "transaction_date", nullable = false)
private final Date transactionDate;
@Column(name = "amount", scale = 6, precision = 19, nullable = false)
private final BigDecimal amount;
public SavingAccountTransaction() {
this.transactionDate = null;
this.amount = BigDecimal.ZERO;
}
public SavingAccountTransaction(final DepositAccountTransactionType transactionType, final BigDecimal amount,
final LocalDate paymentDate) {
this.typeOf = transactionType.getValue();
this.amount = amount;
this.transactionDate = paymentDate.toDate();
}
public static SavingAccountTransaction deposit(final BigDecimal amount, final LocalDate paymentDate) {
return new SavingAccountTransaction(DepositAccountTransactionType.DEPOSIT, amount == null ? new BigDecimal(0) : amount, paymentDate);
}
public static SavingAccountTransaction withdraw(final BigDecimal amount, final LocalDate paymentDate) {
return new SavingAccountTransaction(DepositAccountTransactionType.WITHDRAW, amount == null ? new BigDecimal(0) : amount,
paymentDate);
}
public static SavingAccountTransaction postInterest(final BigDecimal amount, final LocalDate paymentDate) {
return new SavingAccountTransaction(DepositAccountTransactionType.INTEREST_POSTING, amount == null ? new BigDecimal(0) : amount,
paymentDate);
}
public void updateAccount(final SavingAccount savingAccount) {
this.savingAccount = savingAccount;
}
public DepositAccountTransactionType getTypeOf() {
return DepositAccountTransactionType.fromInt(this.typeOf);
}
public BigDecimal getAmount() {
return this.amount;
}
public LocalDate getTransactionDate() {
LocalDate transactionDate = null;
if (this.transactionDate != null) {
transactionDate = new LocalDate(this.transactionDate);
}
return transactionDate;
}
}
@@ -1,109 +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.savingsaccount.domain;
import java.math.BigDecimal;
import java.util.Date;
import javax.persistence.Column;
import javax.persistence.Entity;
import javax.persistence.JoinColumn;
import javax.persistence.ManyToOne;
import javax.persistence.Table;
import javax.persistence.Temporal;
import javax.persistence.TemporalType;
import org.mifosplatform.infrastructure.core.domain.AbstractAuditableCustom;
import org.mifosplatform.useradministration.domain.AppUser;
@Entity
@Table(name = "m_saving_schedule")
public class SavingScheduleInstallments extends AbstractAuditableCustom<AppUser, Long> {
@SuppressWarnings("unused")
@ManyToOne(optional = false)
@JoinColumn(name = "saving_account_id", nullable = false)
private SavingAccount savingAccount;
@Temporal(TemporalType.DATE)
@Column(name = "duedate", nullable = false)
private final Date dueDate;
@SuppressWarnings("unused")
@Column(name = "installment", nullable = false)
private final Integer installmentNumber;
@Column(name = "deposit", scale = 6, precision = 19, nullable = false)
private BigDecimal deposit;
@Temporal(TemporalType.DATE)
@Column(name = "payment_date", nullable = true)
private Date paymentDate;
@Column(name = "deposit_paid", scale = 6, precision = 19, nullable = true)
private BigDecimal depositPaid;
@SuppressWarnings("unused")
@Column(name = "interest_accured", scale = 6, precision = 19, nullable = true)
private BigDecimal interstAccured;
@Column(name = "completed_derived", nullable = false)
private boolean completed;
public SavingScheduleInstallments() {
this.dueDate = null;
this.installmentNumber = null;
this.paymentDate = null;
}
public SavingScheduleInstallments(SavingAccount account, Date dueDate, Integer installmentNumber, BigDecimal deposit,
BigDecimal interstAccured) {
this.savingAccount = account;
this.dueDate = dueDate;
this.installmentNumber = installmentNumber;
this.deposit = deposit;
this.paymentDate = null;
this.depositPaid = BigDecimal.ZERO;
this.completed = false;
this.interstAccured = interstAccured;
}
public void updateAccount(SavingAccount account) {
this.savingAccount = account;
}
public Date getPaymentDate() {
return this.paymentDate;
}
public void setPaymentDate(Date paymentDate) {
this.paymentDate = paymentDate;
}
public BigDecimal getDepositPaid() {
return this.depositPaid;
}
public void setDepositPaid(BigDecimal depositPaid) {
this.depositPaid = depositPaid;
}
public Date getDueDate() {
return this.dueDate;
}
public BigDecimal getDeposit() {
return this.deposit;
}
public boolean isCompleted() {
return this.completed;
}
public void setCompleted(boolean completed) {
this.completed = completed;
}
}
@@ -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.savingsaccount.exception;
import org.mifosplatform.infrastructure.core.exception.AbstractPlatformResourceNotFoundException;
public class SavingAccountNotFoundException extends AbstractPlatformResourceNotFoundException {
public SavingAccountNotFoundException(final Long id) {
super("error.msg.saving.account.id.invalid", "Saving account with identifier " + id + " does not exist", id);
}
}
@@ -1,24 +0,0 @@
package org.mifosplatform.portfolio.savingsaccount.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.savingsaccount.service.SavingAccountWritePlatformService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
@Service
public class ApproveSavingAccountCommandHandler implements NewCommandSourceHandler {
private final SavingAccountWritePlatformService savingAccountWritePlatformService;
@Autowired
public ApproveSavingAccountCommandHandler(final SavingAccountWritePlatformService savingAccountWritePlatformService) {
this.savingAccountWritePlatformService = savingAccountWritePlatformService;
}
@Override
public CommandProcessingResult processCommand(JsonCommand command) {
return this.savingAccountWritePlatformService.approveSavingAccount(command);
}
}
@@ -1,25 +0,0 @@
package org.mifosplatform.portfolio.savingsaccount.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.savingsaccount.service.SavingAccountWritePlatformService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
@Service
public class CreateSavingAccountCommandHandler implements NewCommandSourceHandler {
private final SavingAccountWritePlatformService savingAccountWritePlatformService;
@Autowired
public CreateSavingAccountCommandHandler(final SavingAccountWritePlatformService savingAccountWritePlatformService) {
this.savingAccountWritePlatformService = savingAccountWritePlatformService;
}
@Override
public CommandProcessingResult processCommand(JsonCommand command) {
return this.savingAccountWritePlatformService.createSavingAccount(command);
}
}
@@ -1,25 +0,0 @@
package org.mifosplatform.portfolio.savingsaccount.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.savingsaccount.service.SavingAccountWritePlatformService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
@Service
public class DeleteSavingAccountCommandHandler implements NewCommandSourceHandler {
private final SavingAccountWritePlatformService savingAccountWritePlatformService;
@Autowired
public DeleteSavingAccountCommandHandler(final SavingAccountWritePlatformService savingAccountWritePlatformService) {
this.savingAccountWritePlatformService = savingAccountWritePlatformService;
}
@Override
public CommandProcessingResult processCommand(JsonCommand command) {
return this.savingAccountWritePlatformService.deleteSavingAccount(command.entityId());
}
}
@@ -1,25 +0,0 @@
package org.mifosplatform.portfolio.savingsaccount.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.savingsaccount.service.SavingAccountWritePlatformService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
@Service
public class DepositSavingAmountCommandHandler implements NewCommandSourceHandler {
private final SavingAccountWritePlatformService savingAccountWritePlatformService;
@Autowired
public DepositSavingAmountCommandHandler(final SavingAccountWritePlatformService savingAccountWritePlatformService) {
this.savingAccountWritePlatformService = savingAccountWritePlatformService;
}
@Override
public CommandProcessingResult processCommand(JsonCommand command) {
return this.savingAccountWritePlatformService.depositMoney(command);
}
}
@@ -1,25 +0,0 @@
package org.mifosplatform.portfolio.savingsaccount.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.savingsaccount.service.SavingAccountWritePlatformService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
@Service
public class RejectSavingAccountCommandHandler implements NewCommandSourceHandler {
private final SavingAccountWritePlatformService savingAccountWritePlatformService;
@Autowired
public RejectSavingAccountCommandHandler(final SavingAccountWritePlatformService savingAccountWritePlatformService) {
this.savingAccountWritePlatformService = savingAccountWritePlatformService;
}
@Override
public CommandProcessingResult processCommand(JsonCommand command) {
return this.savingAccountWritePlatformService.rejectSavingApplication(command);
}
}
@@ -1,25 +0,0 @@
package org.mifosplatform.portfolio.savingsaccount.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.savingsaccount.service.SavingAccountWritePlatformService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
@Service
public class UndoApprovalSavingAccountCommandHandler implements NewCommandSourceHandler {
private final SavingAccountWritePlatformService savingAccountWritePlatformService;
@Autowired
public UndoApprovalSavingAccountCommandHandler(final SavingAccountWritePlatformService savingAccountWritePlatformService) {
this.savingAccountWritePlatformService = savingAccountWritePlatformService;
}
@Override
public CommandProcessingResult processCommand(JsonCommand command) {
return this.savingAccountWritePlatformService.undoSavingAccountApproval(command);
}
}
@@ -1,25 +0,0 @@
package org.mifosplatform.portfolio.savingsaccount.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.savingsaccount.service.SavingAccountWritePlatformService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
@Service
public class UpdateSavingAccountCommandHandler implements NewCommandSourceHandler {
private final SavingAccountWritePlatformService savingAccountWritePlatformService;
@Autowired
public UpdateSavingAccountCommandHandler(final SavingAccountWritePlatformService savingAccountWritePlatformService) {
this.savingAccountWritePlatformService = savingAccountWritePlatformService;
}
@Override
public CommandProcessingResult processCommand(JsonCommand command) {
return this.savingAccountWritePlatformService.updateSavingAccount(command.entityId(), command);
}
}
@@ -1,24 +0,0 @@
package org.mifosplatform.portfolio.savingsaccount.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.savingsaccount.service.SavingAccountWritePlatformService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
@Service
public class WithdrawSavingAmountCommandHandler implements NewCommandSourceHandler {
private final SavingAccountWritePlatformService savingAccountWritePlatformService;
@Autowired
public WithdrawSavingAmountCommandHandler(final SavingAccountWritePlatformService savingAccountWritePlatformService) {
this.savingAccountWritePlatformService = savingAccountWritePlatformService;
}
@Override
public CommandProcessingResult processCommand(JsonCommand command) {
return this.savingAccountWritePlatformService.withdrawSavingAmount(command);
}
}
@@ -1,25 +0,0 @@
package org.mifosplatform.portfolio.savingsaccount.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.savingsaccount.service.SavingAccountWritePlatformService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
@Service
public class WithdrawSavingApplicationCommandHandler implements NewCommandSourceHandler {
private final SavingAccountWritePlatformService savingAccountWritePlatformService;
@Autowired
public WithdrawSavingApplicationCommandHandler(final SavingAccountWritePlatformService savingAccountWritePlatformService) {
this.savingAccountWritePlatformService = savingAccountWritePlatformService;
}
@Override
public CommandProcessingResult processCommand(JsonCommand command) {
return this.savingAccountWritePlatformService.withdrawSavingApplication(command);
}
}
@@ -1,131 +0,0 @@
package org.mifosplatform.portfolio.savingsaccount.serialization;
import java.lang.reflect.Type;
import java.math.BigDecimal;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.HashSet;
import java.util.List;
import java.util.Locale;
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 CalculateSavingScheduleQueryFromApiJsonHelper {
final Set<String> supportedParams = new HashSet<String>(Arrays.asList("clientId", "productId", "externalId",
"savingsDepositAmountPerPeriod", "recurringInterestRate", "savingInterestRate", "tenure", "commencementDate", "locale",
"dateFormat", "isLockinPeriodAllowed", "lockinPeriod", "lockinPeriodType", "tenureType", "frequency", "interestType",
"interestCalculationMethod", "minimumBalanceForWithdrawal", "isPartialDepositAllowed", "depositEvery", "interestPostEvery",
"interestPostFrequency"));
private final FromJsonHelper fromApiJsonHelper;
@Autowired
public CalculateSavingScheduleQueryFromApiJsonHelper(final FromJsonHelper fromApiJsonHelper) {
this.fromApiJsonHelper = fromApiJsonHelper;
}
public void validate(final String json) {
if (StringUtils.isBlank(json)) { throw new InvalidJsonException(); }
final Type typeOfMap = new TypeToken<Map<String, Object>>() {}.getType();
fromApiJsonHelper.checkForUnsupportedParameters(typeOfMap, json, supportedParams);
final List<ApiParameterError> dataValidationErrors = new ArrayList<ApiParameterError>();
final DataValidatorBuilder baseDataValidator = new DataValidatorBuilder(dataValidationErrors).resource("saving.account");
final JsonElement element = fromApiJsonHelper.parse(json);
final Long productId = fromApiJsonHelper.extractLongNamed("productId", element);
baseDataValidator.reset().parameter("productId").value(productId).notNull();
final BigDecimal savingsDepositAmountPerPeriod = fromApiJsonHelper.extractBigDecimalWithLocaleNamed(
"savingsDepositAmountPerPeriod", element);
baseDataValidator.reset().parameter("savingsDepositAmountPerPeriod").value(savingsDepositAmountPerPeriod).notNull()
.zeroOrPositiveAmount();
final BigDecimal recurringInterestRate = fromApiJsonHelper.extractBigDecimalWithLocaleNamed("recurringInterestRate", element);
baseDataValidator.reset().parameter("recurringInterestRate").value(recurringInterestRate).notNull().zeroOrPositiveAmount();
final BigDecimal savingInterestRate = fromApiJsonHelper.extractBigDecimalWithLocaleNamed("savingInterestRate", element);
baseDataValidator.reset().parameter("savingInterestRate").value(savingInterestRate).notNull().zeroOrPositiveAmount();
final Integer tenure = fromApiJsonHelper.extractIntegerNamed("tenure", element, Locale.getDefault());
baseDataValidator.reset().parameter("tenure").value(tenure).notNull();
final LocalDate commencementDate = fromApiJsonHelper.extractLocalDateNamed("commencementDate", element);
baseDataValidator.reset().parameter("commencementDate").value(commencementDate).notNull();
final Boolean isLockinPeriodAllowedCommandValue = fromApiJsonHelper.extractBooleanNamed("isLockinPeriodAllowed", element);
baseDataValidator.reset().parameter("isLockinPeriodAllowed").value(isLockinPeriodAllowedCommandValue)
.trueOrFalseRequired(isBooleanValueUpdated(isLockinPeriodAllowedCommandValue));
final Integer lockinPeriod = fromApiJsonHelper.extractIntegerNamed("lockinPeriod", element, Locale.getDefault());
baseDataValidator.reset().parameter("lockinPeriod").value(lockinPeriod).notNull().zeroOrPositiveAmount();
final Integer lockinPeriodType = fromApiJsonHelper.extractIntegerNamed("lockinPeriodType", element, Locale.getDefault());
baseDataValidator.reset().parameter("lockinPeriodType").value(lockinPeriodType).notNull().inMinMaxRange(1, 3);
final Integer tenureType = fromApiJsonHelper.extractIntegerNamed("tenureType", element, Locale.getDefault());
baseDataValidator.reset().parameter("tenureType").value(tenureType).ignoreIfNull();
final Integer frequency = fromApiJsonHelper.extractIntegerNamed("frequency", element, Locale.getDefault());
baseDataValidator.reset().parameter("frequency").value(frequency).ignoreIfNull();
final Integer interestType = fromApiJsonHelper.extractIntegerNamed("interestType", element, Locale.getDefault());
baseDataValidator.reset().parameter("interestType").value(interestType).ignoreIfNull();
final Integer interestCalculationMethod = fromApiJsonHelper.extractIntegerNamed("interestCalculationMethod", element,
Locale.getDefault());
baseDataValidator.reset().parameter("interestCalculationMethod").value(interestCalculationMethod).ignoreIfNull();
final BigDecimal minimumBalanceForWithdrawal = fromApiJsonHelper.extractBigDecimalWithLocaleNamed("minimumBalanceForWithdrawal",
element);
baseDataValidator.reset().parameter("minimumBalanceForWithdrawal").value(minimumBalanceForWithdrawal).ignoreIfNull()
.zeroOrPositiveAmount();
final Boolean isPartialDepositAllowedCommandValue = fromApiJsonHelper.extractBooleanNamed("isPartialDepositAllowed", element);
baseDataValidator.reset().parameter("isPartialDepositAllowed").value(isPartialDepositAllowedCommandValue)
.trueOrFalseRequired(isBooleanValueUpdated(isPartialDepositAllowedCommandValue)).ignoreIfNull();
final Integer depositEvery = fromApiJsonHelper.extractIntegerNamed("depositEvery", element, Locale.getDefault());
baseDataValidator.reset().parameter("depositEvery").value(depositEvery).notNull().zeroOrPositiveAmount();
final Integer interestPostEvery = fromApiJsonHelper.extractIntegerNamed("interestPostEvery", element, Locale.getDefault());
baseDataValidator.reset().parameter("interestPostEvery").value(interestPostEvery).notNull().zeroOrPositiveAmount();
final Integer interestPostFrequency = fromApiJsonHelper.extractIntegerNamed("interestPostFrequency", element, Locale.getDefault());
baseDataValidator.reset().parameter("interestPostFrequency").value(interestPostFrequency).notNull().zeroOrPositiveAmount();
throwExceptionIfValidationWarningsExist(dataValidationErrors);
}
private Boolean isBooleanValueUpdated(final Boolean actualValue) {
Boolean isUpdated = false;
if (actualValue != null) {
isUpdated = true;
}
return isUpdated;
}
private void throwExceptionIfValidationWarningsExist(final List<ApiParameterError> dataValidationErrors) {
if (!dataValidationErrors.isEmpty()) { throw new PlatformApiDataValidationException("validation.msg.validation.errors.exist",
"Validation errors exist.", dataValidationErrors); }
}
}
@@ -1,216 +0,0 @@
package org.mifosplatform.portfolio.savingsaccount.serialization;
import java.lang.reflect.Type;
import java.math.BigDecimal;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.HashSet;
import java.util.List;
import java.util.Locale;
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 class SavingAccountCommandFromApiJsonDeserializer {
final Set<String> supportedParams = new HashSet<String>(Arrays.asList("clientId", "productId", "externalId", "currencyCode",
"digitsAfterDecimal", "savingsDepositAmountPerPeriod", "recurringInterestRate", "savingInterestRate", "tenure",
"commencementDate", "locale", "dateFormat", "isLockinPeriodAllowed", "lockinPeriod", "lockinPeriodType", "tenureType",
"frequency", "interestType", "interestCalculationMethod", "minimumBalanceForWithdrawal", "isPartialDepositAllowed",
"depositEvery", "interestPostEvery", "interestPostFrequency"));
private final FromJsonHelper fromApiJsonHelper;
@Autowired
public SavingAccountCommandFromApiJsonDeserializer(final FromJsonHelper fromApiJsonHelper) {
this.fromApiJsonHelper = fromApiJsonHelper;
}
public void validateForCreate(final String json) {
if (StringUtils.isBlank(json)) { throw new InvalidJsonException(); }
final Type typeOfMap = new TypeToken<Map<String, Object>>() {}.getType();
fromApiJsonHelper.checkForUnsupportedParameters(typeOfMap, json, supportedParams);
final List<ApiParameterError> dataValidationErrors = new ArrayList<ApiParameterError>();
final DataValidatorBuilder baseDataValidator = new DataValidatorBuilder(dataValidationErrors).resource("saving.account");
final JsonElement element = fromApiJsonHelper.parse(json);
final Long clientId = fromApiJsonHelper.extractLongNamed("clientId", element);
baseDataValidator.reset().parameter("clientId").value(clientId).notNull();
final Long productId = fromApiJsonHelper.extractLongNamed("productId", element);
baseDataValidator.reset().parameter("productId").value(productId).notNull();
final String externalId = fromApiJsonHelper.extractStringNamed("externalId", element);
baseDataValidator.reset().parameter("externalId").value(externalId).ignoreIfNull().notExceedingLengthOf(100);
final BigDecimal savingsDepositAmountPerPeriod = fromApiJsonHelper.extractBigDecimalWithLocaleNamed(
"savingsDepositAmountPerPeriod", element);
baseDataValidator.reset().parameter("savingsDepositAmountPerPeriod").value(savingsDepositAmountPerPeriod).notNull()
.zeroOrPositiveAmount();
final BigDecimal recurringInterestRate = fromApiJsonHelper.extractBigDecimalWithLocaleNamed("recurringInterestRate", element);
baseDataValidator.reset().parameter("recurringInterestRate").value(recurringInterestRate).notNull().zeroOrPositiveAmount();
final BigDecimal savingInterestRate = fromApiJsonHelper.extractBigDecimalWithLocaleNamed("savingInterestRate", element);
baseDataValidator.reset().parameter("savingInterestRate").value(savingInterestRate).notNull().zeroOrPositiveAmount();
final Integer tenure = fromApiJsonHelper.extractIntegerNamed("tenure", element, Locale.getDefault());
baseDataValidator.reset().parameter("tenure").value(tenure).notNull();
final LocalDate commencementDate = fromApiJsonHelper.extractLocalDateNamed("commencementDate", element);
baseDataValidator.reset().parameter("commencementDate").value(commencementDate).notNull();
final Boolean isLockinPeriodAllowedCommandValue = fromApiJsonHelper.extractBooleanNamed("isLockinPeriodAllowed", element);
baseDataValidator.reset().parameter("isLockinPeriodAllowed").value(isLockinPeriodAllowedCommandValue)
.trueOrFalseRequired(isBooleanValueUpdated(isLockinPeriodAllowedCommandValue));
final Integer lockinPeriod = fromApiJsonHelper.extractIntegerNamed("lockinPeriod", element, Locale.getDefault());
baseDataValidator.reset().parameter("lockinPeriod").value(lockinPeriod).notNull().zeroOrPositiveAmount();
final Integer lockinPeriodType = fromApiJsonHelper.extractIntegerNamed("lockinPeriodType", element, Locale.getDefault());
baseDataValidator.reset().parameter("lockinPeriodType").value(lockinPeriodType).notNull().inMinMaxRange(1, 3);
final Integer tenureType = fromApiJsonHelper.extractIntegerNamed("tenureType", element, Locale.getDefault());
baseDataValidator.reset().parameter("tenureType").value(tenureType).ignoreIfNull();
final Integer frequency = fromApiJsonHelper.extractIntegerNamed("frequency", element, Locale.getDefault());
baseDataValidator.reset().parameter("frequency").value(frequency).ignoreIfNull();
final Integer interestType = fromApiJsonHelper.extractIntegerNamed("interestType", element, Locale.getDefault());
baseDataValidator.reset().parameter("interestType").value(interestType).ignoreIfNull();
final Integer interestCalculationMethod = fromApiJsonHelper.extractIntegerNamed("interestCalculationMethod", element,
Locale.getDefault());
baseDataValidator.reset().parameter("interestCalculationMethod").value(interestCalculationMethod).ignoreIfNull();
final BigDecimal minimumBalanceForWithdrawal = fromApiJsonHelper.extractBigDecimalWithLocaleNamed("minimumBalanceForWithdrawal",
element);
baseDataValidator.reset().parameter("minimumBalanceForWithdrawal").value(minimumBalanceForWithdrawal).ignoreIfNull()
.zeroOrPositiveAmount();
final Boolean isPartialDepositAllowedCommandValue = fromApiJsonHelper.extractBooleanNamed("isPartialDepositAllowed", element);
baseDataValidator.reset().parameter("isPartialDepositAllowed").value(isPartialDepositAllowedCommandValue)
.trueOrFalseRequired(isBooleanValueUpdated(isPartialDepositAllowedCommandValue)).ignoreIfNull();
final Integer depositEvery = fromApiJsonHelper.extractIntegerNamed("depositEvery", element, Locale.getDefault());
baseDataValidator.reset().parameter("depositEvery").value(depositEvery).notNull().zeroOrPositiveAmount();
final Integer interestPostEvery = fromApiJsonHelper.extractIntegerNamed("interestPostEvery", element, Locale.getDefault());
baseDataValidator.reset().parameter("interestPostEvery").value(interestPostEvery).notNull().zeroOrPositiveAmount();
final Integer interestPostFrequency = fromApiJsonHelper.extractIntegerNamed("interestPostFrequency", element, Locale.getDefault());
baseDataValidator.reset().parameter("interestPostFrequency").value(interestPostFrequency).notNull().zeroOrPositiveAmount();
throwExceptionIfValidationWarningsExist(dataValidationErrors);
}
public void validateForUpdate(final String json) {
if (StringUtils.isBlank(json)) { throw new InvalidJsonException(); }
final Type typeOfMap = new TypeToken<Map<String, Object>>() {}.getType();
fromApiJsonHelper.checkForUnsupportedParameters(typeOfMap, json, supportedParams);
final List<ApiParameterError> dataValidationErrors = new ArrayList<ApiParameterError>();
final DataValidatorBuilder baseDataValidator = new DataValidatorBuilder(dataValidationErrors).resource("saving.account");
final JsonElement element = fromApiJsonHelper.parse(json);
final Long productId = fromApiJsonHelper.extractLongNamed("productId", element);
baseDataValidator.reset().parameter("productId").value(productId).ignoreIfNull();
final String externalId = fromApiJsonHelper.extractStringNamed("externalId", element);
baseDataValidator.reset().parameter("externalId").value(externalId).ignoreIfNull().notExceedingLengthOf(100);
final BigDecimal savingsDepositAmountPerPeriod = fromApiJsonHelper.extractBigDecimalWithLocaleNamed(
"savingsDepositAmountPerPeriod", element);
baseDataValidator.reset().parameter("savingsDepositAmountPerPeriod").value(savingsDepositAmountPerPeriod).ignoreIfNull()
.zeroOrPositiveAmount();
final BigDecimal recurringInterestRate = fromApiJsonHelper.extractBigDecimalWithLocaleNamed("recurringInterestRate", element);
baseDataValidator.reset().parameter("recurringInterestRate").value(recurringInterestRate).ignoreIfNull().zeroOrPositiveAmount();
final BigDecimal savingInterestRate = fromApiJsonHelper.extractBigDecimalWithLocaleNamed("savingInterestRate", element);
baseDataValidator.reset().parameter("savingInterestRate").value(savingInterestRate).ignoreIfNull().zeroOrPositiveAmount();
final Integer tenure = fromApiJsonHelper.extractIntegerNamed("tenure", element, Locale.getDefault());
baseDataValidator.reset().parameter("tenure").value(tenure).ignoreIfNull();
final LocalDate commencementDate = fromApiJsonHelper.extractLocalDateNamed("commencementDate", element);
baseDataValidator.reset().parameter("commencementDate").value(commencementDate).ignoreIfNull();
final Boolean isLockinPeriodAllowedCommandValue = fromApiJsonHelper.extractBooleanNamed("isLockinPeriodAllowed", element);
baseDataValidator.reset().parameter("isLockinPeriodAllowed").value(isLockinPeriodAllowedCommandValue)
.trueOrFalseRequired(isBooleanValueUpdated(isLockinPeriodAllowedCommandValue));
final Integer lockinPeriod = fromApiJsonHelper.extractIntegerNamed("lockinPeriod", element, Locale.getDefault());
baseDataValidator.reset().parameter("lockinPeriod").value(lockinPeriod).ignoreIfNull().zeroOrPositiveAmount();
final Integer lockinPeriodType = fromApiJsonHelper.extractIntegerNamed("lockinPeriodType", element, Locale.getDefault());
baseDataValidator.reset().parameter("lockinPeriodType").value(lockinPeriodType).ignoreIfNull().inMinMaxRange(1, 3);
final Integer tenureType = fromApiJsonHelper.extractIntegerNamed("tenureType", element, Locale.getDefault());
baseDataValidator.reset().parameter("tenureType").value(tenureType).ignoreIfNull();
final Integer frequency = fromApiJsonHelper.extractIntegerNamed("frequency", element, Locale.getDefault());
baseDataValidator.reset().parameter("frequency").value(frequency).ignoreIfNull();
final Integer interestType = fromApiJsonHelper.extractIntegerNamed("interestType", element, Locale.getDefault());
baseDataValidator.reset().parameter("interestType").value(interestType).ignoreIfNull();
final Integer interestCalculationMethod = fromApiJsonHelper.extractIntegerNamed("interestCalculationMethod", element,
Locale.getDefault());
baseDataValidator.reset().parameter("interestCalculationMethod").value(interestCalculationMethod).ignoreIfNull();
final BigDecimal minimumBalanceForWithdrawal = fromApiJsonHelper.extractBigDecimalWithLocaleNamed("minimumBalanceForWithdrawal",
element);
baseDataValidator.reset().parameter("minimumBalanceForWithdrawal").value(minimumBalanceForWithdrawal).ignoreIfNull()
.zeroOrPositiveAmount();
final Boolean isPartialDepositAllowedCommandValue = fromApiJsonHelper.extractBooleanNamed("isPartialDepositAllowed", element);
baseDataValidator.reset().parameter("isPartialDepositAllowed").value(isPartialDepositAllowedCommandValue)
.trueOrFalseRequired(isBooleanValueUpdated(isPartialDepositAllowedCommandValue)).ignoreIfNull();
final Integer depositEvery = fromApiJsonHelper.extractIntegerNamed("depositEvery", element, Locale.getDefault());
baseDataValidator.reset().parameter("depositEvery").value(depositEvery).ignoreIfNull().zeroOrPositiveAmount();
final Integer interestPostEvery = fromApiJsonHelper.extractIntegerNamed("interestPostEvery", element, Locale.getDefault());
baseDataValidator.reset().parameter("interestPostEvery").value(interestPostEvery).ignoreIfNull().zeroOrPositiveAmount();
final Integer interestPostFrequency = fromApiJsonHelper.extractIntegerNamed("interestPostFrequency", element, Locale.getDefault());
baseDataValidator.reset().parameter("interestPostFrequency").value(interestPostFrequency).ignoreIfNull().zeroOrPositiveAmount();
throwExceptionIfValidationWarningsExist(dataValidationErrors);
}
private Boolean isBooleanValueUpdated(final Boolean actualValue) {
Boolean isUpdated = false;
if (actualValue != null) {
isUpdated = true;
}
return isUpdated;
}
private void throwExceptionIfValidationWarningsExist(final List<ApiParameterError> dataValidationErrors) {
if (!dataValidationErrors.isEmpty()) { throw new PlatformApiDataValidationException("validation.msg.validation.errors.exist",
"Validation errors exist.", dataValidationErrors); }
}
}
@@ -1,153 +0,0 @@
package org.mifosplatform.portfolio.savingsaccount.serialization;
import java.lang.reflect.Type;
import java.math.BigDecimal;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.HashSet;
import java.util.List;
import java.util.Locale;
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 class SavingAccountStateTransitionCommandFromApiJsonDeserializer {
private final Set<String> supportedParams = new HashSet<String>(Arrays.asList("locale", "dateFormat", "commencementDate", "eventDate",
"savingsDepositAmountPerPeriod", "minimumBalanceForWithdrawal", "recurringInterestRate", "savingInterestRate", "depositDate",
"interestType", "tenure", "tenureType", "frequency", "payEvery", "note", "interestPostEvery", "interestPostFrequency"));
private final FromJsonHelper fromApiJsonHelper;
@Autowired
public SavingAccountStateTransitionCommandFromApiJsonDeserializer(final FromJsonHelper fromApiJsonHelper) {
this.fromApiJsonHelper = fromApiJsonHelper;
}
public void validateForApprove(final String json) {
if (StringUtils.isBlank(json)) { throw new InvalidJsonException(); }
final Type typeOfMap = new TypeToken<Map<String, Object>>() {}.getType();
fromApiJsonHelper.checkForUnsupportedParameters(typeOfMap, json, supportedParams);
final List<ApiParameterError> dataValidationErrors = new ArrayList<ApiParameterError>();
final DataValidatorBuilder baseDataValidator = new DataValidatorBuilder(dataValidationErrors).resource("saving.account.transition");
final JsonElement element = fromApiJsonHelper.parse(json);
final LocalDate commencementDate = fromApiJsonHelper.extractLocalDateNamed("commencementDate", element);
baseDataValidator.reset().parameter("commencementDate").value(commencementDate).notNull();
final BigDecimal savingsDepositAmountPerPeriod = fromApiJsonHelper.extractBigDecimalWithLocaleNamed(
"savingsDepositAmountPerPeriod", element);
baseDataValidator.reset().parameter("savingsDepositAmountPerPeriod").value(savingsDepositAmountPerPeriod).ignoreIfNull()
.zeroOrPositiveAmount();
final BigDecimal minimumBalanceForWithdrawal = fromApiJsonHelper.extractBigDecimalWithLocaleNamed("minimumBalanceForWithdrawal",
element);
baseDataValidator.reset().parameter("minimumBalanceForWithdrawal").value(minimumBalanceForWithdrawal).ignoreIfNull()
.zeroOrPositiveAmount();
final BigDecimal recurringInterestRate = fromApiJsonHelper.extractBigDecimalWithLocaleNamed("recurringInterestRate", element);
baseDataValidator.reset().parameter("recurringInterestRate").value(recurringInterestRate).ignoreIfNull().zeroOrPositiveAmount();
final BigDecimal savingInterestRate = fromApiJsonHelper.extractBigDecimalWithLocaleNamed("savingInterestRate", element);
baseDataValidator.reset().parameter("savingInterestRate").value(savingInterestRate).ignoreIfNull().zeroOrPositiveAmount();
final Integer interestType = fromApiJsonHelper.extractIntegerNamed("interestType", element, Locale.getDefault());
baseDataValidator.reset().parameter("interestType").value(interestType).ignoreIfNull().zeroOrPositiveAmount();
final Integer tenureType = fromApiJsonHelper.extractIntegerNamed("tenureType", element, Locale.getDefault());
baseDataValidator.reset().parameter("tenureType").value(tenureType).ignoreIfNull().zeroOrPositiveAmount();
final Integer tenure = fromApiJsonHelper.extractIntegerNamed("tenure", element, Locale.getDefault());
baseDataValidator.reset().parameter("tenure").value(tenure).ignoreIfNull().zeroOrPositiveAmount();
final Integer frequency = fromApiJsonHelper.extractIntegerNamed("frequency", element, Locale.getDefault());
baseDataValidator.reset().parameter("frequency").value(frequency).ignoreIfNull().zeroOrPositiveAmount();
final Integer depositEvery = fromApiJsonHelper.extractIntegerNamed("payEvery", element, Locale.getDefault());
baseDataValidator.reset().parameter("payEvery").value(depositEvery).ignoreIfNull().zeroOrPositiveAmount();
throwExceptionIfValidationWarningsExist(dataValidationErrors);
}
public void validateForReject(final String json) {
if (StringUtils.isBlank(json)) { throw new InvalidJsonException(); }
final Type typeOfMap = new TypeToken<Map<String, Object>>() {}.getType();
fromApiJsonHelper.checkForUnsupportedParameters(typeOfMap, json, supportedParams);
final List<ApiParameterError> dataValidationErrors = new ArrayList<ApiParameterError>();
final DataValidatorBuilder baseDataValidator = new DataValidatorBuilder(dataValidationErrors).resource("saving.account.transition");
final JsonElement element = fromApiJsonHelper.parse(json);
final LocalDate eventDate = fromApiJsonHelper.extractLocalDateNamed("eventDate", element);
baseDataValidator.reset().parameter("eventDate").value(eventDate).notNull();
throwExceptionIfValidationWarningsExist(dataValidationErrors);
}
public void validateForWithdrawApplication(final String json) {
if (StringUtils.isBlank(json)) { throw new InvalidJsonException(); }
final Type typeOfMap = new TypeToken<Map<String, Object>>() {}.getType();
fromApiJsonHelper.checkForUnsupportedParameters(typeOfMap, json, supportedParams);
final List<ApiParameterError> dataValidationErrors = new ArrayList<ApiParameterError>();
final DataValidatorBuilder baseDataValidator = new DataValidatorBuilder(dataValidationErrors).resource("saving.account.transition");
final JsonElement element = fromApiJsonHelper.parse(json);
final LocalDate eventDate = fromApiJsonHelper.extractLocalDateNamed("eventDate", element);
baseDataValidator.reset().parameter("eventDate").value(eventDate).notNull();
throwExceptionIfValidationWarningsExist(dataValidationErrors);
}
public void validateForDepositAmount(final String json) {
if (StringUtils.isBlank(json)) { throw new InvalidJsonException(); }
final Type typeOfMap = new TypeToken<Map<String, Object>>() {}.getType();
fromApiJsonHelper.checkForUnsupportedParameters(typeOfMap, json, supportedParams);
final List<ApiParameterError> dataValidationErrors = new ArrayList<ApiParameterError>();
final DataValidatorBuilder baseDataValidator = new DataValidatorBuilder(dataValidationErrors)
.resource("saving.account.transaction.deposit");
final JsonElement element = fromApiJsonHelper.parse(json);
final LocalDate depositDate = fromApiJsonHelper.extractLocalDateNamed("depositDate", element);
baseDataValidator.reset().parameter("depositDate").value(depositDate).notNull();
final BigDecimal savingsDepositAmountPerPeriod = fromApiJsonHelper.extractBigDecimalWithLocaleNamed(
"savingsDepositAmountPerPeriod", element);
baseDataValidator.reset().parameter("savingsDepositAmountPerPeriod").value(savingsDepositAmountPerPeriod).notNull()
.zeroOrPositiveAmount();
throwExceptionIfValidationWarningsExist(dataValidationErrors);
}
private void throwExceptionIfValidationWarningsExist(final List<ApiParameterError> dataValidationErrors) {
if (!dataValidationErrors.isEmpty()) { throw new PlatformApiDataValidationException("validation.msg.validation.errors.exist",
"Validation errors exist.", dataValidationErrors); }
}
}
@@ -1,14 +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.savingsaccount.service;
import org.mifosplatform.infrastructure.core.api.JsonQuery;
import org.mifosplatform.portfolio.savingsaccount.data.SavingScheduleData;
public interface CalculateSavingSchedule {
SavingScheduleData calculateSavingSchedule(JsonQuery query);
}
@@ -1,42 +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.savingsaccount.service;
import org.mifosplatform.infrastructure.core.api.JsonQuery;
import org.mifosplatform.infrastructure.security.service.PlatformSecurityContext;
import org.mifosplatform.portfolio.savingsaccount.data.SavingScheduleData;
import org.mifosplatform.portfolio.savingsaccount.serialization.CalculateSavingScheduleQueryFromApiJsonHelper;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
@Service
public class CalculateSavingScheduleImpl implements CalculateSavingSchedule {
private final PlatformSecurityContext context;
private final CalculateSavingScheduleQueryFromApiJsonHelper fromApiJsonDeserializer;
private final SavingScheduleAssembler savingScheduleAssembler;
@Autowired
public CalculateSavingScheduleImpl(final PlatformSecurityContext context,
final CalculateSavingScheduleQueryFromApiJsonHelper fromApiJsonDeserializer,
final SavingScheduleAssembler savingScheduleAssembler) {
this.context = context;
this.fromApiJsonDeserializer = fromApiJsonDeserializer;
this.savingScheduleAssembler = savingScheduleAssembler;
}
@Override
public SavingScheduleData calculateSavingSchedule(final JsonQuery query) {
context.authenticatedUser();
this.fromApiJsonDeserializer.validate(query.json());
return this.savingScheduleAssembler.fromJson(query.parsedJson());
}
}
@@ -1,57 +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.savingsaccount.service;
import java.util.ArrayList;
import java.util.List;
import org.joda.time.LocalDate;
import org.mifosplatform.portfolio.savingsaccount.domain.DepositScheduleDateGenerator;
import org.mifosplatform.portfolio.savingsaccountproduct.domain.SavingFrequencyType;
public class DefaultDepositScheduleDateGenerator implements DepositScheduleDateGenerator {
@Override
public List<LocalDate> generate(LocalDate scheuleStartDate, Integer paymentPeriods, Integer depositFrequency,
SavingFrequencyType savingFrequencyType) {
List<LocalDate> duePaymentPeriodDates = new ArrayList<LocalDate>(depositFrequency);
LocalDate startDate = scheuleStartDate;
for (int period = 1; period <= paymentPeriods; period++) {
LocalDate duePaymentPeriodDate = startDate;
if (period == 1) {
duePaymentPeriodDate = startDate;
} else {
switch (savingFrequencyType) {
case DAILY:
duePaymentPeriodDate = startDate.plusDays(depositFrequency);
break;
case MONTHLY:
duePaymentPeriodDate = startDate.plusMonths(depositFrequency);
break;
case QUATERLY:
duePaymentPeriodDate = startDate.plusMonths(3*depositFrequency);
break;
case HALFYEARLY:
duePaymentPeriodDate = startDate.plusMonths(6*depositFrequency);
break;
case YEARLY:
duePaymentPeriodDate = startDate.plusYears(depositFrequency);
break;
default:
break;
}
}
duePaymentPeriodDates.add(duePaymentPeriodDate);
startDate = duePaymentPeriodDate;
}
return duePaymentPeriodDates;
}
}
@@ -1,512 +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.savingsaccount.service;
import java.math.BigDecimal;
import java.util.Arrays;
import java.util.LinkedHashMap;
import java.util.List;
import java.util.Map;
import org.joda.time.LocalDate;
import org.mifosplatform.infrastructure.core.api.JsonCommand;
import org.mifosplatform.infrastructure.core.serialization.FromJsonHelper;
import org.mifosplatform.organisation.monetary.domain.MonetaryCurrency;
import org.mifosplatform.organisation.monetary.domain.Money;
import org.mifosplatform.portfolio.client.domain.Client;
import org.mifosplatform.portfolio.client.domain.ClientRepository;
import org.mifosplatform.portfolio.client.exception.ClientNotFoundException;
import org.mifosplatform.portfolio.loanproduct.domain.PeriodFrequencyType;
import org.mifosplatform.portfolio.savingsaccount.data.SavingScheduleData;
import org.mifosplatform.portfolio.savingsaccount.data.SavingSchedulePeriodData;
import org.mifosplatform.portfolio.savingsaccount.domain.ReccuringDepositInterestCalculator;
import org.mifosplatform.portfolio.savingsaccount.domain.SavingAccount;
import org.mifosplatform.portfolio.savingsaccount.domain.SavingScheduleInstallments;
import org.mifosplatform.portfolio.savingsaccountproduct.domain.SavingFrequencyType;
import org.mifosplatform.portfolio.savingsaccountproduct.domain.SavingInterestCalculationMethod;
import org.mifosplatform.portfolio.savingsaccountproduct.domain.SavingProduct;
import org.mifosplatform.portfolio.savingsaccountproduct.domain.SavingProductRepository;
import org.mifosplatform.portfolio.savingsaccountproduct.domain.SavingProductType;
import org.mifosplatform.portfolio.savingsaccountproduct.domain.SavingsInterestType;
import org.mifosplatform.portfolio.savingsaccountproduct.exception.SavingProductNotFoundException;
import org.mifosplatform.portfolio.savingsdepositaccount.domain.DepositAccountStatus;
import org.mifosplatform.portfolio.savingsdepositaccount.domain.DepositLifecycleStateMachine;
import org.mifosplatform.portfolio.savingsdepositaccount.domain.DepositLifecycleStateMachineImpl;
import org.mifosplatform.portfolio.savingsdepositaccount.exception.DepositAccountTransactionsException;
import org.mifosplatform.portfolio.savingsdepositproduct.domain.TenureTypeEnum;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import com.google.gson.JsonElement;
@Service
public class SavingAccountAssembler {
private final ClientRepository clientRepository;
private final SavingProductRepository savingProductRepository;
private final ReccuringDepositInterestCalculator reccuringDepositInterestCalculator;
private final FromJsonHelper fromApiJsonHelper;
private final SavingScheduleAssembler savingScheduleAssembler;
@Autowired
public SavingAccountAssembler(final ClientRepository clientRepository, final SavingProductRepository savingProductRepository,
final ReccuringDepositInterestCalculator reccuringDepositInterestCalculator, final FromJsonHelper fromApiJsonHelper,
final SavingScheduleAssembler savingScheduleAssembler) {
this.clientRepository = clientRepository;
this.savingProductRepository = savingProductRepository;
this.reccuringDepositInterestCalculator = reccuringDepositInterestCalculator;
this.fromApiJsonHelper = fromApiJsonHelper;
this.savingScheduleAssembler = savingScheduleAssembler;
}
public SavingAccount assembleFrom(final JsonCommand command) {
final JsonElement element = command.parsedJson();
final Long clientId = fromApiJsonHelper.extractLongNamed("clientId", element);
final Long productId = fromApiJsonHelper.extractLongNamed("productId", element);
final String externalId = fromApiJsonHelper.extractStringNamed("externalId", element);
final String currencyCode = command.stringValueOfParameterNamed("currencyCode");
final Integer digitsAfterDecimal = command.integerValueOfParameterNamed("digitsAfterDecimal");
final BigDecimal savingsDepositAmountPerPeriod = command.bigDecimalValueOfParameterNamed("savingsDepositAmountPerPeriod");
final BigDecimal recurringInterestRate = command.bigDecimalValueOfParameterNamed("recurringInterestRate");
final BigDecimal savingInterestRateCommandValue = command.bigDecimalValueOfParameterNamed("savingInterestRate");
final Integer tenureCommandValue = command.integerValueOfParameterNamed("tenure");
final LocalDate commencementDate = command.localDateValueOfParameterNamed("commencementDate");
final Integer lockinPeriodTypeCommandValue = command.integerValueOfParameterNamed("lockinPeriodType");
final boolean isLockinPeriodAllowedCommandValue = command.booleanPrimitiveValueOfParameterNamed("isLockinPeriodAllowed");
final Integer lockinPeriodCommandValue = command.integerValueOfParameterNamed("lockinPeriod");
final Integer tenureTypeCommandValue = command.integerValueOfParameterNamed("tenureType");
final Integer frequencyCommandValue = command.integerValueOfParameterNamed("frequency");
final Integer interestTypeCommandValue = command.integerValueOfParameterNamed("interestType");
final Integer interestCalculationMethodCommandValue = command.integerValueOfParameterNamed("interestCalculationMethod");
// final BigDecimal minimumBalanceForWithdrawal =
// command.bigDecimalValueOfParameterNamed("minimumBalanceForWithdrawal");
// final boolean isPartialDepositAllowed =
// command.booleanPrimitiveValueOfParameterNamed("isPartialDepositAllowed");
final Integer depositEvery = command.integerValueOfParameterNamed("depositEvery");
final Integer interestPostEvery = command.integerValueOfParameterNamed("interestPostEvery");
final Integer interestPostFrequencyCommandValue = command.integerValueOfParameterNamed("interestPostFrequency");
Client client = this.clientRepository.findOne(clientId);
if (client == null || client.isDeleted()) { throw new ClientNotFoundException(clientId); }
SavingProduct product = this.savingProductRepository.findOne(productId);
if (product == null || product.isDeleted()) { throw new SavingProductNotFoundException(productId); }
MonetaryCurrency currency = product.getCurrency();
if (currencyCode != null) currency = new MonetaryCurrency(currencyCode, currency.getDigitsAfterDecimal());
if (digitsAfterDecimal != null) currency = new MonetaryCurrency(currency.getCode(), digitsAfterDecimal);
Money savingsDeposit = Money.of(currency, product.getSavingProductRelatedDetail().getSavingsDepositAmount());
if (savingsDepositAmountPerPeriod != null) {
savingsDeposit = Money.of(currency, savingsDepositAmountPerPeriod);
}
Integer tenure = product.getSavingProductRelatedDetail().getTenure();
if (tenureCommandValue != null) {
tenure = tenureCommandValue;
}
TenureTypeEnum tenureTypeEnum = TenureTypeEnum.fromInt(product.getSavingProductRelatedDetail().getTenureType());
if (tenureTypeCommandValue != null) {
tenureTypeEnum = TenureTypeEnum.fromInt(tenureTypeCommandValue);
}
SavingProductType savingProductType = SavingProductType.fromInt(product.getSavingProductRelatedDetail().getSavingProductType());
SavingFrequencyType savingFrequencyType = SavingFrequencyType.fromInt(product.getSavingProductRelatedDetail().getFrequency());
if (frequencyCommandValue != null) {
savingFrequencyType = SavingFrequencyType.fromInt(frequencyCommandValue);
}
SavingInterestCalculationMethod savingInterestCalculationMethod = SavingInterestCalculationMethod.fromInt(product
.getSavingProductRelatedDetail().getInterestCalculationMethod());
if (interestCalculationMethodCommandValue != null) {
savingInterestCalculationMethod = SavingInterestCalculationMethod.fromInt(interestCalculationMethodCommandValue);
}
SavingsInterestType interestType = SavingsInterestType.fromInt(product.getSavingProductRelatedDetail().getInterestType());
if (interestTypeCommandValue != null) {
interestType = SavingsInterestType.fromInt(interestTypeCommandValue);
}
BigDecimal savingInterestRate = product.getInterestRate();
if (savingInterestRateCommandValue != null) savingInterestRate = savingInterestRateCommandValue;
boolean isLockinPeriodAllowed = product.getSavingProductRelatedDetail().isLockinPeriodAllowed();
if (isBooleanValueUpdated(isLockinPeriodAllowedCommandValue)) {
isLockinPeriodAllowed = isLockinPeriodAllowedCommandValue;
}
Integer lockinPeriod = product.getSavingProductRelatedDetail().getLockinPeriod();
if (lockinPeriodCommandValue != null) {
lockinPeriod = lockinPeriodCommandValue;
}
PeriodFrequencyType lockinPeriodType = PeriodFrequencyType.fromInt(product.getSavingProductRelatedDetail().getLockinPeriodType());
if (lockinPeriodTypeCommandValue != null) {
lockinPeriodType = PeriodFrequencyType.fromInt(lockinPeriodTypeCommandValue);
}
Integer interestPostFrequency = PeriodFrequencyType.fromInt(interestPostFrequencyCommandValue).getValue();
SavingAccount account = SavingAccount.openNew(client, product, externalId, savingsDeposit, recurringInterestRate,
savingInterestRate, tenure, commencementDate, tenureTypeEnum, savingProductType, savingFrequencyType, interestType,
savingInterestCalculationMethod, isLockinPeriodAllowed, lockinPeriod, lockinPeriodType,
this.reccuringDepositInterestCalculator, defaultDepositLifecycleStateMachine(), depositEvery, interestPostEvery,
interestPostFrequency);
SavingScheduleData savingScheduleData = this.savingScheduleAssembler.fromJson(element);
for (SavingSchedulePeriodData savingSchedulePeriodData : savingScheduleData.getPeriods()) {
final SavingScheduleInstallments installment = new SavingScheduleInstallments(account, savingSchedulePeriodData.getDueDate()
.toDate(), savingSchedulePeriodData.getPeriod(), savingSchedulePeriodData.getDepositDue(),
savingSchedulePeriodData.getInterestAccured());
account.addSavingScheduleInstallment(installment);
}
return account;
}
public Map<String, Object> assembleFrom(final JsonCommand command, final SavingAccount account) {
JsonElement element = command.parsedJson();
Map<String, Object> actualChanges = new LinkedHashMap<String, Object>(20);
final String localeAsInput = command.locale();
SavingProduct product = account.getProduct();
final String productIdParamName = "productId";
if (command.isChangeInLongParameterNamed(productIdParamName, product.getId())) {
final Long newValue = command.longValueOfParameterNamed(productIdParamName);
if (newValue != null) {
product = this.savingProductRepository.findOne(newValue);
actualChanges.put("productId", newValue);
if (product == null || product.isDeleted()) throw new SavingProductNotFoundException(newValue);
}
}
String externalId = account.getExternalId();
final String externalIdParamName = "externalId";
if (command.isChangeInStringParameterNamed(externalIdParamName, externalId)) {
final String newValue = command.stringValueOfParameterNamed(externalIdParamName);
actualChanges.put(externalIdParamName, newValue);
externalId = newValue;
}
Money savingsDeposit = Money.of(product.getCurrency(), account.getSavingsDepositAmountPerPeriod());
final String savingsDepositAmountPerPeriodParamName = "savingsDepositAmountPerPeriod";
if (command.isChangeInBigDecimalParameterNamed(savingsDepositAmountPerPeriodParamName, savingsDeposit.getAmount())) {
final BigDecimal newValue = command.bigDecimalValueOfParameterNamed(savingsDepositAmountPerPeriodParamName);
actualChanges.put(savingsDepositAmountPerPeriodParamName, newValue);
actualChanges.put("locale", localeAsInput);
savingsDeposit = Money.of(savingsDeposit.getCurrency(), newValue);
}
Integer tenure = account.getTenure();
final String tenureParamName = "tenure";
if (command.isChangeInIntegerParameterNamed(tenureParamName, tenure)) {
final Integer newValue = command.integerValueOfParameterNamed(tenureParamName);
actualChanges.put(tenureParamName, newValue);
actualChanges.put("locale", localeAsInput);
tenure = newValue;
}
LocalDate commencementDate = new LocalDate(account.getProjectedCommencementDate());
final String commencementDateParamName = "commencementDate";
if (command.isChangeInLocalDateParameterNamed("commencementDate", commencementDate)) {
final LocalDate newValue = command.localDateValueOfParameterNamed(commencementDateParamName);
actualChanges.put(commencementDateParamName, newValue);
commencementDate = newValue;
}
TenureTypeEnum tenureTypeEnum = TenureTypeEnum.fromInt(account.getTenureType());
final String tenureTypeParamName = "tenureType";
if (command.isChangeInIntegerParameterNamed(tenureTypeParamName, tenureTypeEnum.getValue())) {
final Integer newValue = command.integerValueOfParameterNamed(tenureTypeParamName);
actualChanges.put(tenureTypeParamName, newValue);
actualChanges.put("locale", localeAsInput);
tenureTypeEnum = TenureTypeEnum.fromInt(newValue);
}
SavingProductType savingProductType = SavingProductType.fromInt(account.getSavingProductType());
SavingFrequencyType savingFrequencyType = SavingFrequencyType.fromInt(account.getFrequency());
final String frequencyParamName = "frequency";
if (command.isChangeInIntegerParameterNamed(frequencyParamName, savingFrequencyType.getValue())) {
final Integer newValue = command.integerValueOfParameterNamed(frequencyParamName);
actualChanges.put(frequencyParamName, newValue);
actualChanges.put("locale", localeAsInput);
savingFrequencyType = SavingFrequencyType.fromInt(newValue);
}
SavingInterestCalculationMethod savingInterestCalculationMethod = SavingInterestCalculationMethod.fromInt(account
.getInterestCalculationMethod());
final String interestCalculationMethodParamName = "interestCalculationMethod";
if (command.isChangeInIntegerParameterNamed(interestCalculationMethodParamName, savingInterestCalculationMethod.getValue())) {
final Integer newValue = command.integerValueOfParameterNamed(interestCalculationMethodParamName);
actualChanges.put(interestCalculationMethodParamName, newValue);
actualChanges.put("locale", localeAsInput);
savingInterestCalculationMethod = SavingInterestCalculationMethod.fromInt(newValue);
}
BigDecimal reccuringInterestRate = account.getReccuringInterestRate();
final String reccuringInterestRateParamName = "reccuringInterestRate";
if (command.isChangeInBigDecimalParameterNamed(reccuringInterestRateParamName, reccuringInterestRate)) {
final BigDecimal newValue = command.bigDecimalValueOfParameterNamed(reccuringInterestRateParamName);
actualChanges.put(reccuringInterestRateParamName, newValue);
actualChanges.put("locale", localeAsInput);
reccuringInterestRate = newValue;
}
BigDecimal savingInterestRate = account.getSavingInterestRate();
final String savingInterestRateParamName = "savingInterestRate";
if (command.isChangeInBigDecimalParameterNamed(savingInterestRateParamName, savingInterestRate)) {
final BigDecimal newValue = command.bigDecimalValueOfParameterNamed(savingInterestRateParamName);
actualChanges.put(savingInterestRateParamName, newValue);
actualChanges.put("locale", localeAsInput);
savingInterestRate = newValue;
}
Boolean isLockinPeriodAllowed = account.isLockinPeriodAllowed();
final String isLockinPeriodAllowedParamName = "isLockinPeriodAllowed";
if (command.isChangeInBooleanParameterNamed(isLockinPeriodAllowedParamName, isLockinPeriodAllowed)) {
final Boolean newValue = command.booleanObjectValueOfParameterNamed(isLockinPeriodAllowedParamName);
actualChanges.put(isLockinPeriodAllowedParamName, newValue);
actualChanges.put("locale", localeAsInput);
isLockinPeriodAllowed = newValue;
}
Integer lockinPeriod = account.getLockinPeriod();
final String lockinPeriodParamName = "lockinPeriod";
if (command.isChangeInIntegerParameterNamed(lockinPeriodParamName, lockinPeriod)) {
final Integer newValue = command.integerValueOfParameterNamed(lockinPeriodParamName);
actualChanges.put(lockinPeriodParamName, newValue);
actualChanges.put("locale", localeAsInput);
lockinPeriod = newValue;
}
PeriodFrequencyType lockinPeriodType = PeriodFrequencyType.fromInt(account.getLockinPeriodType());
final String lockinPeriodTypeParamName = "lockinPeriodType";
if (command.isChangeInIntegerParameterNamed(lockinPeriodTypeParamName, lockinPeriodType.getValue())) {
final Integer newValue = command.integerValueOfParameterNamed(lockinPeriodTypeParamName);
actualChanges.put(lockinPeriodTypeParamName, newValue);
actualChanges.put("locale", localeAsInput);
lockinPeriodType = PeriodFrequencyType.fromInt(newValue);
}
Integer payEvery = account.getPayEvery();
final String depositEveryParamName = "depositEvery";
if (command.isChangeInIntegerParameterNamed(depositEveryParamName, payEvery)) {
final Integer newValue = command.integerValueOfParameterNamed(depositEveryParamName);
actualChanges.put(depositEveryParamName, newValue);
actualChanges.put("locale", localeAsInput);
payEvery = newValue;
}
SavingsInterestType interestType = SavingsInterestType.fromInt(product.getSavingProductRelatedDetail().getInterestType());
final String interestTypeParamName = "interestType";
if (command.isChangeInIntegerParameterNamed(interestTypeParamName, interestType.getValue())) {
final Integer newValue = command.integerValueOfParameterNamed(interestTypeParamName);
actualChanges.put(interestTypeParamName, newValue);
actualChanges.put("locale", localeAsInput);
interestType = SavingsInterestType.fromInt(newValue);
}
Integer interestPostEvery = account.getInterestPostEvery();
final String interestPostEveryParamName = "interestPostEvery";
if (command.isChangeInIntegerParameterNamed(interestPostEveryParamName, interestPostEvery)) {
final Integer newValue = command.integerValueOfParameterNamed(interestPostEveryParamName);
actualChanges.put(interestPostEveryParamName, newValue);
actualChanges.put("locale", localeAsInput);
interestPostEvery = newValue;
}
Integer interestPostFrequency = account.getInterestPostFrequency();
final String interestPostFrequencyParamName = "interestPostFrequency";
if (command.isChangeInIntegerParameterNamed(interestPostFrequencyParamName, interestPostFrequency)) {
final Integer newValue = command.integerValueOfParameterNamed(interestPostFrequencyParamName);
actualChanges.put(interestPostFrequencyParamName, newValue);
actualChanges.put("locale", localeAsInput);
interestPostFrequency = PeriodFrequencyType.fromInt(newValue).getValue();
}
account.modifyAccount(product, externalId, savingsDeposit, reccuringInterestRate, savingInterestRate, tenure, commencementDate,
tenureTypeEnum, savingProductType, savingFrequencyType, savingInterestCalculationMethod, isLockinPeriodAllowed,
lockinPeriod, lockinPeriodType, this.reccuringDepositInterestCalculator, payEvery, interestType, interestPostEvery,
interestPostFrequency);
SavingScheduleData savingScheduleData = this.savingScheduleAssembler.fromJson(element);
for (SavingSchedulePeriodData savingSchedulePeriodData : savingScheduleData.getPeriods()) {
final SavingScheduleInstallments installment = new SavingScheduleInstallments(account, savingSchedulePeriodData.getDueDate()
.toDate(), savingSchedulePeriodData.getPeriod(), savingSchedulePeriodData.getDepositDue(),
savingSchedulePeriodData.getInterestAccured());
account.addSavingScheduleInstallment(installment);
}
return actualChanges;
}
private DepositLifecycleStateMachine defaultDepositLifecycleStateMachine() {
List<DepositAccountStatus> allowedDepositStatuses = Arrays.asList(DepositAccountStatus.values());
return new DepositLifecycleStateMachineImpl(allowedDepositStatuses);
}
public Map<String, Object> approveSavingAccount(final JsonCommand command, final SavingAccount account) {
JsonElement element = command.parsedJson();
Map<String, Object> actualChanges = new LinkedHashMap<String, Object>(20);
final String localeAsInput = command.locale();
LocalDate approvalDate = account.projectedCommencementDate();
final String commencementDateParamName = "commencementDate";
if (command.isChangeInLocalDateParameterNamed("commencementDate", approvalDate)) {
final LocalDate newValue = command.localDateValueOfParameterNamed(commencementDateParamName);
actualChanges.put(commencementDateParamName, newValue);
approvalDate = newValue;
}
BigDecimal savingsDepositAmountPerPeriod = account.getSavingsDepositAmountPerPeriod();
final String savingsDepositAmountPerPeriodParamName = "savingsDepositAmountPerPeriod";
if (command.isChangeInBigDecimalParameterNamed(savingsDepositAmountPerPeriodParamName, savingsDepositAmountPerPeriod)) {
final BigDecimal newValue = command.bigDecimalValueOfParameterNamed(savingsDepositAmountPerPeriodParamName);
actualChanges.put(savingsDepositAmountPerPeriodParamName, newValue);
actualChanges.put("locale", localeAsInput);
savingsDepositAmountPerPeriod = newValue;
}
BigDecimal recurringInterestRate = account.getReccuringInterestRate();
final String reccuringInterestRateParamName = "reccuringInterestRate";
if (command.isChangeInBigDecimalParameterNamed(reccuringInterestRateParamName, recurringInterestRate)) {
final BigDecimal newValue = command.bigDecimalValueOfParameterNamed(reccuringInterestRateParamName);
actualChanges.put(reccuringInterestRateParamName, newValue);
actualChanges.put("locale", localeAsInput);
recurringInterestRate = newValue;
}
BigDecimal savingInterestRate = account.getSavingInterestRate();
final String savingInterestRateParamName = "savingInterestRate";
if (command.isChangeInBigDecimalParameterNamed(savingInterestRateParamName, savingInterestRate)) {
final BigDecimal newValue = command.bigDecimalValueOfParameterNamed(savingInterestRateParamName);
actualChanges.put(savingInterestRateParamName, newValue);
actualChanges.put("locale", localeAsInput);
savingInterestRate = newValue;
}
Integer interestType = account.getInterestType();
final String interestTypeParamName = "interestType";
if (command.isChangeInIntegerParameterNamed(interestTypeParamName, interestType)) {
final Integer newValue = command.integerValueOfParameterNamed(interestTypeParamName);
actualChanges.put(interestTypeParamName, newValue);
actualChanges.put("locale", localeAsInput);
interestType = SavingsInterestType.fromInt(newValue).getValue();
}
Integer tenure = account.getTenure();
final String tenureParamName = "tenure";
if (command.isChangeInIntegerParameterNamed(tenureParamName, tenure)) {
final Integer newValue = command.integerValueOfParameterNamed(tenureParamName);
actualChanges.put(tenureParamName, newValue);
actualChanges.put("locale", localeAsInput);
tenure = newValue;
}
Integer tenureType = account.getTenureType();
final String tenureTypeParamName = "tenureType";
if (command.isChangeInIntegerParameterNamed(tenureTypeParamName, tenureType)) {
final Integer newValue = command.integerValueOfParameterNamed(tenureTypeParamName);
actualChanges.put(tenureTypeParamName, newValue);
actualChanges.put("locale", localeAsInput);
tenureType = TenureTypeEnum.fromInt(newValue).getValue();
}
Integer frequency = account.getFrequency();
final String frequencyParamName = "frequency";
if (command.isChangeInIntegerParameterNamed(frequencyParamName, frequency)) {
final Integer newValue = command.integerValueOfParameterNamed(frequencyParamName);
actualChanges.put(frequencyParamName, newValue);
actualChanges.put("locale", localeAsInput);
frequency = SavingFrequencyType.fromInt(newValue).getValue();
}
Integer depositEvery = account.getPayEvery();
final String depositEveryParamName = "depositEvery";
if (command.isChangeInIntegerParameterNamed(depositEveryParamName, depositEvery)) {
final Integer newValue = command.integerValueOfParameterNamed(depositEveryParamName);
actualChanges.put(depositEveryParamName, newValue);
actualChanges.put("locale", localeAsInput);
depositEvery = newValue;
}
Integer interestPostEvery = account.getInterestPostEvery();
final String interestPostEveryParamName = "interestPostEvery";
if (command.isChangeInIntegerParameterNamed(interestPostEveryParamName, interestPostEvery)) {
final Integer newValue = command.integerValueOfParameterNamed(interestPostEveryParamName);
actualChanges.put(interestPostEveryParamName, newValue);
actualChanges.put("locale", localeAsInput);
interestPostEvery = newValue;
}
Integer interestPostFrequency = account.getInterestPostFrequency();
final String interestPostFrequencyParamName = "interestPostFrequency";
if (command.isChangeInIntegerParameterNamed(interestPostFrequencyParamName, interestPostFrequency)) {
final Integer newValue = command.integerValueOfParameterNamed(interestPostFrequencyParamName);
actualChanges.put(interestPostFrequencyParamName, newValue);
actualChanges.put("locale", localeAsInput);
interestPostFrequency = PeriodFrequencyType.fromInt(newValue).getValue();
}
account.approveSavingAccount(approvalDate, savingsDepositAmountPerPeriod, recurringInterestRate, savingInterestRate, interestType,
tenure, tenureType, frequency, depositEvery, defaultDepositLifecycleStateMachine(),
this.reccuringDepositInterestCalculator, interestPostEvery, interestPostFrequency);
/*
* CalculateSavingScheduleCommand calculateSavingScheduleCommand = new
* CalculateSavingScheduleCommand(account.getProduct().getId(),
* savingsDepositAmountPerPeriod, payEvery, frequency,
* recurringInterestRate, approvalDate,
* tenure,tenureType,interestPostEvery
* ,interestPostFrequency,account.getInterestCalculationMethod());
*/
SavingScheduleData savingScheduleData = this.savingScheduleAssembler.calculateSavingSchedule(element, account);
for (SavingSchedulePeriodData savingSchedulePeriodData : savingScheduleData.getPeriods()) {
final SavingScheduleInstallments installment = new SavingScheduleInstallments(account, savingSchedulePeriodData.getDueDate()
.toDate(), savingSchedulePeriodData.getPeriod(), savingSchedulePeriodData.getDepositDue(),
savingSchedulePeriodData.getInterestAccured());
account.addSavingScheduleInstallment(installment);
}
return actualChanges;
}
public void withdrawSavingAccountMoney(final JsonCommand command, final SavingAccount account) {
LocalDate transactionDate = command.localDateValueOfParameterNamed("transactionDate");
BigDecimal withdraAmount = command.bigDecimalValueOfParameterNamed("amount");
if (withdraAmount.doubleValue() > account.getOutstandingAmount().doubleValue()) { throw new DepositAccountTransactionsException(
"deposit.transaction.interest.withdrawal.exceed", "You can Withdraw " + account.getOutstandingAmount() + " only"); }
account.withdrawAmount(withdraAmount, transactionDate);
}
public void postInterest(final SavingAccount account) {
account.postInterest();
}
private Boolean isBooleanValueUpdated(final Boolean actualValue) {
Boolean isUpdated = false;
if (actualValue != null) {
isUpdated = true;
}
return isUpdated;
}
}
@@ -1,35 +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.savingsaccount.service;
import java.math.BigDecimal;
import java.util.Collection;
import org.mifosplatform.organisation.monetary.data.CurrencyData;
import org.mifosplatform.portfolio.savingsaccount.data.SavingAccountData;
import org.mifosplatform.portfolio.savingsaccount.data.SavingAccountForLookup;
import org.mifosplatform.portfolio.savingsaccount.data.SavingAccountTransactionsData;
import org.mifosplatform.portfolio.savingsaccount.data.SavingPermissionData;
import org.mifosplatform.portfolio.savingsaccount.data.SavingScheduleData;
public interface SavingAccountReadPlatformService {
Collection<SavingAccountData> retrieveAllSavingsAccounts();
SavingAccountData retrieveSavingsAccount(Long accountId);
SavingAccountData retrieveNewSavingsAccountDetails(Long clientId, Long productId);
SavingPermissionData retrieveSavingAccountPermissions(SavingAccountData data);
BigDecimal deriveSavingDueAmount(SavingAccountData account);
SavingScheduleData retrieveSavingsAccountSchedule(Long accountId, CurrencyData currencyData);
Collection<SavingAccountForLookup> retrieveSavingAccountsForLookUp();
Collection<SavingAccountTransactionsData> retrieveSavingsAccountTransactions(Long accountId);
}
@@ -1,342 +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.savingsaccount.service;
import java.math.BigDecimal;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.util.Collection;
import java.util.List;
import org.joda.time.LocalDate;
import org.joda.time.Months;
import org.mifosplatform.infrastructure.core.data.EnumOptionData;
import org.mifosplatform.infrastructure.core.domain.JdbcSupport;
import org.mifosplatform.infrastructure.core.service.TenantAwareRoutingDataSource;
import org.mifosplatform.infrastructure.security.service.PlatformSecurityContext;
import org.mifosplatform.organisation.monetary.data.CurrencyData;
import org.mifosplatform.portfolio.client.data.ClientData;
import org.mifosplatform.portfolio.client.service.ClientReadPlatformService;
import org.mifosplatform.portfolio.savingsaccount.data.SavingAccountData;
import org.mifosplatform.portfolio.savingsaccount.data.SavingAccountForLookup;
import org.mifosplatform.portfolio.savingsaccount.data.SavingAccountTransactionsData;
import org.mifosplatform.portfolio.savingsaccount.data.SavingPermissionData;
import org.mifosplatform.portfolio.savingsaccount.data.SavingScheduleData;
import org.mifosplatform.portfolio.savingsaccount.data.SavingSchedulePeriodData;
import org.mifosplatform.portfolio.savingsaccountproduct.data.SavingProductData;
import org.mifosplatform.portfolio.savingsaccountproduct.data.SavingProductLookup;
import org.mifosplatform.portfolio.savingsaccountproduct.service.SavingProductEnumerations;
import org.mifosplatform.portfolio.savingsaccountproduct.service.SavingProductReadPlatformService;
import org.mifosplatform.portfolio.savingsdepositaccount.service.DepositAccountEnumerations;
import org.mifosplatform.portfolio.savingsdepositaccount.service.DepositAccountTransactionEnumerations;
import org.mifosplatform.portfolio.savingsdepositproduct.domain.TenureTypeEnum;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.jdbc.core.JdbcTemplate;
import org.springframework.jdbc.core.RowMapper;
import org.springframework.stereotype.Service;
@Service
public class SavingAccountReadPlatformServiceImpl implements SavingAccountReadPlatformService {
private final PlatformSecurityContext context;
private final JdbcTemplate jdbcTemplate;
private final ClientReadPlatformService clientReadPlatformService;
private final SavingProductReadPlatformService savingProductReadPlatformService;
@Autowired
public SavingAccountReadPlatformServiceImpl(final PlatformSecurityContext context, final TenantAwareRoutingDataSource dataSource,
final ClientReadPlatformService clientReadPlatformService,
final SavingProductReadPlatformService savingProductReadPlatformService) {
this.context = context;
this.jdbcTemplate = new JdbcTemplate(dataSource);
this.clientReadPlatformService = clientReadPlatformService;
this.savingProductReadPlatformService = savingProductReadPlatformService;
}
@Override
public Collection<SavingAccountData> retrieveAllSavingsAccounts() {
this.context.authenticatedUser();
SavingAccountMapper mapper = new SavingAccountMapper();
String sql = "select " + mapper.schema() + " where sa.is_deleted=0";
return this.jdbcTemplate.query(sql, mapper, new Object[] {});
}
@Override
public SavingAccountData retrieveSavingsAccount(final Long accountId) {
this.context.authenticatedUser();
SavingAccountMapper mapper = new SavingAccountMapper();
String sql = "select " + mapper.schema() + " where sa.id = ? and sa.is_deleted=0";
SavingAccountData savingAccountData = this.jdbcTemplate.queryForObject(sql, mapper, new Object[] { accountId });
return savingAccountData;
}
private static final class SavingAccountMapper implements RowMapper<SavingAccountData> {
public String schema() {
return "sa.id AS id, sa.status_enum AS status, sa.external_id AS externalId,"
+ " sa.client_id AS clientId, sa.product_id AS productId, sa.deposit_amount_per_period AS savingsDepostiAmountPerPeriod,"
+ " sa.savings_product_type AS savingsProductType, sa.currency_code AS currencyCode, sa.currency_digits AS currencyDigits,"
+ " sa.total_deposit_amount AS totalDepositAmount, sa.reccuring_nominal_interest_rate AS reccuringInterestRate,"
+ " sa.regular_saving_nominal_interest_rate AS savingInterestRate, sa.tenure AS tenure, sa.tenure_type AS tenureType,"
+ " sa.frequency AS savingsFrequencyType, sa.interest_type AS interestType, sa.interest_calculation_method AS interestCalculationMethod,"
+ " sa.projected_commencement_date AS projectedCommencementDate, sa.actual_commencement_date AS actualCommencementDate,"
+ " sa.matures_on_date AS maturesOnDate, sa.projected_interest_accrued_on_maturity AS projectedInterestAccuredOnMaturity,"
+ " sa.actual_interest_accrued AS actualInterestAccured, sa.projected_total_maturity_amount AS projectedTotalMaturityAmount,"
+ " sa.actual_total_amount AS actualTotalAmount, sa.is_preclosure_allowed AS isPreclosureAllowed, sa.outstanding_amount as outstandingAmount, "
+ " sa.pre_closure_interest_rate AS preClosureInterestRate, sa.is_lock_in_period_allowed AS isLockinPeriodAllowed,"
+ " sa.lock_in_period AS lockinPeriod, sa.lock_in_period_type AS lockinPeriodType, sa.withdrawnon_date AS withdrawnonDate,"
+ " sa.rejectedon_date AS rejectedonDate, sa.closedon_date AS closedonDate, ps.name AS productName, sa.deposit_every as depositEvery, "
+ " sa.interest_posting_every AS interestPostEvery, sa.interest_posting_frequency AS interestPostFrequency, "
+ " c.firstname AS firstname, c.lastname AS lastname, curr.name AS currencyName, "
+ " curr.internationalized_name_code AS currencyNameCode, curr.display_symbol AS currencyDisplaySymbol "
+ " FROM m_saving_account sa " + " JOIN m_client c ON c.id = sa.client_id"
+ " JOIN m_currency curr ON curr.code = sa.currency_code " + " JOIN m_product_savings ps ON sa.product_id = ps.id ";
}
@Override
public SavingAccountData mapRow(final ResultSet rs, @SuppressWarnings("unused") final int rowNum) throws SQLException {
Long id = rs.getLong("id");
String externalId = rs.getString("externalId");
Long clientId = rs.getLong("clientId");
String clientName = rs.getString("firstname") + " " + rs.getString("lastname");
Long productId = rs.getLong("productId");
String productName = rs.getString("productName");
EnumOptionData productType = SavingProductEnumerations.savingProductType(JdbcSupport.getInteger(rs, "savingsProductType"));
Integer statusId = JdbcSupport.getInteger(rs, "status");
EnumOptionData status = DepositAccountEnumerations.status(statusId);
String currencyCode = rs.getString("currencyCode");
String currencyName = rs.getString("currencyName");
String currencyNameCode = rs.getString("currencyNameCode");
String currencyDisplaySymbol = rs.getString("currencyDisplaySymbol");
Integer currencyDigits = JdbcSupport.getInteger(rs, "currencyDigits");
CurrencyData currencyData = new CurrencyData(currencyCode, currencyName, currencyDigits, currencyDisplaySymbol,
currencyNameCode);
BigDecimal savingsDepostiAmountPerPeriod = rs.getBigDecimal("savingsDepostiAmountPerPeriod");
EnumOptionData savingsFrequencyType = SavingProductEnumerations.interestFrequencyType(JdbcSupport.getInteger(rs,
"savingsFrequencyType"));
BigDecimal totalDepositAmount = rs.getBigDecimal("totalDepositAmount");
BigDecimal reccuringInterestRate = rs.getBigDecimal("reccuringInterestRate");
BigDecimal savingInterestRate = rs.getBigDecimal("savingInterestRate");
EnumOptionData interestType = SavingProductEnumerations.savingInterestType(JdbcSupport.getInteger(rs, "interestType"));
EnumOptionData interestCalculationMethod = SavingProductEnumerations.savingInterestCalculationMethod(JdbcSupport.getInteger(rs,
"interestCalculationMethod"));
Integer tenure = JdbcSupport.getInteger(rs, "tenure");
EnumOptionData tenureType = SavingProductEnumerations.tenureTypeEnum(JdbcSupport.getInteger(rs, "tenureType"));
LocalDate projectedCommencementDate = JdbcSupport.getLocalDate(rs, "projectedCommencementDate");
LocalDate actualCommencementDate = JdbcSupport.getLocalDate(rs, "actualCommencementDate");
LocalDate maturesOnDate = JdbcSupport.getLocalDate(rs, "maturesOnDate");
BigDecimal projectedInterestAccuredOnMaturity = rs.getBigDecimal("projectedInterestAccuredOnMaturity");
BigDecimal actualInterestAccured = rs.getBigDecimal("actualInterestAccured");
BigDecimal projectedMaturityAmount = rs.getBigDecimal("projectedTotalMaturityAmount");
BigDecimal actualMaturityAmount = rs.getBigDecimal("actualTotalAmount");
boolean preClosureAllowed = rs.getBoolean("isPreclosureAllowed");
BigDecimal preClosureInterestRate = rs.getBigDecimal("preClosureInterestRate");
BigDecimal outstandingAmount = rs.getBigDecimal("outstandingAmount");
LocalDate withdrawnonDate = JdbcSupport.getLocalDate(rs, "withdrawnonDate");
LocalDate rejectedonDate = JdbcSupport.getLocalDate(rs, "rejectedonDate");
LocalDate closedonDate = JdbcSupport.getLocalDate(rs, "closedonDate");
boolean isLockinPeriodAllowed = rs.getBoolean("isLockinPeriodAllowed");
Integer lockinPeriod = JdbcSupport.getInteger(rs, "lockinPeriod");
Integer lockinPeriodTypeValue = JdbcSupport.getInteger(rs, "lockinPeriodType");
EnumOptionData lockinPeriodType = SavingProductEnumerations.savingsLockinPeriod(lockinPeriodTypeValue);
Integer depositEvery = JdbcSupport.getInteger(rs, "depositEvery");
Integer interestPostEvery = JdbcSupport.getInteger(rs, "interestPostEvery");
EnumOptionData interestPostFrequency = SavingProductEnumerations.interestFrequencyType(JdbcSupport.getInteger(rs,
"interestPostFrequency"));
return new SavingAccountData(id, status, externalId, clientId, clientName, productId, productName, productType, currencyData,
savingsDepostiAmountPerPeriod, savingsFrequencyType, totalDepositAmount, reccuringInterestRate, savingInterestRate,
interestType, interestCalculationMethod, tenure, tenureType, projectedCommencementDate, actualCommencementDate,
maturesOnDate, projectedInterestAccuredOnMaturity, actualInterestAccured, projectedMaturityAmount,
actualMaturityAmount, preClosureAllowed, preClosureInterestRate, withdrawnonDate, rejectedonDate, closedonDate,
isLockinPeriodAllowed, lockinPeriod, lockinPeriodType, depositEvery, outstandingAmount, interestPostEvery,
interestPostFrequency);
}
}
@Override
public SavingAccountData retrieveNewSavingsAccountDetails(final Long clientId, final Long productId) {
context.authenticatedUser();
ClientData clientAccount = this.clientReadPlatformService.retrieveIndividualClient(clientId);
SavingAccountData accountData = null;
Collection<SavingProductLookup> savingProducts = this.savingProductReadPlatformService.retrieveAllSavingProductsForLookup();
if (productId != null && productId != -1) {
SavingProductData selectedProduct = findSavingProductById(savingProducts, productId);
CurrencyData currency = selectedProduct.getCurrency();
accountData = new SavingAccountData(clientAccount.id(), clientAccount.displayName(), selectedProduct.getId(),
selectedProduct.getName(), currency, selectedProduct.getInterestRate(), selectedProduct.getSavingsDepositAmount(),
selectedProduct.getSavingProductType(), selectedProduct.getTenureType(), selectedProduct.getTenure(),
selectedProduct.getSavingFrequencyType(), selectedProduct.getInterestType(),
selectedProduct.getInterestCalculationMethod(), selectedProduct.isLockinPeriodAllowed(),
selectedProduct.getLockinPeriod(), selectedProduct.getLockinPeriodType(), selectedProduct.getDepositEvery());
} else {
accountData = SavingAccountData.createFrom(clientAccount.id(), clientAccount.displayName());
}
return accountData;
}
private SavingProductData findSavingProductById(final Collection<SavingProductLookup> savingProducts, final Long productId) {
SavingProductData match = this.savingProductReadPlatformService.retrieveNewSavingProductDetails();
for (SavingProductLookup savingProductLookup : savingProducts) {
if (savingProductLookup.hasId(productId)) {
match = this.savingProductReadPlatformService.retrieveSavingProduct(savingProductLookup.getId());
break;
}
}
return match;
}
@Override
public SavingPermissionData retrieveSavingAccountPermissions(final SavingAccountData savingAccountData) {
boolean pendingApproval = (savingAccountData.getStatus().getId().equals(100L));
boolean undoApprovalAllowed = (savingAccountData.getStatus().getId().equals(300L));
boolean renewelAllowed = false;
if (savingAccountData.getMaturesOnDate() != null && savingAccountData.getTenureType().equals(TenureTypeEnum.FIXED_PERIOD)) {
if (new LocalDate().isAfter(savingAccountData.getMaturesOnDate())) {
renewelAllowed = true;
}
}
boolean rejectAllowed = pendingApproval;
boolean withdrawnByApplicantAllowed = pendingApproval;
boolean isMaturedDepositAccount = (savingAccountData.getStatus().getId().equals(700L));
return new SavingPermissionData(rejectAllowed, withdrawnByApplicantAllowed, undoApprovalAllowed, pendingApproval, renewelAllowed,
isMaturedDepositAccount);
}
@SuppressWarnings("unused")
@Override
public BigDecimal deriveSavingDueAmount(final SavingAccountData account) {
BigDecimal dueAmount = BigDecimal.ZERO;
EnumOptionData status = account.getStatus();
LocalDate date = account.getActualCommencementDate();
if (account.getStatus() != null && account.getActualCommencementDate() != null) {
BigDecimal amountPerPeriod = account.getSavingsDepostiAmountPerPeriod();
Integer tenure = account.getTenure();
Integer depositEvery = account.getDepositEvery();
Integer noOfPeriods = tenure / depositEvery;
Integer noOfMonths = Months.monthsBetween(date, new LocalDate()).getMonths();
Integer noOfPeriodsExistedTillDate = noOfMonths / depositEvery;
BigDecimal totalAmountToBePaidTillDate = BigDecimal.valueOf(noOfPeriodsExistedTillDate.doubleValue()
* amountPerPeriod.doubleValue());
dueAmount = dueAmount.add(BigDecimal.valueOf(totalAmountToBePaidTillDate.doubleValue()
- account.getOutstandingAmount().doubleValue()));
}
dueAmount = dueAmount.doubleValue() < 0 ? BigDecimal.ZERO : dueAmount;
return dueAmount;
}
@Override
public SavingScheduleData retrieveSavingsAccountSchedule(final Long accountId, final CurrencyData currency) {
this.context.authenticatedUser();
SavingAccountScheduleMapper mapper = new SavingAccountScheduleMapper();
String sql = "Select " + mapper.savingScheduleSchema() + " where ss.saving_account_id =? order by ss.installment";
List<SavingSchedulePeriodData> periods = this.jdbcTemplate.query(sql, mapper, new Object[] { accountId });
BigDecimal cumulativeDepositDue = BigDecimal.ZERO;
BigDecimal cumulativeDepositPaid = BigDecimal.ZERO;
BigDecimal cummulativeInterestAccured = BigDecimal.ZERO;
for (SavingSchedulePeriodData data : periods) {
cumulativeDepositDue = cumulativeDepositDue.add(data.getDepositDue());
cumulativeDepositPaid = cumulativeDepositPaid.add(data.getDepositPaid());
cummulativeInterestAccured = cummulativeInterestAccured.add(data.getInterestAccured());
}
SavingScheduleData scheduleData = new SavingScheduleData(currency, cumulativeDepositDue, cumulativeDepositPaid,
cummulativeInterestAccured, periods);
return scheduleData;
}
public static final class SavingAccountScheduleMapper implements RowMapper<SavingSchedulePeriodData> {
public String savingScheduleSchema() {
return "ss.id as id, ss.saving_account_id as savingAccountId, ss.duedate as dueDate, ss.installment as installment, "
+ " ss.deposit as deposit, ss.payment_date as paymentDate, ss.deposit_paid as depositPaid, "
+ " ss.completed_derived as completedDerived, ss.interest_accured AS interestAccured FROM m_saving_schedule ss";
}
@Override
public SavingSchedulePeriodData mapRow(final ResultSet rs, @SuppressWarnings("unused") final int rowNum) throws SQLException {
LocalDate dueDate = JdbcSupport.getLocalDate(rs, "dueDate");
Integer installment = JdbcSupport.getInteger(rs, "installment");
BigDecimal depositDue = rs.getBigDecimal("deposit");
BigDecimal depositPaid = rs.getBigDecimal("depositPaid");
BigDecimal interestAccured = rs.getBigDecimal("interestAccured");
return new SavingSchedulePeriodData(installment, dueDate, depositDue, depositPaid, interestAccured);
}
}
@Override
public Collection<SavingAccountForLookup> retrieveSavingAccountsForLookUp() {
SavingAccountLookupMapper mapper = new SavingAccountLookupMapper();
String sql = "select " + mapper.schema();
return this.jdbcTemplate.query(sql, mapper, new Object[] {});
}
private static final class SavingAccountLookupMapper implements RowMapper<SavingAccountForLookup> {
public String schema() {
return " sa.id as id from m_saving_account sa where sa.is_deleted=0 and sa.status_enum=300";
}
@Override
public SavingAccountForLookup mapRow(final ResultSet rs, @SuppressWarnings("unused") final int rowNum) throws SQLException {
Long id = rs.getLong("id");
return new SavingAccountForLookup(id);
}
}
@Override
public Collection<SavingAccountTransactionsData> retrieveSavingsAccountTransactions(final Long accountId) {
this.context.authenticatedUser();
SavingAccountTransactionMapper savingAccountTransactionMapper = new SavingAccountTransactionMapper();
String sql = "select " + savingAccountTransactionMapper.schema() + " where stxn.saving_account_id = ? ";
return jdbcTemplate.query(sql, savingAccountTransactionMapper, new Object[] { accountId });
}
private static final class SavingAccountTransactionMapper implements RowMapper<SavingAccountTransactionsData> {
public String schema() {
return "stxn.id as id, stxn.transaction_type_enum as type, stxn.transaction_date as transactionDate, stxn.amount as amount FROM m_saving_account_transaction stxn";
}
@Override
public SavingAccountTransactionsData mapRow(final ResultSet rs, @SuppressWarnings("unused") final int rowNum) throws SQLException {
Long id = rs.getLong("id");
LocalDate transactionDate = JdbcSupport.getLocalDate(rs, "transactionDate");
Integer transactionTypeValue = JdbcSupport.getInteger(rs, "type");
EnumOptionData transactionType = DepositAccountTransactionEnumerations.depositType(transactionTypeValue);
BigDecimal amount = rs.getBigDecimal("amount");
return new SavingAccountTransactionsData(id, transactionDate, transactionType, amount);
}
}
}
@@ -1,36 +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.savingsaccount.service;
import java.util.Collection;
import org.mifosplatform.infrastructure.core.api.JsonCommand;
import org.mifosplatform.infrastructure.core.data.CommandProcessingResult;
import org.mifosplatform.portfolio.savingsaccount.data.SavingAccountForLookup;
public interface SavingAccountWritePlatformService {
CommandProcessingResult createSavingAccount(JsonCommand command);
CommandProcessingResult updateSavingAccount(Long accountId, JsonCommand command);
CommandProcessingResult rejectSavingApplication(JsonCommand command);
CommandProcessingResult withdrawSavingApplication(JsonCommand command);
CommandProcessingResult undoSavingAccountApproval(JsonCommand undoCommand);
CommandProcessingResult approveSavingAccount(JsonCommand command);
CommandProcessingResult depositMoney(JsonCommand command);
CommandProcessingResult withdrawSavingAmount(JsonCommand command);
CommandProcessingResult deleteSavingAccount(Long accountId);
CommandProcessingResult postInterest(Collection<SavingAccountForLookup> savingAccounts);
}
@@ -1,327 +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.savingsaccount.service;
import java.util.Arrays;
import java.util.Collection;
import java.util.LinkedHashMap;
import java.util.List;
import java.util.Map;
import org.apache.commons.lang.StringUtils;
import org.joda.time.LocalDate;
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.security.service.PlatformSecurityContext;
import org.mifosplatform.portfolio.note.domain.Note;
import org.mifosplatform.portfolio.note.domain.NoteRepository;
import org.mifosplatform.portfolio.savingsaccount.data.SavingAccountForLookup;
import org.mifosplatform.portfolio.savingsaccount.domain.SavingAccount;
import org.mifosplatform.portfolio.savingsaccount.domain.SavingAccountRepository;
import org.mifosplatform.portfolio.savingsaccount.exception.SavingAccountNotFoundException;
import org.mifosplatform.portfolio.savingsaccount.serialization.SavingAccountCommandFromApiJsonDeserializer;
import org.mifosplatform.portfolio.savingsaccount.serialization.SavingAccountStateTransitionCommandFromApiJsonDeserializer;
import org.mifosplatform.portfolio.savingsdepositaccount.domain.DepositAccountStatus;
import org.mifosplatform.portfolio.savingsdepositaccount.domain.DepositLifecycleStateMachine;
import org.mifosplatform.portfolio.savingsdepositaccount.domain.DepositLifecycleStateMachineImpl;
import org.mifosplatform.portfolio.savingsdepositaccount.exception.InvalidSavingStateTransitionException;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.dao.DataIntegrityViolationException;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
@Service
public class SavingAccountWritePlatformServiceJpaRepositoryImpl implements SavingAccountWritePlatformService {
private final static Logger logger = LoggerFactory.getLogger(SavingAccountWritePlatformServiceJpaRepositoryImpl.class);
private final PlatformSecurityContext context;
private final SavingAccountRepository savingAccountRepository;
private final SavingAccountAssembler savingAccountAssembler;
private final NoteRepository noteRepository;
private final SavingAccountCommandFromApiJsonDeserializer fromApiJsonDeserializer;
private final SavingAccountStateTransitionCommandFromApiJsonDeserializer savingAccountStateTransitionCommandFromApiJsonDeserializer;
@Autowired
public SavingAccountWritePlatformServiceJpaRepositoryImpl(final PlatformSecurityContext context,
final SavingAccountRepository savingAccountRepository, final SavingAccountAssembler savingAccountAssembler,
final NoteRepository noteRepository,
final SavingAccountCommandFromApiJsonDeserializer fromApiJsonDeserializer,
final SavingAccountStateTransitionCommandFromApiJsonDeserializer savingAccountStateTransitionCommandFromApiJsonDeserializer) {
this.context = context;
this.savingAccountRepository = savingAccountRepository;
this.savingAccountAssembler = savingAccountAssembler;
this.noteRepository = noteRepository;
this.fromApiJsonDeserializer = fromApiJsonDeserializer;
this.savingAccountStateTransitionCommandFromApiJsonDeserializer = savingAccountStateTransitionCommandFromApiJsonDeserializer;
}
@Transactional
@Override
public CommandProcessingResult createSavingAccount(final JsonCommand command) {
try {
this.context.authenticatedUser();
this.fromApiJsonDeserializer.validateForCreate(command.json());
SavingAccount account = this.savingAccountAssembler.assembleFrom(command);
this.savingAccountRepository.save(account);
return new CommandProcessingResultBuilder() //
.withEntityId(account.getId()) //
.build();
} catch (DataIntegrityViolationException dve) {
handleDataIntegrityIssues(command, dve);
return new CommandProcessingResult(Long.valueOf(-1));
}
}
@Override
public CommandProcessingResult updateSavingAccount(final Long accountId, final JsonCommand command) {
try {
this.context.authenticatedUser();
this.fromApiJsonDeserializer.validateForUpdate(command.json());
Map<String, Object> changes = new LinkedHashMap<String, Object>(20);;
SavingAccount account = this.savingAccountRepository.findOne(accountId);
if (account == null || account.isDeleted()) { throw new SavingAccountNotFoundException(accountId); }
if (account.isPendingApproval()) {
changes = this.savingAccountAssembler.assembleFrom(command, account);
this.savingAccountRepository.save(account);
}
return new CommandProcessingResultBuilder() //
.withEntityId(account.getId()) //
.with(changes)
.build();
} catch (DataIntegrityViolationException dve) {
handleDataIntegrityIssues(command, dve);
return new CommandProcessingResult(Long.valueOf(-1));
}
}
/*
* Guaranteed to throw an exception no matter what the data integrity issue
* is.
*/
private void handleDataIntegrityIssues(final JsonCommand command, final DataIntegrityViolationException dve) {
Throwable realCause = dve.getMostSpecificCause();
if (realCause.getMessage().contains("saving_acc_external_id")) {
final String externalId = command.stringValueOfParameterNamed("externalId");
throw new PlatformDataIntegrityException(
"error.msg.saving.account.duplicate.externalId", "Saving account with externalId " + externalId
+ " already exists", "externalId", externalId); }
logger.error(dve.getMessage(), dve);
throw new PlatformDataIntegrityException("error.msg.saving.account.unknown.data.integrity.issue",
"Unknown data integrity issue with resource.");
}
@Override
public CommandProcessingResult rejectSavingApplication(JsonCommand command) {
this.context.authenticatedUser();
this.savingAccountStateTransitionCommandFromApiJsonDeserializer.validateForReject(command.json());
SavingAccount account = this.savingAccountRepository.findOne(command.entityId());
if (account == null || account.isDeleted()) {
throw new SavingAccountNotFoundException(command.entityId());
}
LocalDate eventDate = command.localDateValueOfParameterNamed("eventDate");
if (this.isBeforeToday(eventDate)) {
final String errorMessage = "User has no authority to reject saving with a date in the past. ";
throw new InvalidSavingStateTransitionException("reject", "cannot.be.before.submittal.date", errorMessage, account.projectedCommencementDate(), eventDate);
}
account.reject(eventDate, defaultDepositLifecycleStateMachine());
this.savingAccountRepository.save(account);
String noteText = command.stringValueOfParameterNamed("note");
if (StringUtils.isNotBlank(noteText)) {
Note note = Note.savingNote(account, noteText);
this.noteRepository.save(note);
}
return new CommandProcessingResultBuilder() //
.withEntityId(account.getId()) //
.build();
}
private DepositLifecycleStateMachine defaultDepositLifecycleStateMachine() {
List<DepositAccountStatus> allowedDepositStatuses = Arrays.asList(DepositAccountStatus.values());
return new DepositLifecycleStateMachineImpl(allowedDepositStatuses);
}
@Override
public CommandProcessingResult withdrawSavingApplication(JsonCommand command) {
this.context.authenticatedUser();
this.savingAccountStateTransitionCommandFromApiJsonDeserializer.validateForWithdrawApplication(command.json());
SavingAccount account = this.savingAccountRepository.findOne(command.entityId());
if (account == null || account.isDeleted()) {
throw new SavingAccountNotFoundException(command.entityId());
}
LocalDate eventDate = command.localDateValueOfParameterNamed("eventDate");
if (this.isBeforeToday(eventDate)) {
final String errorMessage = "User has no authority to withdraw saving with a date in the past. ";
throw new InvalidSavingStateTransitionException("reject", "cannot.be.before.submittal.date", errorMessage, account.projectedCommencementDate(), eventDate);
}
account.withdrawnByApplicant(eventDate, defaultDepositLifecycleStateMachine());
this.savingAccountRepository.save(account);
String noteText = command.stringValueOfParameterNamed("note");
if (StringUtils.isNotBlank(noteText)) {
Note note = Note.savingNote(account, noteText);
this.noteRepository.save(note);
}
return new CommandProcessingResultBuilder() //
.withEntityId(account.getId()) //
.build();
}
@Override
public CommandProcessingResult undoSavingAccountApproval(JsonCommand command) {
this.context.authenticatedUser();
SavingAccount account = this.savingAccountRepository.findOne(command.entityId());
if (account == null || account.isDeleted()) {
throw new SavingAccountNotFoundException(command.getLoanId());
}
account.undoSavingAccountApproval(defaultDepositLifecycleStateMachine());
this.savingAccountRepository.save(account);
String noteText = command.stringValueOfParameterNamed("note");
if (StringUtils.isNotBlank(noteText)) {
Note note = Note.savingNote(account, noteText);
this.noteRepository.save(note);
}
return new CommandProcessingResultBuilder() //
.withEntityId(account.getId()) //
.build();
}
@Override
public CommandProcessingResult approveSavingAccount(JsonCommand command) {
this.context.authenticatedUser();
this.savingAccountStateTransitionCommandFromApiJsonDeserializer.validateForApprove(command.json());
SavingAccount account = this.savingAccountRepository.findOne(command.entityId());
if (account == null || account.isDeleted()) {
throw new SavingAccountNotFoundException(command.entityId());
}
LocalDate approvalDate = command.localDateValueOfParameterNamed("commencementDate");
if (approvalDate.isBefore(account.projectedCommencementDate())) {
final String errorMessage = "The date on which a saving is approved cannot be before its submittal date: "
+ approvalDate.toString();
throw new InvalidSavingStateTransitionException("approval", "cannot.be.before.submittal.date", errorMessage,
account.projectedCommencementDate(), approvalDate);
}
Map<String, Object> changes = this.savingAccountAssembler.approveSavingAccount(command,account);
this.savingAccountRepository.save(account);
String noteText = command.stringValueOfParameterNamed("note");
if (StringUtils.isNotBlank(noteText)) {
Note note = Note.savingNote(account, noteText);
this.noteRepository.save(note);
}
return new CommandProcessingResultBuilder() //
.withEntityId(account.getId()) //
.with(changes)
.build();
}
@Override
public CommandProcessingResult depositMoney(JsonCommand command) {
this.context.authenticatedUser();
this.savingAccountStateTransitionCommandFromApiJsonDeserializer.validateForDepositAmount(command.json());
SavingAccount account = this.savingAccountRepository.findOne(command.entityId());
if (account == null || account.isDeleted()) {
throw new SavingAccountNotFoundException(command.entityId());
}
if (account.isActive())
account.depositMoney(command);
this.savingAccountRepository.save(account);
String noteText = command.stringValueOfParameterNamed("note");
if (StringUtils.isNotBlank(noteText)) {
Note note = Note.savingNote(account, noteText);
this.noteRepository.save(note);
}
return new CommandProcessingResultBuilder() //
.withEntityId(account.getId()) //
.build();
}
@Override
public CommandProcessingResult withdrawSavingAmount(JsonCommand command) {
this.context.authenticatedUser();
SavingAccount account = this.savingAccountRepository.findOne(command.entityId());
if (account == null || account.isDeleted()) {
throw new SavingAccountNotFoundException(command.entityId());
}
if (account.isActive())
this.savingAccountAssembler.withdrawSavingAccountMoney(command,account);
this.savingAccountRepository.save(account);
String noteText = command.stringValueOfParameterNamed("note");
if (StringUtils.isNotBlank(noteText)) {
Note note = Note.savingNote(account, noteText);
this.noteRepository.save(note);
}
return new CommandProcessingResultBuilder() //
.withEntityId(account.getId()) //
.build();
}
@Override
public CommandProcessingResult deleteSavingAccount(Long accountId) {
this.context.authenticatedUser();
SavingAccount account = this.savingAccountRepository.findOne(accountId);
if (account == null || account.isDeleted()) {
throw new SavingAccountNotFoundException(accountId);
}
account.delete();
this.savingAccountRepository.save(account);
return new CommandProcessingResultBuilder() //
.withEntityId(account.getId()) //
.build();
}
@Override
public CommandProcessingResult postInterest(Collection<SavingAccountForLookup> savingAccounts) {
this.context.authenticatedUser();
try {
for(SavingAccountForLookup accountForLookup : savingAccounts ){
SavingAccount account = this.savingAccountRepository.findOne(accountForLookup.getId());
if (account == null || account.isDeleted()) { throw new SavingAccountNotFoundException(accountForLookup.getId()); }
this.savingAccountAssembler.postInterest(account);
this.savingAccountRepository.save(account);
}
return new CommandProcessingResultBuilder() //
.withEntityId(Long.valueOf(savingAccounts.size())) //
.build();
} catch (Exception e) {
return new CommandProcessingResult(Long.valueOf(-1));
}
}
private boolean isBeforeToday(final LocalDate date) {
return date.isBefore(new LocalDate());
}
}
@@ -1,139 +0,0 @@
package org.mifosplatform.portfolio.savingsaccount.service;
import java.math.BigDecimal;
import java.util.ArrayList;
import java.util.Collection;
import org.joda.time.LocalDate;
import org.mifosplatform.infrastructure.core.serialization.FromJsonHelper;
import org.mifosplatform.organisation.monetary.data.CurrencyData;
import org.mifosplatform.organisation.monetary.domain.ApplicationCurrency;
import org.mifosplatform.organisation.monetary.domain.ApplicationCurrencyRepository;
import org.mifosplatform.portfolio.savingsaccount.data.SavingScheduleData;
import org.mifosplatform.portfolio.savingsaccount.data.SavingSchedulePeriodData;
import org.mifosplatform.portfolio.savingsaccount.domain.SavingAccount;
import org.mifosplatform.portfolio.savingsaccountproduct.domain.SavingFrequencyType;
import org.mifosplatform.portfolio.savingsaccountproduct.domain.SavingInterestCalculationMethod;
import org.mifosplatform.portfolio.savingsaccountproduct.domain.SavingProduct;
import org.mifosplatform.portfolio.savingsaccountproduct.domain.SavingProductRepository;
import org.mifosplatform.portfolio.savingsaccountproduct.domain.SavingProductType;
import org.mifosplatform.portfolio.savingsaccountproduct.exception.SavingProductNotFoundException;
import org.mifosplatform.portfolio.savingsdepositproduct.domain.TenureTypeEnum;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import com.google.gson.JsonElement;
@Service
public class SavingScheduleAssembler {
private final FromJsonHelper fromApiJsonHelper;
private final SavingProductRepository savingProductRepository;
private final SavingScheduleGenerator savingScheduleGenerator;
private final ApplicationCurrencyRepository applicationCurrencyRepository;
@Autowired
public SavingScheduleAssembler( final FromJsonHelper fromApiJsonHelper,
final SavingProductRepository savingProductRepository,
final ApplicationCurrencyRepository applicationCurrencyRepository) {
this.fromApiJsonHelper = fromApiJsonHelper;
this.savingProductRepository = savingProductRepository;
this.savingScheduleGenerator = new SavingScheduleGenerator();
this.applicationCurrencyRepository = applicationCurrencyRepository;
}
public SavingScheduleData fromJson(JsonElement element) {
SavingScheduleData savingScheduleData = null;
final Long productId = fromApiJsonHelper.extractLongNamed("productId", element);
final Integer depositEvery = fromApiJsonHelper.extractIntegerWithLocaleNamed("depositEvery", element);
final LocalDate scheduleStartDate = fromApiJsonHelper.extractLocalDateNamed("commencementDate", element);
final BigDecimal interestRate = this.fromApiJsonHelper.extractBigDecimalWithLocaleNamed("recurringInterestRate", element);
final BigDecimal depositAmountPerPeriod = this.fromApiJsonHelper.extractBigDecimalWithLocaleNamed("savingsDepositAmountPerPeriod", element);
final Integer tenure = this.fromApiJsonHelper.extractIntegerWithLocaleNamed("tenure", element);
final Integer tenureTypeCommandValue = this.fromApiJsonHelper.extractIntegerWithLocaleNamed("tenureType", element);
TenureTypeEnum tenureType = TenureTypeEnum.fromInt(tenureTypeCommandValue);
final Integer frequencyCommandValue = this.fromApiJsonHelper.extractIntegerWithLocaleNamed("frequency", element);
SavingFrequencyType savingFrequencyType = SavingFrequencyType.fromInt(frequencyCommandValue);
//final Integer interestTypeCommandValue = this.fromApiJsonHelper.extractIntegerWithLocaleNamed("interestType", element);
//SavingsInterestType interestType = SavingsInterestType.fromInt(interestTypeCommandValue);
final Integer interestCalculationMethodCommandValue = this.fromApiJsonHelper.extractIntegerWithLocaleNamed("interestCalculationMethod", element);
SavingInterestCalculationMethod interestCalculationMethod = SavingInterestCalculationMethod.fromInt(interestCalculationMethodCommandValue);
final SavingProduct savingProduct = this.savingProductRepository.findOne(productId);
if (savingProduct == null) throw new SavingProductNotFoundException(productId);
final ApplicationCurrency applicationCurrency = this.applicationCurrencyRepository.findOneByCode(savingProduct.getCurrency().getCode());
SavingProductType savingProductType = SavingProductType.fromInt(savingProduct.getSavingProductRelatedDetail().getSavingProductType());
if (savingProductType.isReccuring() && tenureType.isFixedPeriod()) {
savingScheduleData = savingScheduleGenerator.generate(scheduleStartDate, depositAmountPerPeriod,
depositEvery, savingFrequencyType, savingProduct, tenure, applicationCurrency,interestRate,interestCalculationMethod);
} else {
final Collection<SavingSchedulePeriodData> periods = new ArrayList<SavingSchedulePeriodData>();
CurrencyData currencyData = new CurrencyData(applicationCurrency.getCode(), applicationCurrency.getName(),
savingProduct.getCurrency().getDigitsAfterDecimal(), applicationCurrency.getDisplaySymbol(), applicationCurrency.getNameCode());
SavingSchedulePeriodData installment = SavingSchedulePeriodData.addScheduleInformation(1, new LocalDate(scheduleStartDate).plusMonths(depositEvery), depositAmountPerPeriod, BigDecimal.ZERO);
periods.add(installment);
savingScheduleData = new SavingScheduleData(currencyData, depositAmountPerPeriod, BigDecimal.ZERO, BigDecimal.ZERO, periods);
}
return savingScheduleData;
}
public SavingScheduleData calculateSavingSchedule(JsonElement element, SavingAccount account) {
SavingScheduleData savingScheduleData = null;
SavingProduct savingProduct = account.getProduct();
SavingProductType savingProductType = SavingProductType.fromInt(account.getSavingProductType());
SavingInterestCalculationMethod interestCalculationMethod = SavingInterestCalculationMethod.fromInt(account.getInterestCalculationMethod());
TenureTypeEnum tenureType = TenureTypeEnum.fromInt(account.getTenureType());
final Integer tenureTypeCommandValue = this.fromApiJsonHelper.extractIntegerWithLocaleNamed("tenureType", element);
if (tenureTypeCommandValue != null) tenureType = TenureTypeEnum.fromInt(tenureTypeCommandValue);
LocalDate scheduleStartDate = new LocalDate(account.getProjectedCommencementDate());
final LocalDate commencementDate = fromApiJsonHelper.extractLocalDateNamed("commencementDate", element);
if (commencementDate != null) scheduleStartDate = commencementDate ;
BigDecimal depositAmountPerPeriod = account.getSavingsDepositAmountPerPeriod();
final BigDecimal savingsDepositAmountPerPeriod = this.fromApiJsonHelper.extractBigDecimalWithLocaleNamed("savingsDepositAmountPerPeriod", element);
if (savingsDepositAmountPerPeriod != null ) depositAmountPerPeriod = savingsDepositAmountPerPeriod;
Integer depositEvery = account.getPayEvery();
final Integer depositEveryCommandValue = fromApiJsonHelper.extractIntegerWithLocaleNamed("depositEvery", element);
if (depositEveryCommandValue != null ) depositEvery = depositEveryCommandValue;
SavingFrequencyType savingFrequencyType = SavingFrequencyType.fromInt(account.getFrequency());
final Integer frequencyCommandValue = this.fromApiJsonHelper.extractIntegerWithLocaleNamed("frequency", element);
if (frequencyCommandValue != null ) savingFrequencyType = SavingFrequencyType.fromInt(frequencyCommandValue);
Integer tenure = account.getTenure();
final Integer tenureCommandValue = this.fromApiJsonHelper.extractIntegerWithLocaleNamed("tenure", element);
if (tenureCommandValue != null ) tenure = tenureCommandValue;
BigDecimal interestRate = account.getReccuringInterestRate();
final BigDecimal recurringInterestRate = this.fromApiJsonHelper.extractBigDecimalWithLocaleNamed("recurringInterestRate", element);
if (recurringInterestRate != null ) interestRate = recurringInterestRate;
final ApplicationCurrency applicationCurrency = this.applicationCurrencyRepository.findOneByCode(savingProduct.getCurrency().getCode());
if (savingProductType.isReccuring() && tenureType.isFixedPeriod()) {
savingScheduleData = savingScheduleGenerator.generate(scheduleStartDate, depositAmountPerPeriod,
depositEvery, savingFrequencyType, savingProduct, tenure, applicationCurrency,interestRate,interestCalculationMethod);
} else {
final Collection<SavingSchedulePeriodData> periods = new ArrayList<SavingSchedulePeriodData>();
CurrencyData currencyData = new CurrencyData(applicationCurrency.getCode(), applicationCurrency.getName(),
savingProduct.getCurrency().getDigitsAfterDecimal(), applicationCurrency.getDisplaySymbol(), applicationCurrency.getNameCode());
SavingSchedulePeriodData installment = SavingSchedulePeriodData.addScheduleInformation(1, new LocalDate(scheduleStartDate).plusMonths(depositEvery), depositAmountPerPeriod, BigDecimal.ZERO);
periods.add(installment);
savingScheduleData = new SavingScheduleData(currencyData, depositAmountPerPeriod, BigDecimal.ZERO, BigDecimal.ZERO, periods);
}
return savingScheduleData;
}
}
@@ -1,130 +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.savingsaccount.service;
import java.math.BigDecimal;
import java.math.MathContext;
import java.math.RoundingMode;
import java.util.ArrayList;
import java.util.Collection;
import java.util.List;
import org.joda.time.LocalDate;
import org.mifosplatform.organisation.monetary.data.CurrencyData;
import org.mifosplatform.organisation.monetary.domain.ApplicationCurrency;
import org.mifosplatform.organisation.monetary.domain.MonetaryCurrency;
import org.mifosplatform.organisation.monetary.domain.Money;
import org.mifosplatform.portfolio.savingsaccount.data.SavingScheduleData;
import org.mifosplatform.portfolio.savingsaccount.data.SavingSchedulePeriodData;
import org.mifosplatform.portfolio.savingsaccount.domain.DepositScheduleDateGenerator;
import org.mifosplatform.portfolio.savingsaccountproduct.domain.SavingFrequencyType;
import org.mifosplatform.portfolio.savingsaccountproduct.domain.SavingInterestCalculationMethod;
import org.mifosplatform.portfolio.savingsaccountproduct.domain.SavingProduct;
public class SavingScheduleGenerator {
private final DepositScheduleDateGenerator scheduledDateGenerator = new DefaultDepositScheduleDateGenerator();
private final Integer monthsInYear = 12;
public SavingScheduleData generate(final LocalDate scheduleStartDate, final BigDecimal depositAmountPerPeriod,
final Integer depositFrequency, final SavingFrequencyType savingFrequencyType, final SavingProduct savingProduct,
final Integer tenure, final ApplicationCurrency applicationCurrency, final BigDecimal interestRate, final SavingInterestCalculationMethod interestCalculationMethod) {
LocalDate startDate = scheduleStartDate;
int periodNumber = 1;
Integer paymentPeriods = tenure / depositFrequency;
final Collection<SavingSchedulePeriodData> periods = new ArrayList<SavingSchedulePeriodData>();
final List<LocalDate> scheduledDates = this.scheduledDateGenerator.generate(startDate, paymentPeriods, depositFrequency,
savingFrequencyType);
final MonetaryCurrency currency = savingProduct.getCurrency();
final Money depositAmount = Money.of(currency, depositAmountPerPeriod);
Money totalDeposit = Money.zero(currency);
MathContext mc = new MathContext(8, RoundingMode.HALF_EVEN);
BigDecimal interestRateAsFraction = interestRate.divide(BigDecimal.valueOf(100), mc);
Integer noofTimesInterestCompoundPerYear = determineIntValue(savingFrequencyType);
BigDecimal interestRatePerPeriod = BigDecimal.valueOf(interestRateAsFraction.doubleValue()/ noofTimesInterestCompoundPerYear.doubleValue());
BigDecimal onePlusInterestRatePerPeriod = BigDecimal.ONE.add(interestRatePerPeriod);
BigDecimal cummulativeDepositPaid = BigDecimal.ZERO;
BigDecimal cummulativeInterestAccured = BigDecimal.ZERO;
Integer tempTenure = tenure;
BigDecimal termAmount = BigDecimal.ZERO;
BigDecimal totalInterest = BigDecimal.ZERO;
BigDecimal closingBalance = BigDecimal.ZERO;
for (LocalDate scheduleDate : scheduledDates) {
if (interestCalculationMethod.isMonthlyCollection()) {
BigDecimal monthsExpressedInYears = BigDecimal.valueOf(tempTenure.doubleValue() / monthsInYear.doubleValue());
BigDecimal timeforOneCalculationPeriod = BigDecimal.valueOf(noofTimesInterestCompoundPerYear * monthsExpressedInYears.doubleValue());
BigDecimal amountPerPeriod = depositAmountPerPeriod.multiply(BigDecimal.valueOf(Math.pow(onePlusInterestRatePerPeriod.doubleValue(), timeforOneCalculationPeriod.doubleValue())));
BigDecimal interestAccured = amountPerPeriod.subtract(depositAmountPerPeriod);
totalDeposit = totalDeposit.plus(depositAmount);
cummulativeInterestAccured = cummulativeInterestAccured.add(interestAccured);
SavingSchedulePeriodData installment = SavingSchedulePeriodData.addScheduleInformation(periodNumber, scheduleDate,
depositAmount.getAmount(), interestAccured);
periods.add(installment);
periodNumber++;
tempTenure = tempTenure - depositFrequency;
} else if (interestCalculationMethod.isAverageBalance()){
BigDecimal amountPerPeriod = depositAmount.getAmount();
Integer depositEveryOriginalValue = depositFrequency;
BigDecimal amountPermonth = BigDecimal.valueOf(amountPerPeriod.doubleValue()/depositFrequency.doubleValue());
while (depositEveryOriginalValue > 0) {
closingBalance = closingBalance.add(amountPermonth);
termAmount = termAmount.add(closingBalance);
depositEveryOriginalValue--;
}
BigDecimal averageAmount = BigDecimal.valueOf(termAmount.doubleValue()/depositFrequency.doubleValue());
BigDecimal interestRatePerTerm = BigDecimal.valueOf(interestRateAsFraction.doubleValue()/monthsInYear.doubleValue()*depositFrequency.doubleValue());
BigDecimal interestAccured = averageAmount.multiply(interestRatePerTerm);
totalInterest = totalInterest.add(interestAccured);
depositEveryOriginalValue = depositFrequency;
termAmount = BigDecimal.ZERO;
totalDeposit = totalDeposit.plus(depositAmount);
cummulativeInterestAccured = totalInterest;
SavingSchedulePeriodData installment = SavingSchedulePeriodData.addScheduleInformation(periodNumber, scheduleDate,
depositAmount.getAmount(), interestAccured);
periods.add(installment);
periodNumber++;
}
}
CurrencyData currencyData = new CurrencyData(applicationCurrency.getCode(), applicationCurrency.getName(),
currency.getDigitsAfterDecimal(), applicationCurrency.getDisplaySymbol(), applicationCurrency.getNameCode());
return new SavingScheduleData(currencyData, totalDeposit.getAmount(),cummulativeDepositPaid, cummulativeInterestAccured, periods);
}
private Integer determineIntValue(SavingFrequencyType frequencyType){
Integer noofTimesInterestCompoundPerYear = Integer.valueOf(0);
switch (frequencyType) {
case MONTHLY:
noofTimesInterestCompoundPerYear = monthsInYear;
break;
case QUATERLY:
noofTimesInterestCompoundPerYear = monthsInYear / 3;
break;
case HALFYEARLY:
noofTimesInterestCompoundPerYear = monthsInYear / 6;
break;
case YEARLY:
noofTimesInterestCompoundPerYear = monthsInYear / 12;
break;
default:
throw new RuntimeException("The specified frequency not supported");
}
return noofTimesInterestCompoundPerYear;
}
}
@@ -1,207 +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.savingsaccountproduct.api;
import java.util.Arrays;
import java.util.Collection;
import java.util.HashSet;
import java.util.List;
import java.util.Set;
import javax.ws.rs.Consumes;
import javax.ws.rs.DELETE;
import javax.ws.rs.GET;
import javax.ws.rs.POST;
import javax.ws.rs.PUT;
import javax.ws.rs.Path;
import javax.ws.rs.PathParam;
import javax.ws.rs.Produces;
import javax.ws.rs.core.Context;
import javax.ws.rs.core.MediaType;
import javax.ws.rs.core.UriInfo;
import org.mifosplatform.commands.domain.CommandWrapper;
import org.mifosplatform.commands.service.CommandWrapperBuilder;
import org.mifosplatform.commands.service.PortfolioCommandSourceWritePlatformService;
import org.mifosplatform.infrastructure.core.api.ApiRequestParameterHelper;
import org.mifosplatform.infrastructure.core.data.CommandProcessingResult;
import org.mifosplatform.infrastructure.core.data.EnumOptionData;
import org.mifosplatform.infrastructure.core.serialization.ApiRequestJsonSerializationSettings;
import org.mifosplatform.infrastructure.core.serialization.DefaultToApiJsonSerializer;
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.savingsaccountproduct.data.SavingProductData;
import org.mifosplatform.portfolio.savingsaccountproduct.domain.SavingFrequencyType;
import org.mifosplatform.portfolio.savingsaccountproduct.domain.SavingInterestCalculationMethod;
import org.mifosplatform.portfolio.savingsaccountproduct.domain.SavingProductType;
import org.mifosplatform.portfolio.savingsaccountproduct.domain.SavingsInterestType;
import org.mifosplatform.portfolio.savingsaccountproduct.domain.SavingsLockinPeriodEnum;
import org.mifosplatform.portfolio.savingsaccountproduct.service.SavingProductEnumerations;
import org.mifosplatform.portfolio.savingsaccountproduct.service.SavingProductReadPlatformService;
import org.mifosplatform.portfolio.savingsdepositproduct.domain.TenureTypeEnum;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Scope;
import org.springframework.stereotype.Component;
@Path("/savingproducts")
@Component
@Scope("singleton")
public class SavingProductsApiResource {
private final Set<String> SAVINGS_PRODUCT_DATA_PARAMETERS = new HashSet<String>(Arrays.asList("currencyOptions", "id", "createdOn",
"lastModifedOn", "locale", "name", "description", "currencyCode", "digitsAfterDecimal", "interstRate", "minInterestRate",
"maxInterestRate", "savingsDepositAmount", "savingProductType", "tenureType", "tenure", "frequency", "interestType",
"interestCalculationMethod", "minimumBalanceForWithdrawal", "isPartialDepositAllowed", "isLockinPeriodAllowed", "lockinPeriod",
"lockinPeriodType", "currencyOptions", "savingsProductTypeOptions", "tenureTypeOptions", "depositEvery",
"savingFrequencyOptions", "savingsInterestTypeOptions", "lockinPeriodTypeOptions", "interestCalculationOptions"));
private final SavingProductReadPlatformService savingProductReadPlatformService;
private final CurrencyReadPlatformService currencyReadPlatformService;
private final String entityType = "SAVINGSPRODUCT";
private final PlatformSecurityContext context;
private final DefaultToApiJsonSerializer<SavingProductData> toApiJsonSerializer;
private final PortfolioCommandSourceWritePlatformService commandsSourceWritePlatformService;
private final ApiRequestParameterHelper apiRequestParameterHelper;
@Autowired
public SavingProductsApiResource(final SavingProductReadPlatformService savingProductReadPlatformService,
final CurrencyReadPlatformService currencyReadPlatformService, final PlatformSecurityContext context,
final DefaultToApiJsonSerializer<SavingProductData> toApiJsonSerializer,
final PortfolioCommandSourceWritePlatformService commandsSourceWritePlatformService,
final ApiRequestParameterHelper apiRequestParameterHelper) {
this.savingProductReadPlatformService = savingProductReadPlatformService;
this.currencyReadPlatformService = currencyReadPlatformService;
this.context = context;
this.toApiJsonSerializer = toApiJsonSerializer;
this.commandsSourceWritePlatformService = commandsSourceWritePlatformService;
this.apiRequestParameterHelper = apiRequestParameterHelper;
}
@POST
@Consumes({ MediaType.APPLICATION_JSON })
@Produces({ MediaType.APPLICATION_JSON })
public String createSavingProduct(final String apiRequestBodyAsJson) {
final CommandWrapper commandRequest = new CommandWrapperBuilder().createSavingProduct().withJson(apiRequestBodyAsJson).build();
final CommandProcessingResult result = this.commandsSourceWritePlatformService.logCommandSource(commandRequest);
return this.toApiJsonSerializer.serialize(result);
}
@PUT
@Path("{productId}")
@Consumes({ MediaType.APPLICATION_JSON })
@Produces({ MediaType.APPLICATION_JSON })
public String updateSavingProduct(@PathParam("productId") final Long productId, final String apiRequestBodyAsJson) {
final CommandWrapper commandRequest = new CommandWrapperBuilder().updateSavingProduct(productId).withJson(apiRequestBodyAsJson)
.build();
final CommandProcessingResult result = this.commandsSourceWritePlatformService.logCommandSource(commandRequest);
return this.toApiJsonSerializer.serialize(result);
}
@GET
@Consumes({ MediaType.APPLICATION_JSON })
@Produces({ MediaType.APPLICATION_JSON })
public String retrieveAllSavingProducts(@Context final UriInfo uriInfo) {
context.authenticatedUser().validateHasReadPermission(entityType);
Collection<SavingProductData> products = this.savingProductReadPlatformService.retrieveAllSavingProducts();
final ApiRequestJsonSerializationSettings settings = apiRequestParameterHelper.process(uriInfo.getQueryParameters());
return this.toApiJsonSerializer.serialize(settings, products, SAVINGS_PRODUCT_DATA_PARAMETERS);
}
@GET
@Path("{productId}")
@Consumes({ MediaType.APPLICATION_JSON })
@Produces({ MediaType.APPLICATION_JSON })
public String retrieveSavingProductDetails(@PathParam("productId") final Long productId, @Context final UriInfo uriInfo) {
context.authenticatedUser().validateHasReadPermission(entityType);
SavingProductData savingProduct = this.savingProductReadPlatformService.retrieveSavingProduct(productId);
final ApiRequestJsonSerializationSettings settings = apiRequestParameterHelper.process(uriInfo.getQueryParameters());
if (settings.isTemplate()) {
savingProduct = handleTemplateRelatedData(savingProduct);
}
return this.toApiJsonSerializer.serialize(settings, savingProduct, SAVINGS_PRODUCT_DATA_PARAMETERS);
}
@GET
@Path("template")
@Consumes({ MediaType.APPLICATION_JSON })
@Produces({ MediaType.APPLICATION_JSON })
public String retrieveNewSavingProductDetails(@Context final UriInfo uriInfo) {
context.authenticatedUser().validateHasReadPermission(entityType);
SavingProductData savingProduct = this.savingProductReadPlatformService.retrieveNewSavingProductDetails();
final ApiRequestJsonSerializationSettings settings = apiRequestParameterHelper.process(uriInfo.getQueryParameters());
savingProduct = handleTemplateRelatedData(savingProduct);
return this.toApiJsonSerializer.serialize(settings, savingProduct, SAVINGS_PRODUCT_DATA_PARAMETERS);
}
private SavingProductData handleTemplateRelatedData(final SavingProductData savingProduct) {
Collection<CurrencyData> currencyOptions = this.currencyReadPlatformService.retrieveAllowedCurrencies();
EnumOptionData reccuring = SavingProductEnumerations.savingProductType(SavingProductType.RECURRING);
EnumOptionData regular = SavingProductEnumerations.savingProductType(SavingProductType.REGULAR);
List<EnumOptionData> savingsProductTypeOptions = Arrays.asList(reccuring, regular);
EnumOptionData fixed = SavingProductEnumerations.tenureTypeEnum(TenureTypeEnum.FIXED_PERIOD);
EnumOptionData perpetual = SavingProductEnumerations.tenureTypeEnum(TenureTypeEnum.PERPETUAL);
List<EnumOptionData> tenureTypeOptions = Arrays.asList(fixed, perpetual);
EnumOptionData monthly = SavingProductEnumerations.interestFrequencyType(SavingFrequencyType.MONTHLY);
List<EnumOptionData> savingFrequencyOptions = Arrays.asList(monthly);
EnumOptionData simple = SavingProductEnumerations.savingInterestType(SavingsInterestType.SIMPLE);
EnumOptionData compounding = SavingProductEnumerations.savingInterestType(SavingsInterestType.COMPOUNDING);
List<EnumOptionData> savingsInterestTypeOptions = Arrays.asList(simple, compounding);
EnumOptionData months = SavingProductEnumerations.savingsLockinPeriod(SavingsLockinPeriodEnum.MONTHS);
List<EnumOptionData> lockinPeriodTypeOptions = Arrays.asList(months);
EnumOptionData averagebal = SavingProductEnumerations.savingInterestCalculationMethod(SavingInterestCalculationMethod.AVERAGEBAL);
EnumOptionData minbal = SavingProductEnumerations.savingInterestCalculationMethod(SavingInterestCalculationMethod.MINBAL);
EnumOptionData monthlyCollection = SavingProductEnumerations
.savingInterestCalculationMethod(SavingInterestCalculationMethod.MONTHLYCOLLECTION);
List<EnumOptionData> interestCalculationOptions = Arrays.asList(averagebal, minbal, monthlyCollection);
return new SavingProductData(savingProduct, currencyOptions, savingsProductTypeOptions, tenureTypeOptions, savingFrequencyOptions,
savingsInterestTypeOptions, lockinPeriodTypeOptions, interestCalculationOptions);
}
@DELETE
@Path("{productId}")
@Consumes({ MediaType.APPLICATION_JSON })
@Produces({ MediaType.APPLICATION_JSON })
public String deleteProduct(@PathParam("productId") final Long productId) {
final CommandWrapper commandRequest = new CommandWrapperBuilder().deleteSavingProduct(productId).build();
final CommandProcessingResult result = this.commandsSourceWritePlatformService.logCommandSource(commandRequest);
return this.toApiJsonSerializer.serialize(result);
}
}
@@ -1,279 +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.savingsaccountproduct.data;
import java.io.Serializable;
import java.math.BigDecimal;
import java.util.ArrayList;
import java.util.Collection;
import java.util.List;
import org.joda.time.DateTime;
import org.mifosplatform.infrastructure.core.data.EnumOptionData;
import org.mifosplatform.organisation.monetary.data.CurrencyData;
import org.mifosplatform.portfolio.savingsaccountproduct.domain.SavingFrequencyType;
import org.mifosplatform.portfolio.savingsaccountproduct.domain.SavingInterestCalculationMethod;
import org.mifosplatform.portfolio.savingsaccountproduct.domain.SavingProductType;
import org.mifosplatform.portfolio.savingsaccountproduct.domain.SavingsInterestType;
import org.mifosplatform.portfolio.savingsaccountproduct.domain.SavingsLockinPeriodEnum;
import org.mifosplatform.portfolio.savingsaccountproduct.service.SavingProductEnumerations;
import org.mifosplatform.portfolio.savingsdepositproduct.domain.TenureTypeEnum;
public class SavingProductData implements Serializable {
private final Long id;
private final String name;
private final String description;
private final CurrencyData currency;
private final Integer digitsAfterDecimal;
private final BigDecimal interestRate;
private final BigDecimal minInterestRate;
private final BigDecimal maxInterestRate;
private final BigDecimal savingsDepositAmount;
private final EnumOptionData savingProductType;
private final EnumOptionData tenureType;
private final Integer tenure;
private final EnumOptionData savingFrequencyType;
private final EnumOptionData interestType;
private final EnumOptionData interestCalculationMethod;
private final BigDecimal minimumBalanceForWithdrawal;
private final boolean isPartialDepositAllowed;
private final boolean isLockinPeriodAllowed;
private final Integer lockinPeriod;
private final EnumOptionData lockinPeriodType;
private DateTime createdOn;
private DateTime lastModifedOn;
private final Integer depositEvery;
@SuppressWarnings("unused")
private Collection<CurrencyData> currencyOptions = new ArrayList<CurrencyData>();
private List<EnumOptionData> savingsProductTypeOptions = new ArrayList<EnumOptionData>();
private List<EnumOptionData> tenureTypeOptions = new ArrayList<EnumOptionData>();
private List<EnumOptionData> savingFrequencyOptions = new ArrayList<EnumOptionData>();
private List<EnumOptionData> savingsInterestTypeOptions = new ArrayList<EnumOptionData>();
private List<EnumOptionData> lockinPeriodTypeOptions = new ArrayList<EnumOptionData>();
private List<EnumOptionData> interestCalculationOptions = new ArrayList<EnumOptionData>();
public SavingProductData() {
this.createdOn = new DateTime();
this.lastModifedOn = new DateTime();
this.id = null;
this.name = null;
this.description = null;
this.interestRate = BigDecimal.ZERO;
this.minInterestRate = BigDecimal.ZERO;
this.maxInterestRate = BigDecimal.ZERO;
this.currency = new CurrencyData("USD", "US Dollar", 2, "$", "currency.USD");
this.digitsAfterDecimal = Integer.valueOf(2);
this.savingsDepositAmount = BigDecimal.ZERO;
this.savingProductType = SavingProductEnumerations.savingProductType(SavingProductType.RECURRING);
this.tenureType = SavingProductEnumerations.tenureTypeEnum(TenureTypeEnum.FIXED_PERIOD);
this.tenure = Integer.valueOf(12);
this.savingFrequencyType = SavingProductEnumerations.interestFrequencyType(SavingFrequencyType.MONTHLY);
this.interestType = SavingProductEnumerations.savingInterestType(SavingsInterestType.COMPOUNDING);
this.interestCalculationMethod = SavingProductEnumerations
.savingInterestCalculationMethod(SavingInterestCalculationMethod.AVERAGEBAL);
this.minimumBalanceForWithdrawal = BigDecimal.valueOf(100);
this.isPartialDepositAllowed = false;
this.isLockinPeriodAllowed = false;
this.lockinPeriod = Integer.valueOf(0);
this.lockinPeriodType = SavingProductEnumerations.savingsLockinPeriod(SavingsLockinPeriodEnum.MONTHS);
this.depositEvery = Integer.valueOf(3);
}
public SavingProductData(DateTime createdOn, DateTime lastModifedOn, Long id, String name, String description, BigDecimal interestRate,
BigDecimal minInterestRate, BigDecimal maxInterestRate, CurrencyData currency, Integer digitsAfterDecimal,
BigDecimal savingsDepositAmount, EnumOptionData savingProductType, EnumOptionData tenureType, Integer tenure,
EnumOptionData savingFrequencyType, EnumOptionData savingInterestType, EnumOptionData interestCalculationMethod,
BigDecimal minimumBalanceForWithdrawal, boolean isPartialDepositAllowed, boolean isLockinPeriodAllowed, Integer lockinPeriod,
EnumOptionData lockinPeriodType, Integer depositEvery) {
this.createdOn = createdOn;
this.lastModifedOn = lastModifedOn;
this.id = id;
this.name = name;
this.description = description;
this.interestRate = interestRate;
this.minInterestRate = minInterestRate;
this.maxInterestRate = maxInterestRate;
this.currency = currency;
this.digitsAfterDecimal = digitsAfterDecimal;
this.savingsDepositAmount = savingsDepositAmount;
this.savingProductType = savingProductType;
this.tenureType = tenureType;
this.tenure = tenure;
this.savingFrequencyType = savingFrequencyType;
this.interestType = savingInterestType;
this.interestCalculationMethod = interestCalculationMethod;
this.minimumBalanceForWithdrawal = minimumBalanceForWithdrawal;
this.isPartialDepositAllowed = isPartialDepositAllowed;
this.isLockinPeriodAllowed = isLockinPeriodAllowed;
this.lockinPeriod = lockinPeriod;
this.lockinPeriodType = lockinPeriodType;
this.depositEvery = depositEvery;
}
public SavingProductData(SavingProductData product, Collection<CurrencyData> currencyOptions,
List<EnumOptionData> savingsProductTypeOptions, List<EnumOptionData> tenureTypeOptions,
List<EnumOptionData> savingFrequencyOptions, List<EnumOptionData> savingsInterestTypeOptions,
List<EnumOptionData> lockinPeriodTypeOptions, List<EnumOptionData> interestCalculationOptions) {
this.createdOn = product.getCreatedOn();
this.lastModifedOn = product.getLastModifedOn();
this.id = product.getId();
this.name = product.getName();
this.description = product.getDescription();
this.interestRate = product.getInterestRate();
this.minInterestRate = product.getMinInterestRate();
this.maxInterestRate = product.getMaxInterestRate();
this.currency = product.getCurrency();
this.digitsAfterDecimal = product.getDigitsAfterDecimal();
this.savingsDepositAmount = product.getSavingsDepositAmount();
this.savingProductType = product.getSavingProductType();
this.tenureType = product.getTenureType();
this.tenure = product.getTenure();
this.savingFrequencyType = product.getSavingFrequencyType();
this.interestType = product.getInterestType();
this.interestCalculationMethod = product.getInterestCalculationMethod();
this.minimumBalanceForWithdrawal = product.getMinimumBalanceForWithdrawal();
this.isPartialDepositAllowed = product.isPartialDepositAllowed();
this.isLockinPeriodAllowed = product.isLockinPeriodAllowed();
this.lockinPeriod = product.getLockinPeriod();
this.lockinPeriodType = product.getLockinPeriodType();
this.depositEvery = product.getDepositEvery();
this.currencyOptions = currencyOptions;
this.savingsProductTypeOptions = savingsProductTypeOptions;
this.tenureTypeOptions = tenureTypeOptions;
this.savingFrequencyOptions = savingFrequencyOptions;
this.savingsInterestTypeOptions = savingsInterestTypeOptions;
this.lockinPeriodTypeOptions = lockinPeriodTypeOptions;
this.interestCalculationOptions = interestCalculationOptions;
}
public Long getId() {
return id;
}
public String getName() {
return name;
}
public String getDescription() {
return description;
}
public CurrencyData getCurrency() {
return currency;
}
public Integer getDigitsAfterDecimal() {
return digitsAfterDecimal;
}
public BigDecimal getInterestRate() {
return interestRate;
}
public BigDecimal getMinInterestRate() {
return minInterestRate;
}
public BigDecimal getMaxInterestRate() {
return maxInterestRate;
}
public BigDecimal getSavingsDepositAmount() {
return savingsDepositAmount;
}
public EnumOptionData getSavingProductType() {
return savingProductType;
}
public EnumOptionData getTenureType() {
return tenureType;
}
public Integer getTenure() {
return tenure;
}
public EnumOptionData getInterestType() {
return interestType;
}
public EnumOptionData getInterestCalculationMethod() {
return interestCalculationMethod;
}
public BigDecimal getMinimumBalanceForWithdrawal() {
return minimumBalanceForWithdrawal;
}
public boolean isPartialDepositAllowed() {
return isPartialDepositAllowed;
}
public boolean isLockinPeriodAllowed() {
return isLockinPeriodAllowed;
}
public Integer getLockinPeriod() {
return lockinPeriod;
}
public EnumOptionData getLockinPeriodType() {
return lockinPeriodType;
}
public DateTime getCreatedOn() {
return createdOn;
}
public DateTime getLastModifedOn() {
return lastModifedOn;
}
public void setCurrencyOptions(Collection<CurrencyData> currencyOptions) {
this.currencyOptions = currencyOptions;
}
public EnumOptionData getSavingFrequencyType() {
return savingFrequencyType;
}
public List<EnumOptionData> getSavingsProductTypeOptions() {
return savingsProductTypeOptions;
}
public List<EnumOptionData> getTenureTypeOptions() {
return tenureTypeOptions;
}
public List<EnumOptionData> getSavingFrequencyOptions() {
return savingFrequencyOptions;
}
public List<EnumOptionData> getSavingsInterestTypeOptions() {
return savingsInterestTypeOptions;
}
public List<EnumOptionData> getLockinPeriodTypeOptions() {
return lockinPeriodTypeOptions;
}
public List<EnumOptionData> getInterestCalculationOptions() {
return interestCalculationOptions;
}
public Integer getDepositEvery() {
return this.depositEvery;
}
}
@@ -1,37 +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.savingsaccountproduct.data;
import java.io.Serializable;
public class SavingProductLookup implements Serializable {
private final Long id;
private final String name;
public SavingProductLookup() {
this.id = null;
this.name = null;
}
public SavingProductLookup(final Long id, final String name) {
this.id = id;
this.name = name;
}
public Long getId() {
return id;
}
public String getName() {
return name;
}
public boolean hasId(final Long matchingId) {
return this.id.equals(matchingId);
}
}
@@ -1,59 +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.savingsaccountproduct.domain;
public enum SavingFrequencyType {
INVALID(0, "savingFrequencyType.invalid"), //
DAILY(1, "savingFrequencyType.daily"), //
MONTHLY(2, "savingFrequencyType.monthly"), //
QUATERLY(3, "savingFrequencyType.quaterly"), //
HALFYEARLY(4, "savingFrequencyType.halfyearly"), //
YEARLY(5, "savingFrequencyType.yearly");
private final Integer value;
private final String code;
private SavingFrequencyType(final Integer value, final String code) {
this.value = value;
this.code = code;
}
public Integer getValue() {
return value;
}
public String getCode() {
return code;
}
public static SavingFrequencyType fromInt(final Integer frequency) {
SavingFrequencyType savingFrequencyType = SavingFrequencyType.INVALID;
switch (frequency) {
case 1:
savingFrequencyType = SavingFrequencyType.DAILY;
break;
case 2:
savingFrequencyType = SavingFrequencyType.MONTHLY;
break;
case 3:
savingFrequencyType = SavingFrequencyType.QUATERLY;
break;
case 4:
savingFrequencyType = SavingFrequencyType.HALFYEARLY;
break;
case 5:
savingFrequencyType = SavingFrequencyType.YEARLY;
break;
default:
savingFrequencyType = SavingFrequencyType.INVALID;
break;
}
return savingFrequencyType;
}
}
@@ -1,58 +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.savingsaccountproduct.domain;
public enum SavingInterestCalculationMethod {
INVALID(0, "savinginterest.calculation.method.invalid"), //
AVERAGEBAL(1, "savinginterest.calculation.method.averagebal"), //
MINBAL(2, "savinginterest.calculation.method.minbal"), //
MONTHLYCOLLECTION(3, "savinginterest.calculation.method.monthlycllection");
private final Integer value;
private final String code;
private SavingInterestCalculationMethod(final Integer value, final String code) {
this.value = value;
this.code = code;
}
public Integer getValue() {
return value;
}
public String getCode() {
return code;
}
public static SavingInterestCalculationMethod fromInt(final Integer frequency) {
SavingInterestCalculationMethod savingInterestCalculationMethod = SavingInterestCalculationMethod.INVALID;
switch (frequency) {
case 1:
savingInterestCalculationMethod = SavingInterestCalculationMethod.AVERAGEBAL;
break;
case 2:
savingInterestCalculationMethod = SavingInterestCalculationMethod.MINBAL;
break;
case 3:
savingInterestCalculationMethod = SavingInterestCalculationMethod.MONTHLYCOLLECTION;
break;
default:
savingInterestCalculationMethod = SavingInterestCalculationMethod.INVALID;
break;
}
return savingInterestCalculationMethod;
}
public boolean isAverageBalance() {
return this.value.equals(SavingInterestCalculationMethod.AVERAGEBAL.value);
}
public boolean isMonthlyCollection() {
return this.value.equals(SavingInterestCalculationMethod.MONTHLYCOLLECTION.value);
}
}
@@ -1,142 +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.savingsaccountproduct.domain;
import java.math.BigDecimal;
import java.util.LinkedHashMap;
import java.util.Map;
import javax.persistence.Column;
import javax.persistence.Embedded;
import javax.persistence.Entity;
import javax.persistence.Table;
import org.apache.commons.lang.StringUtils;
import org.mifosplatform.infrastructure.core.api.JsonCommand;
import org.mifosplatform.infrastructure.core.domain.AbstractAuditableCustom;
import org.mifosplatform.organisation.monetary.domain.MonetaryCurrency;
import org.mifosplatform.portfolio.loanproduct.domain.PeriodFrequencyType;
import org.mifosplatform.portfolio.savingsdepositproduct.domain.TenureTypeEnum;
import org.mifosplatform.useradministration.domain.AppUser;
@Entity
@Table(name = "m_product_savings")
public class SavingProduct extends AbstractAuditableCustom<AppUser, Long> {
@Column(name = "name", nullable = false)
private String name;
@Column(name = "description")
private String description;
@Column(name = "is_deleted", nullable = false)
private boolean deleted = false;
@Embedded
private final SavingProductRelatedDetail savingProductRelatedDetail;
protected SavingProduct() {
this.name = null;
this.description = null;
this.savingProductRelatedDetail = null;
}
public SavingProduct(final String name, final String description, final MonetaryCurrency currency, final BigDecimal interestRate,
final BigDecimal minInterestRate, final BigDecimal maxInterestRate, final BigDecimal savingsDepositAmount,
final Integer depositEvery, final SavingProductType savingProductType, final TenureTypeEnum tenureType, final Integer tenure,
final SavingFrequencyType savingFrequencyType, final SavingsInterestType savingsInterestType,
final SavingInterestCalculationMethod savingInterestCalculationMethod, final BigDecimal minimumBalanceForWithdrawal,
final boolean isPartialDepositAllowed, final boolean isLockinPeriodAllowed, final Integer lockinPeriod,
final PeriodFrequencyType lockinPeriodType) {
this.name = name.trim();
if (StringUtils.isNotBlank(description)) {
this.description = description.trim();
} else {
this.description = null;
}
this.savingProductRelatedDetail = new SavingProductRelatedDetail(currency, interestRate, minInterestRate, maxInterestRate,
savingsDepositAmount, depositEvery, savingProductType, tenureType, tenure, savingFrequencyType, savingsInterestType,
savingInterestCalculationMethod, minimumBalanceForWithdrawal, isPartialDepositAllowed, isLockinPeriodAllowed, lockinPeriod,
lockinPeriodType);
}
public String getName() {
return this.name;
}
public String getDescription() {
return this.description;
}
public MonetaryCurrency getCurrency() {
return this.savingProductRelatedDetail.getCurrency();
}
public BigDecimal getInterestRate() {
return this.savingProductRelatedDetail.getInterestRate();
}
public BigDecimal getMinimumBalance() {
return this.savingProductRelatedDetail.getMinimumBalance();
}
public boolean isDeleted() {
return deleted;
}
public void delete() {
this.deleted = true;
}
public SavingProductRelatedDetail getSavingProductRelatedDetail() {
return savingProductRelatedDetail;
}
public Map<String, Object> update(final JsonCommand command) {
final Map<String, Object> actualChanges = new LinkedHashMap<String, Object>(20);
final String nameParamName = "name";
if (command.isChangeInStringParameterNamed(nameParamName, this.name)) {
final String newValue = command.stringValueOfParameterNamed(nameParamName);
actualChanges.put(nameParamName, newValue);
this.name = newValue;
}
final String descriptionParamName = "description";
if (command.isChangeInStringParameterNamed(descriptionParamName, this.description)) {
final String newValue = command.stringValueOfParameterNamed(descriptionParamName);
actualChanges.put(descriptionParamName, newValue);
this.description = newValue;
}
return this.savingProductRelatedDetail.update(command, actualChanges);
}
public static SavingProduct assembleFromJson(final JsonCommand command, final MonetaryCurrency currency,
final SavingProductType savingProductType, final TenureTypeEnum tenureType, final SavingFrequencyType savingFrequencyType,
final SavingsInterestType interestType, final SavingInterestCalculationMethod savingInterestCalculationMethod,
final PeriodFrequencyType lockinPeriodType) {
final String name = command.stringValueOfParameterNamed("name");
final String description = command.stringValueOfParameterNamed("description");
final BigDecimal interestRate = command.bigDecimalValueOfParameterNamed("interestRate");
final BigDecimal minInterestRate = command.bigDecimalValueOfParameterNamed("minInterestRate");
final BigDecimal maxInterestRate = command.bigDecimalValueOfParameterNamed("maxInterestRate");
final BigDecimal savingsDepositAmount = command.bigDecimalValueOfParameterNamed("savingsDepositAmount");
final Integer tenure = command.integerValueOfParameterNamed("tenure");
final BigDecimal minimumBalanceForWithdrawal = command.bigDecimalValueOfParameterNamed("minimumBalanceForWithdrawal");
final boolean isPartialDepositAllowed = command.booleanPrimitiveValueOfParameterNamed("isPartialDepositAllowed");
final boolean isLockinPeriodAllowed = command.booleanPrimitiveValueOfParameterNamed("isLockinPeriodAllowed");
final Integer lockinPeriod = command.integerValueOfParameterNamed("lockinPeriod");
final Integer depositEvery = command.integerValueOfParameterNamed("depositEvery");
return new SavingProduct(name, description, currency, interestRate, minInterestRate, maxInterestRate, savingsDepositAmount,
depositEvery, savingProductType, tenureType, tenure, savingFrequencyType, interestType, savingInterestCalculationMethod,
minimumBalanceForWithdrawal, isPartialDepositAllowed, isLockinPeriodAllowed, lockinPeriod, lockinPeriodType);
}
}
@@ -1,310 +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.savingsaccountproduct.domain;
import java.math.BigDecimal;
import java.util.Map;
import javax.persistence.Column;
import javax.persistence.Embeddable;
import javax.persistence.Embedded;
import org.mifosplatform.infrastructure.core.api.JsonCommand;
import org.mifosplatform.organisation.monetary.domain.MonetaryCurrency;
import org.mifosplatform.portfolio.loanproduct.domain.PeriodFrequencyType;
import org.mifosplatform.portfolio.savingsdepositproduct.domain.TenureTypeEnum;
@Embeddable
public class SavingProductRelatedDetail {
@Embedded
private MonetaryCurrency currency;
@Column(name = "interest_rate", scale = 6, precision = 19, nullable = false)
private BigDecimal interestRate;
@SuppressWarnings("unused")
@Column(name = "min_interest_rate", scale = 6, precision = 19, nullable = false)
private BigDecimal minInterestRate;
@SuppressWarnings("unused")
@Column(name = "max_interest_rate", scale = 6, precision = 19, nullable = false)
private BigDecimal maxInterestRate;
@Column(name = "savings_deposit_amount", scale = 6, precision = 19, nullable = false)
private BigDecimal savingsDepositAmount;
@Column(name = "deposit_every")
private Integer depositEvery;
@Column(name = "savings_product_type", nullable = false)
private Integer savingProductType;
@Column(name = "tenure_type", nullable = false)
private Integer tenureType;
@Column(name = "tenure", nullable = false)
private Integer tenure;
@Column(name = "frequency", nullable = false)
private Integer frequency;
@Column(name = "interest_type", nullable = false)
private Integer interestType;
@Column(name = "interest_calculation_method")
private Integer interestCalculationMethod;
@Column(name = "min_bal_for_withdrawal", scale = 6, precision = 19, nullable = false)
private BigDecimal minimumBalanceForWithdrawal;
@Column(name = "is_partial_deposit_allowed", nullable = false)
private boolean isPartialDepositAllowed;
@Column(name = "is_lock_in_period_allowed", nullable = false)
private boolean isLockinPeriodAllowed;
@Column(name = "lock_in_period", nullable = false)
private Integer lockinPeriod;
@Column(name = "lock_in_period_type", nullable = false)
private Integer lockinPeriodType;
public SavingProductRelatedDetail() {
this.interestRate = null;
this.savingsDepositAmount = null;
}
public SavingProductRelatedDetail(final MonetaryCurrency currency, final BigDecimal interestRate, final BigDecimal minInterestRate,
final BigDecimal maxInterestRate, final BigDecimal savingsDepositAmount, final Integer depositEvery,
final SavingProductType savingProductType, final TenureTypeEnum tenureType, final Integer tenure,
final SavingFrequencyType frequency, final SavingsInterestType interestType,
final SavingInterestCalculationMethod interestCalculationMethod, final BigDecimal minimumBalanceForWithdrawal,
final boolean isPartialDepositAllowed, final boolean isLockinPeriodAllowed, final Integer lockinPeriod,
final PeriodFrequencyType lockinPeriodType) {
this.currency = currency;
this.interestRate = interestRate;
this.minInterestRate = minInterestRate;
this.maxInterestRate = maxInterestRate;
this.savingsDepositAmount = savingsDepositAmount;
this.depositEvery = depositEvery;
this.savingProductType = savingProductType.getValue();
this.tenureType = tenureType.getValue();
this.tenure = tenure;
this.frequency = frequency.getValue();
this.interestType = interestType.getValue();
this.interestCalculationMethod = interestCalculationMethod.getValue();
this.minimumBalanceForWithdrawal = minimumBalanceForWithdrawal;
this.isPartialDepositAllowed = isPartialDepositAllowed;
this.isLockinPeriodAllowed = isLockinPeriodAllowed;
this.lockinPeriod = lockinPeriod;
this.lockinPeriodType = lockinPeriodType.getValue();
}
public MonetaryCurrency getCurrency() {
return this.currency.copy();
}
public BigDecimal getInterestRate() {
return BigDecimal.valueOf(Double.valueOf(this.interestRate.stripTrailingZeros().toString()));
}
public BigDecimal getMinimumBalance() {
return BigDecimal.valueOf(Double.valueOf(this.savingsDepositAmount.stripTrailingZeros().toString()));
}
public Map<String, Object> update(final JsonCommand command, final Map<String, Object> actualChanges) {
final String localeAsInput = command.locale();
Integer digitsAfterDecimal = this.currency.getDigitsAfterDecimal();
final String digitsAfterDecimalParamName = "digitsAfterDecimal";
if (command.isChangeInIntegerParameterNamed(digitsAfterDecimalParamName, digitsAfterDecimal)) {
final Integer newValue = command.integerValueOfParameterNamed(digitsAfterDecimalParamName);
actualChanges.put(digitsAfterDecimalParamName, newValue);
actualChanges.put("locale", localeAsInput);
digitsAfterDecimal = newValue;
this.currency = new MonetaryCurrency(this.currency.getCode(), digitsAfterDecimal);
}
String currencyCode = this.currency.getCode();
final String currencyCodeParamName = "currencyCode";
if (command.isChangeInStringParameterNamed(currencyCodeParamName, currencyCode)) {
final String newValue = command.stringValueOfParameterNamed(currencyCodeParamName);
actualChanges.put(currencyCodeParamName, newValue);
currencyCode = newValue;
this.currency = new MonetaryCurrency(currencyCode, this.currency.getDigitsAfterDecimal());
}
final String interestRateParamName = "interestRate";
if (command.isChangeInBigDecimalParameterNamed(interestRateParamName, this.interestRate)) {
final BigDecimal newValue = command.bigDecimalValueOfParameterNamed(interestRateParamName);
actualChanges.put(interestRateParamName, newValue);
actualChanges.put("locale", localeAsInput);
this.interestRate = newValue;
}
final String savingsDepositAmountParamName = "savingsDepositAmount";
if (command.isChangeInBigDecimalParameterNamed(savingsDepositAmountParamName, this.savingsDepositAmount)) {
final BigDecimal newValue = command.bigDecimalValueOfParameterNamed(savingsDepositAmountParamName);
actualChanges.put(savingsDepositAmountParamName, newValue);
actualChanges.put("locale", localeAsInput);
this.savingsDepositAmount = newValue;
}
final String depositEveryParamName = "depositEvery";
if (command.isChangeInIntegerParameterNamed(depositEveryParamName, this.depositEvery)) {
final Integer newValue = command.integerValueOfParameterNamed(depositEveryParamName);
actualChanges.put(depositEveryParamName, newValue);
actualChanges.put("locale", localeAsInput);
this.depositEvery = newValue;
}
final String savingProductTypeParamName = "savingProductType";
if (command.isChangeInIntegerParameterNamed(savingProductTypeParamName, this.savingProductType)) {
final Integer newValue = command.integerValueOfParameterNamed(savingProductTypeParamName);
actualChanges.put(savingProductTypeParamName, newValue);
actualChanges.put("locale", localeAsInput);
this.savingProductType = SavingProductType.fromInt(newValue).getValue();
}
final String tenureTypeParamName = "tenureType";
if (command.isChangeInIntegerParameterNamed(tenureTypeParamName, this.tenureType)) {
final Integer newValue = command.integerValueOfParameterNamed(tenureTypeParamName);
actualChanges.put(tenureTypeParamName, newValue);
actualChanges.put("locale", localeAsInput);
this.tenureType = TenureTypeEnum.fromInt(newValue).getValue();
}
final String tenureParamName = "tenure";
if (command.isChangeInIntegerParameterNamed(tenureParamName, this.tenure)) {
final Integer newValue = command.integerValueOfParameterNamed(tenureParamName);
actualChanges.put(tenureParamName, newValue);
actualChanges.put("locale", localeAsInput);
this.tenure = newValue;
}
final String frequencyParamName = "frequency";
if (command.isChangeInIntegerParameterNamed(frequencyParamName, this.frequency)) {
final Integer newValue = command.integerValueOfParameterNamed(frequencyParamName);
actualChanges.put(frequencyParamName, newValue);
actualChanges.put("locale", localeAsInput);
this.frequency = SavingFrequencyType.fromInt(newValue).getValue();
}
final String interestTypeParamName = "interestType";
if (command.isChangeInIntegerParameterNamed(interestTypeParamName, this.interestType)) {
final Integer newValue = command.integerValueOfParameterNamed(interestTypeParamName);
actualChanges.put(interestTypeParamName, newValue);
actualChanges.put("locale", localeAsInput);
this.interestType = SavingsInterestType.fromInt(newValue).getValue();
}
final String interestCalculationMethodParamName = "interestCalculationMethod";
if (command.isChangeInIntegerParameterNamed(interestCalculationMethodParamName, this.interestCalculationMethod)) {
final Integer newValue = command.integerValueOfParameterNamed(interestCalculationMethodParamName);
actualChanges.put(interestCalculationMethodParamName, newValue);
actualChanges.put("locale", localeAsInput);
this.interestCalculationMethod = SavingInterestCalculationMethod.fromInt(newValue).getValue();
}
final String minimumBalanceForWithdrawalParamName = "minimumBalanceForWithdrawal";
if (command.isChangeInBigDecimalParameterNamed(minimumBalanceForWithdrawalParamName, this.minimumBalanceForWithdrawal)) {
final BigDecimal newValue = command.bigDecimalValueOfParameterNamed(minimumBalanceForWithdrawalParamName);
actualChanges.put(minimumBalanceForWithdrawalParamName, newValue);
actualChanges.put("locale", localeAsInput);
this.minimumBalanceForWithdrawal = newValue;
}
final String isPartialDepositAllowedParamName = "isPartialDepositAllowed";
if (command.isChangeInBooleanParameterNamed(isPartialDepositAllowedParamName, this.isPartialDepositAllowed)) {
final Boolean newValue = command.booleanObjectValueOfParameterNamed(isPartialDepositAllowedParamName);
actualChanges.put(isPartialDepositAllowedParamName, newValue);
actualChanges.put("locale", localeAsInput);
this.isPartialDepositAllowed = newValue;
}
final String isLockinPeriodAllowedParamName = "isLockinPeriodAllowed";
if (command.isChangeInBooleanParameterNamed(isLockinPeriodAllowedParamName, this.isLockinPeriodAllowed)) {
final Boolean newValue = command.booleanObjectValueOfParameterNamed(isLockinPeriodAllowedParamName);
actualChanges.put(isLockinPeriodAllowedParamName, newValue);
actualChanges.put("locale", localeAsInput);
this.isLockinPeriodAllowed = newValue;
}
final String lockinPeriodParamName = "lockinPeriod";
if (command.isChangeInIntegerParameterNamed(lockinPeriodParamName, this.lockinPeriod)) {
final Integer newValue = command.integerValueOfParameterNamed(lockinPeriodParamName);
actualChanges.put(lockinPeriodParamName, newValue);
actualChanges.put("locale", localeAsInput);
this.lockinPeriod = newValue;
}
final String lockinPeriodTypeParamName = "lockinPeriodType";
if (command.isChangeInIntegerParameterNamed(lockinPeriodTypeParamName, this.lockinPeriodType)) {
final Integer newValue = command.integerValueOfParameterNamed(lockinPeriodTypeParamName);
actualChanges.put(lockinPeriodTypeParamName, newValue);
actualChanges.put("locale", localeAsInput);
this.lockinPeriodType = PeriodFrequencyType.fromInt(newValue).getValue();
}
return actualChanges;
}
public BigDecimal getSavingsDepositAmount() {
return savingsDepositAmount;
}
public Integer getDepositEvery() {
return this.depositEvery;
}
public Integer getSavingProductType() {
return savingProductType;
}
public Integer getTenureType() {
return tenureType;
}
public Integer getTenure() {
return tenure;
}
public Integer getFrequency() {
return frequency;
}
public Integer getInterestType() {
return interestType;
}
public Integer getInterestCalculationMethod() {
return interestCalculationMethod;
}
public BigDecimal getMinimumBalanceForWithdrawal() {
return minimumBalanceForWithdrawal;
}
public boolean isPartialDepositAllowed() {
return isPartialDepositAllowed;
}
public boolean isLockinPeriodAllowed() {
return isLockinPeriodAllowed;
}
public Integer getLockinPeriod() {
return lockinPeriod;
}
public Integer getLockinPeriodType() {
return lockinPeriodType;
}
}
@@ -1,13 +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.savingsaccountproduct.domain;
import org.springframework.data.jpa.repository.JpaRepository;
import org.springframework.data.jpa.repository.JpaSpecificationExecutor;
public interface SavingProductRepository extends JpaRepository<SavingProduct, Long>, JpaSpecificationExecutor<SavingProduct> {
//
}
@@ -1,55 +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.savingsaccountproduct.domain;
public enum SavingProductType {
INVALID(0, "savingProductType.invalid"), //
RECURRING(1, "savingProductType.reccuring"), //
REGULAR(2, "savingProductType.regular");
private final Integer value;
private final String code;
private SavingProductType(final Integer value, final String code) {
this.value = value;
this.code = code;
}
public Integer getValue() {
return value;
}
public String getCode() {
return code;
}
public static SavingProductType fromInt(final Integer frequency) {
SavingProductType savingProductType = SavingProductType.INVALID;
switch (frequency) {
case 1:
savingProductType = SavingProductType.RECURRING;
break;
case 2:
savingProductType = SavingProductType.REGULAR;
break;
default:
savingProductType = SavingProductType.INVALID;
break;
}
return savingProductType;
}
public boolean isReccuring() {
return this.value.equals(SavingProductType.RECURRING.getValue());
}
public boolean isRegular() {
return this.value.equals(SavingProductType.REGULAR.getValue());
}
}
@@ -1,46 +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.savingsaccountproduct.domain;
public enum SavingsInterestType {
INVALID(0, "savingsInterestType.invalid"), //
SIMPLE(1, "savingsInterestType.simple"), //
COMPOUNDING(2, "savingsInterestType.compounding");
private final Integer value;
private final String code;
private SavingsInterestType(final Integer value, final String code) {
this.value = value;
this.code = code;
}
public Integer getValue() {
return value;
}
public String getCode() {
return code;
}
public static SavingsInterestType fromInt(final Integer frequency) {
SavingsInterestType savingsInterestType = SavingsInterestType.INVALID;
switch (frequency) {
case 1:
savingsInterestType = SavingsInterestType.SIMPLE;
break;
case 2:
savingsInterestType = SavingsInterestType.COMPOUNDING;
break;
default:
savingsInterestType = SavingsInterestType.INVALID;
break;
}
return savingsInterestType;
}
}
@@ -1,55 +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.savingsaccountproduct.domain;
public enum SavingsLockinPeriodEnum {
DAYS(0, "lockin.period.type.days"), //
WEEKS(1, "lockin.period.type.weeks"), //
MONTHS(2, "lockin.period.type.months"), //
YEARS(3, "lockin.period.type.years"), //
INVALID(4, "lockin.period.type.invalid");
private final Integer value;
private final String code;
private SavingsLockinPeriodEnum(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 SavingsLockinPeriodEnum fromInt(final Integer frequency) {
SavingsLockinPeriodEnum lockinPeriodType = SavingsLockinPeriodEnum.INVALID;
switch (frequency) {
case 0:
lockinPeriodType = SavingsLockinPeriodEnum.DAYS;
break;
case 1:
lockinPeriodType = SavingsLockinPeriodEnum.WEEKS;
break;
case 2:
lockinPeriodType = SavingsLockinPeriodEnum.MONTHS;
break;
case 3:
lockinPeriodType = SavingsLockinPeriodEnum.YEARS;
break;
default:
lockinPeriodType = SavingsLockinPeriodEnum.INVALID;
break;
}
return lockinPeriodType;
}
}
@@ -1,24 +0,0 @@
package org.mifosplatform.portfolio.savingsaccountproduct.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.savingsaccountproduct.service.SavingProductWritePlatformService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
@Service
public class UpdateSavingProductCommandHandler implements NewCommandSourceHandler {
private final SavingProductWritePlatformService savingProductWritePlatformService;
@Autowired
public UpdateSavingProductCommandHandler(final SavingProductWritePlatformService savingProductWritePlatformService) {
this.savingProductWritePlatformService = savingProductWritePlatformService;
}
@Override
public CommandProcessingResult processCommand(final JsonCommand command) {
return this.savingProductWritePlatformService.updateSavingProduct(command.entityId(), command);
}
}
@@ -1,214 +0,0 @@
package org.mifosplatform.portfolio.savingsaccountproduct.serialization;
import java.lang.reflect.Type;
import java.math.BigDecimal;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.HashSet;
import java.util.List;
import java.util.Locale;
import java.util.Map;
import java.util.Set;
import org.apache.commons.lang.StringUtils;
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 class SavingProductCommandFromApiJsonDeserializer {
private final Set<String> supportedParams = new HashSet<String>(Arrays.asList("locale", "name", "description", "currencyCode",
"digitsAfterDecimal", "interestRate", "minInterestRate", "maxInterestRate", "savingsDepositAmount", "savingProductType",
"tenureType", "tenure", "frequency", "interestType", "interestCalculationMethod", "minimumBalanceForWithdrawal",
"isPartialDepositAllowed", "isLockinPeriodAllowed", "lockinPeriod", "lockinPeriodType", "depositEvery"));
private final FromJsonHelper fromApiJsonHelper;
@Autowired
public SavingProductCommandFromApiJsonDeserializer(final FromJsonHelper fromApiJsonHelper) {
this.fromApiJsonHelper = fromApiJsonHelper;
}
public void validateForCreate(final String json) {
if (StringUtils.isBlank(json)) { throw new InvalidJsonException(); }
final Type typeOfMap = new TypeToken<Map<String, Object>>() {}.getType();
fromApiJsonHelper.checkForUnsupportedParameters(typeOfMap, json, supportedParams);
List<ApiParameterError> dataValidationErrors = new ArrayList<ApiParameterError>();
DataValidatorBuilder baseDataValidator = new DataValidatorBuilder(dataValidationErrors).resource("product");
final JsonElement element = fromApiJsonHelper.parse(json);
final String name = fromApiJsonHelper.extractStringNamed("name", element);
baseDataValidator.reset().parameter("name").value(name).notBlank().notExceedingLengthOf(100);
final String description = fromApiJsonHelper.extractStringNamed("description", element);
baseDataValidator.reset().parameter("description").value(description).notExceedingLengthOf(500);
final String currencyCode = fromApiJsonHelper.extractStringNamed("currencyCode", element);
baseDataValidator.reset().parameter("currencyCode").value(currencyCode).notBlank();
final Integer digitsAfterDecimal = fromApiJsonHelper.extractIntegerNamed("digitsAfterDecimal", element, Locale.getDefault());
baseDataValidator.reset().parameter("digitsAfterDecimal").value(digitsAfterDecimal).notNull().inMinMaxRange(0, 6);
final BigDecimal interestRate = fromApiJsonHelper.extractBigDecimalWithLocaleNamed("interestRate", element);
baseDataValidator.reset().parameter("interestRate").value(interestRate).notNull().zeroOrPositiveAmount();
final BigDecimal minInterestRate = fromApiJsonHelper.extractBigDecimalWithLocaleNamed("minInterestRate", element);
baseDataValidator.reset().parameter("minInterestRate").value(minInterestRate).notNull().zeroOrPositiveAmount();
final BigDecimal maxInterestRate = fromApiJsonHelper.extractBigDecimalWithLocaleNamed("maxInterestRate", element);
baseDataValidator.reset().parameter("maxInterestRate").value(maxInterestRate).notNull().zeroOrPositiveAmount();
baseDataValidator.reset().parameter("minInterestRate").comapareMinAndMaxOfTwoBigDecmimalNos(minInterestRate, maxInterestRate);
baseDataValidator.reset().parameter("interestRate").comapareMinAndMaxOfTwoBigDecmimalNos(interestRate, maxInterestRate);
baseDataValidator.reset().parameter("minInterestRate").comapareMinAndMaxOfTwoBigDecmimalNos(minInterestRate, interestRate);
final BigDecimal savingsDepositAmount = fromApiJsonHelper.extractBigDecimalWithLocaleNamed("savingsDepositAmount", element);
baseDataValidator.reset().parameter("savingsDepositAmount").value(savingsDepositAmount).notNull().zeroOrPositiveAmount();
final Integer savingProductType = fromApiJsonHelper.extractIntegerNamed("savingProductType", element, Locale.getDefault());
baseDataValidator.reset().parameter("savingProductType").value(savingProductType).notNull();
final Integer tenureType = fromApiJsonHelper.extractIntegerNamed("tenureType", element, Locale.getDefault());
baseDataValidator.reset().parameter("tenureType").value(tenureType).notNull();
final Integer tenure = fromApiJsonHelper.extractIntegerNamed("tenure", element, Locale.getDefault());
baseDataValidator.reset().parameter("tenure").value(tenure).notNull();
final Integer frequency = fromApiJsonHelper.extractIntegerNamed("frequency", element, Locale.getDefault());
baseDataValidator.reset().parameter("frequency").value(frequency).notNull();
final Integer interestType = fromApiJsonHelper.extractIntegerNamed("interestType", element, Locale.getDefault());
baseDataValidator.reset().parameter("interestType").value(interestType).notNull();
final Integer interestCalculationMethod = fromApiJsonHelper.extractIntegerNamed("interestCalculationMethod", element,
Locale.getDefault());
baseDataValidator.reset().parameter("interestCalculationMethod").value(interestCalculationMethod).notNull();
final BigDecimal minimumBalanceForWithdrawal = fromApiJsonHelper.extractBigDecimalWithLocaleNamed("minimumBalanceForWithdrawal",
element);
baseDataValidator.reset().parameter("minimumBalanceForWithdrawal").value(minimumBalanceForWithdrawal).notNull()
.zeroOrPositiveAmount();
final Boolean isPartialDepositAllowedCommandValue = fromApiJsonHelper.extractBooleanNamed("isPartialDepositAllowed", element);
baseDataValidator.reset().parameter("isPartialDepositAllowed").value(isPartialDepositAllowedCommandValue)
.trueOrFalseRequired(isBooleanValueUpdated(isPartialDepositAllowedCommandValue)).notNull();
final Boolean isLockinPeriodAllowedCommandValue = fromApiJsonHelper.extractBooleanNamed("isLockinPeriodAllowed", element);
baseDataValidator.reset().parameter("isLockinPeriodAllowed").value(isLockinPeriodAllowedCommandValue)
.trueOrFalseRequired(isBooleanValueUpdated(isLockinPeriodAllowedCommandValue));
final Integer lockinPeriod = fromApiJsonHelper.extractIntegerNamed("lockinPeriod", element, Locale.getDefault());
baseDataValidator.reset().parameter("lockinPeriod").value(lockinPeriod).notNull().zeroOrPositiveAmount();
final Integer lockinPeriodType = fromApiJsonHelper.extractIntegerNamed("lockinPeriodType", element, Locale.getDefault());
baseDataValidator.reset().parameter("lockinPeriodType").value(lockinPeriodType).notNull().inMinMaxRange(1, 3);
throwExceptionIfValidationWarningsExist(dataValidationErrors);
}
public void validateForUpdate(final String json) {
if (StringUtils.isBlank(json)) { throw new InvalidJsonException(); }
final Type typeOfMap = new TypeToken<Map<String, Object>>() {}.getType();
fromApiJsonHelper.checkForUnsupportedParameters(typeOfMap, json, supportedParams);
List<ApiParameterError> dataValidationErrors = new ArrayList<ApiParameterError>();
DataValidatorBuilder baseDataValidator = new DataValidatorBuilder(dataValidationErrors).resource("product");
final JsonElement element = fromApiJsonHelper.parse(json);
final String name = fromApiJsonHelper.extractStringNamed("name", element);
baseDataValidator.reset().parameter("name").value(name).ignoreIfNull().notBlank().notExceedingLengthOf(100);
final String description = fromApiJsonHelper.extractStringNamed("description", element);
baseDataValidator.reset().parameter("description").value(description).notExceedingLengthOf(500);
final String currencyCode = fromApiJsonHelper.extractStringNamed("currencyCode", element);
baseDataValidator.reset().parameter("currencyCode").value(currencyCode).ignoreIfNull().notBlank();
final Integer digitsAfterDecimal = fromApiJsonHelper.extractIntegerNamed("digitsAfterDecimal", element, Locale.getDefault());
baseDataValidator.reset().parameter("digitsAfterDecimal").value(digitsAfterDecimal).ignoreIfNull().inMinMaxRange(0, 6);
final BigDecimal interestRate = fromApiJsonHelper.extractBigDecimalWithLocaleNamed("interestRate", element);
baseDataValidator.reset().parameter("interestRate").value(interestRate).ignoreIfNull().zeroOrPositiveAmount();
final BigDecimal minInterestRate = fromApiJsonHelper.extractBigDecimalWithLocaleNamed("minInterestRate", element);
baseDataValidator.reset().parameter("minInterestRate").value(minInterestRate).ignoreIfNull().zeroOrPositiveAmount();
final BigDecimal maxInterestRate = fromApiJsonHelper.extractBigDecimalWithLocaleNamed("maxInterestRate", element);
baseDataValidator.reset().parameter("maxInterestRate").value(maxInterestRate).ignoreIfNull().zeroOrPositiveAmount();
baseDataValidator.reset().parameter("minInterestRate").comapareMinAndMaxOfTwoBigDecmimalNos(minInterestRate, maxInterestRate);
baseDataValidator.reset().parameter("interestRate").comapareMinAndMaxOfTwoBigDecmimalNos(interestRate, maxInterestRate);
baseDataValidator.reset().parameter("minInterestRate").comapareMinAndMaxOfTwoBigDecmimalNos(minInterestRate, interestRate);
final BigDecimal savingsDepositAmount = fromApiJsonHelper.extractBigDecimalWithLocaleNamed("savingsDepositAmount", element);
baseDataValidator.reset().parameter("savingsDepositAmount").value(savingsDepositAmount).ignoreIfNull().zeroOrPositiveAmount();
final Integer savingProductType = fromApiJsonHelper.extractIntegerNamed("savingProductType", element, Locale.getDefault());
baseDataValidator.reset().parameter("savingProductType").value(savingProductType).ignoreIfNull();
final Integer tenureType = fromApiJsonHelper.extractIntegerNamed("tenureType", element, Locale.getDefault());
baseDataValidator.reset().parameter("tenureType").value(tenureType).ignoreIfNull();
final Integer tenure = fromApiJsonHelper.extractIntegerNamed("tenure", element, Locale.getDefault());
baseDataValidator.reset().parameter("tenure").value(tenure).ignoreIfNull().integerGreaterThanZero();
final Integer frequency = fromApiJsonHelper.extractIntegerNamed("frequency", element, Locale.getDefault());
baseDataValidator.reset().parameter("frequency").value(frequency).ignoreIfNull();
final Integer interestType = fromApiJsonHelper.extractIntegerNamed("interestType", element, Locale.getDefault());
baseDataValidator.reset().parameter("interestType").value(interestType).ignoreIfNull();
final Integer interestCalculationMethod = fromApiJsonHelper.extractIntegerNamed("interestCalculationMethod", element,
Locale.getDefault());
baseDataValidator.reset().parameter("interestCalculationMethod").value(interestCalculationMethod).ignoreIfNull();
final BigDecimal minimumBalanceForWithdrawal = fromApiJsonHelper.extractBigDecimalWithLocaleNamed("minimumBalanceForWithdrawal",
element);
baseDataValidator.reset().parameter("minimumBalanceForWithdrawal").value(minimumBalanceForWithdrawal).ignoreIfNull()
.zeroOrPositiveAmount();
final Boolean isPartialDepositAllowedCommandValue = fromApiJsonHelper.extractBooleanNamed("isPartialDepositAllowed", element);
baseDataValidator.reset().parameter("isPartialDepositAllowed").value(isPartialDepositAllowedCommandValue)
.trueOrFalseRequired(isBooleanValueUpdated(isPartialDepositAllowedCommandValue)).ignoreIfNull();
final Boolean isLockinPeriodAllowedCommandValue = fromApiJsonHelper.extractBooleanNamed("isLockinPeriodAllowed", element);
baseDataValidator.reset().parameter("isLockinPeriodAllowed").value(isLockinPeriodAllowedCommandValue)
.trueOrFalseRequired(isBooleanValueUpdated(isLockinPeriodAllowedCommandValue)).ignoreIfNull();
final Integer lockinPeriod = fromApiJsonHelper.extractIntegerNamed("lockinPeriod", element, Locale.getDefault());
baseDataValidator.reset().parameter("lockinPeriod").value(lockinPeriod).ignoreIfNull().zeroOrPositiveAmount();
final Integer lockinPeriodType = fromApiJsonHelper.extractIntegerNamed("lockinPeriodType", element, Locale.getDefault());
baseDataValidator.reset().parameter("lockinPeriodType").value(lockinPeriodType).ignoreIfNull().inMinMaxRange(1, 3);
throwExceptionIfValidationWarningsExist(dataValidationErrors);
}
private void throwExceptionIfValidationWarningsExist(final List<ApiParameterError> dataValidationErrors) {
if (!dataValidationErrors.isEmpty()) { throw new PlatformApiDataValidationException("validation.msg.validation.errors.exist",
"Validation errors exist.", dataValidationErrors); }
}
private Boolean isBooleanValueUpdated(final Boolean actualValue) {
Boolean isUpdated = false;
if (actualValue != null) {
isUpdated = true;
}
return isUpdated;
}
}

Some files were not shown because too many files have changed in this diff Show More