MIFOSX-247: basic savings functions for deposit and withdrawal.

This commit is contained in:
Keith Woodlock
2013-03-22 00:42:01 +00:00
parent 2374bf9402
commit 1b4403e767
44 changed files with 1548 additions and 504 deletions
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
@@ -0,0 +1,51 @@
INSERT INTO `m_permission` (`grouping`, `code`, `entity_name`, `action_name`, `can_maker_checker`)
VALUES
('transaction_savings', 'DEPOSIT_SAVINGSACCOUNT', 'SAVINGSACCOUNT', 'DEPOSIT', '1'),
('transaction_savings', 'DEPOSIT_SAVINGSACCOUNT_CHECKER', 'SAVINGSACCOUNT', 'DEPOSIT', '0'),
('transaction_savings', 'WITHDRAWAL_SAVINGSACCOUNT', 'SAVINGSACCOUNT', 'WITHDRAWAL', '1'),
('transaction_savings', 'WITHDRAWAL_SAVINGSACCOUNT_CHECKER', 'SAVINGSACCOUNT', 'WITHDRAWAL', '0');
DROP TABLE IF EXISTS `m_savings_account_transaction`;
DROP TABLE IF EXISTS `m_savings_account`;
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,
`total_deposits_derived` decimal(19,6) DEFAULT NULL,
`total_withdrawals_derived` decimal(19,6) DEFAULT NULL,
`total_interest_posted_derived` decimal(19,6) DEFAULT NULL,
`account_balance_derived` decimal(19,6) NOT NULL DEFAULT 0,
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;
CREATE TABLE `m_savings_account_transaction` (
`id` bigint(20) NOT NULL AUTO_INCREMENT,
`savings_account_id` bigint(20) NOT NULL,
`transaction_type_enum` smallint(5) NOT NULL,
`transaction_date` date NOT NULL,
`amount` decimal(19,6) NOT NULL,
`is_reversed` tinyint(1) NOT NULL,
PRIMARY KEY (`id`),
KEY `FKSAT0000000001` (`savings_account_id`),
CONSTRAINT `FKSAT0000000001` FOREIGN KEY (`savings_account_id`) REFERENCES `m_savings_account` (`id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8;
@@ -13,6 +13,7 @@ public class CommandWrapper {
private final Long groupId;
private final Long clientId;
private final Long loanId;
private final Long savingsId;
private final String actionName;
private final String entityName;
private final String taskPermissionName;
@@ -41,6 +42,7 @@ public class CommandWrapper {
this.groupId = null;
this.clientId = null;
this.loanId = null;
this.savingsId = null;
this.actionName = actionName;
this.entityName = entityName;
this.taskPermissionName = actionName + "_" + entityName;
@@ -55,14 +57,16 @@ public class CommandWrapper {
}
public CommandWrapper(final Long officeId, final Long groupId, final Long clientId, final Long loanId, final String actionName,
final String entityName, final Long entityId, final Long subentityId, final Long codeId,
final String supportedEntityType, final Long supportedEntityId, final String href, final String json, final String transactionId) {
public CommandWrapper(final Long officeId, final Long groupId, final Long clientId, final Long loanId, final Long savingsId,
final String actionName, final String entityName, final Long entityId, final Long subentityId,
final Long codeId, final String supportedEntityType, final Long supportedEntityId, final String href, final String json,
final String transactionId) {
this.commandId = null;
this.officeId = officeId;
this.groupId = groupId;
this.clientId = clientId;
this.loanId = loanId;
this.savingsId = savingsId;
this.actionName = actionName;
this.entityName = entityName;
this.taskPermissionName = actionName + "_" + entityName;
@@ -107,11 +111,11 @@ public class CommandWrapper {
public String getTaskPermissionName() {
return this.taskPermissionName;
}
public Long getCodeId(){
public Long getCodeId() {
return this.codeId;
}
public String getHref() {
return this.href;
}
@@ -119,7 +123,7 @@ public class CommandWrapper {
public String getJson() {
return this.json;
}
public String getTransactionId() {
return this.transactionId;
}
@@ -148,6 +152,10 @@ public class CommandWrapper {
return this.loanId;
}
public Long getSavingsId() {
return this.savingsId;
}
public Long getSupportedEntityId() {
return this.supportedEntityId;
}
@@ -177,7 +185,7 @@ public class CommandWrapper {
public boolean isUpdateRolePermissions() {
return this.actionName.equalsIgnoreCase("PERMISSIONS") && this.entityId != null;
}
public boolean isConfigurationResource() {
return this.entityName.equalsIgnoreCase("CONFIGURATION");
}
@@ -205,27 +213,27 @@ public class CommandWrapper {
public boolean isCodeValueResource() {
return this.entityName.equalsIgnoreCase("CODEVALUE");
}
public boolean isStaffResource() {
return this.entityName.equalsIgnoreCase("STAFF");
}
public boolean isGuarantorResource() {
return this.entityName.equalsIgnoreCase("GUARANTOR");
}
public boolean isGLAccountResource() {
return this.entityName.equalsIgnoreCase("GLACCOUNT");
}
public boolean isGLClosureResource() {
return this.entityName.equalsIgnoreCase("GLCLOSURE");
}
public boolean isJournalEntryResource() {
return this.entityName.equalsIgnoreCase("JOURNALENTRY");
}
public boolean isRevertJournalEntry() {
return this.actionName.equalsIgnoreCase("REVERSE") && this.entityName.equalsIgnoreCase("JOURNALENTRY");
}
@@ -265,7 +273,7 @@ public class CommandWrapper {
public boolean isLoanResource() {
return this.entityName.equalsIgnoreCase("LOAN");
}
public boolean isLoanChargeResource() {
return this.entityName.equalsIgnoreCase("LOANCHARGE");
}
@@ -341,7 +349,7 @@ public class CommandWrapper {
public boolean isRemoveLoanOfficer() {
return this.actionName.equalsIgnoreCase("REMOVELOANOFFICER") && this.entityName.equalsIgnoreCase("LOAN");
}
public boolean isBulkUpdateLoanOfficer() {
return this.actionName.equalsIgnoreCase("BULKREASSIGN") && this.entityName.equalsIgnoreCase("LOAN");
}
@@ -354,7 +362,7 @@ public class CommandWrapper {
/* also covers case of deleting all of a one to many*/
return isDatatableResource() && isDeleteOperation() && this.subentityId == null;
}
public boolean isDeleteMultiple() {
return isDatatableResource() && isDeleteOperation() && this.subentityId != null;
}
@@ -362,7 +370,7 @@ public class CommandWrapper {
public boolean isUpdateOneToOne() {
return isDatatableResource() && isUpdateOperation() && this.subentityId == null;
}
public boolean isUpdateMultiple() {
return isDatatableResource() && isUpdateOperation() && this.subentityId != null;
}
@@ -370,7 +378,7 @@ public class CommandWrapper {
public boolean isUnassignStaff() {
return this.actionName.equalsIgnoreCase("UNASSIGNSTAFF") && this.entityName.equalsIgnoreCase("GROUP");
}
public String commandName() {
return this.actionName + "_" + this.entityName;
}
@@ -379,96 +387,74 @@ public class CommandWrapper {
return this.isUserResource() && isUpdate() && loggedInUserId.equals(this.entityId);
}
public boolean isDepositProductResource() {
return this.entityName.equalsIgnoreCase("DEPOSITPRODUCT");
}
public boolean isDepositProductResource() {
return this.entityName.equalsIgnoreCase("DEPOSITPRODUCT");
}
public boolean isDepositAccountResource() {
return this.entityName.equalsIgnoreCase("DEPOSITACCOUNT");
}
public boolean isDepositAccountResource() {
return this.entityName.equalsIgnoreCase("DEPOSITACCOUNT");
}
public boolean isApprovalOfDeposit() {
return this.actionName.equalsIgnoreCase("APPROVE") && this.entityName.equalsIgnoreCase("DEPOSITACCOUNT");
}
public boolean isApprovalOfDeposit() {
return this.actionName.equalsIgnoreCase("APPROVE") && this.entityName.equalsIgnoreCase("DEPOSITACCOUNT");
}
public boolean isWithdrawDepositAmount() {
return this.actionName.equalsIgnoreCase("WITHDRAWAL") && this.entityName.equalsIgnoreCase("DEPOSITACCOUNT");
}
public boolean isWithdrawDepositAmount() {
return this.actionName.equalsIgnoreCase("WITHDRAWAL") && this.entityName.equalsIgnoreCase("DEPOSITACCOUNT");
}
public boolean isWithdrawInterest() {
return this.actionName.equalsIgnoreCase("INTEREST") && this.entityName.equalsIgnoreCase("DEPOSITACCOUNT");
}
public boolean isWithdrawInterest() {
return this.actionName.equalsIgnoreCase("INTEREST") && this.entityName.equalsIgnoreCase("DEPOSITACCOUNT");
}
public boolean isRenewOfDepositApplicaion() {
return this.actionName.equalsIgnoreCase("RENEW") && this.entityName.equalsIgnoreCase("DEPOSITACCOUNT");
}
public boolean isRenewOfDepositApplicaion() {
return this.actionName.equalsIgnoreCase("RENEW") && this.entityName.equalsIgnoreCase("DEPOSITACCOUNT");
}
public boolean isRejectionOfDepositApplicaion() {
return this.actionName.equalsIgnoreCase("REJECT") && this.entityName.equalsIgnoreCase("DEPOSITACCOUNT");
}
public boolean isRejectionOfDepositApplicaion() {
return this.actionName.equalsIgnoreCase("REJECT") && this.entityName.equalsIgnoreCase("DEPOSITACCOUNT");
}
public boolean isWithdrawByApplicant() {
return this.actionName.equalsIgnoreCase("WITHDRAW") && this.entityName.equalsIgnoreCase("DEPOSITACCOUNT");
}
public boolean isWithdrawByApplicant() {
return this.actionName.equalsIgnoreCase("WITHDRAW") && this.entityName.equalsIgnoreCase("DEPOSITACCOUNT");
}
public boolean isUndoApprovalOfDepositApplication() {
return this.actionName.equalsIgnoreCase("APPROVALUNDO") && this.entityName.equalsIgnoreCase("DEPOSITACCOUNT");
}
public boolean isUndoApprovalOfDepositApplication() {
return this.actionName.equalsIgnoreCase("APPROVALUNDO") && this.entityName.equalsIgnoreCase("DEPOSITACCOUNT");
}
public boolean isSavingProductResource() {
return this.entityName.equalsIgnoreCase("SAVINGSPRODUCT");
}
public boolean isSavingsProductResource() {
return this.entityName.equalsIgnoreCase("SAVINGSPRODUCT");
}
public boolean isSavingAccountResource() {
return this.entityName.equalsIgnoreCase("SAVINGSACCOUNT");
}
public boolean isSavingsAccountResource() {
return this.entityName.equalsIgnoreCase("SAVINGSACCOUNT");
}
public boolean isApprovalOfSaving() {
return this.actionName.equalsIgnoreCase("APPROVE") && this.entityName.equalsIgnoreCase("SAVINGSACCOUNT");
}
public boolean isSavingsAccountDeposit() {
return this.actionName.equalsIgnoreCase("DEPOSIT") && this.entityName.equalsIgnoreCase("SAVINGSACCOUNT");
}
public boolean isSavingAccountDeposit() {
return this.actionName.equalsIgnoreCase("DEPOSIT") && this.entityName.equalsIgnoreCase("SAVINGSACCOUNT");
}
public boolean isSavingsAccountWithdrawal() {
return this.actionName.equalsIgnoreCase("WITHDRAWAL") && this.entityName.equalsIgnoreCase("SAVINGSACCOUNT");
}
public boolean isRejectOfSavingAccount() {
return this.actionName.equalsIgnoreCase("REJECT") && this.entityName.equalsIgnoreCase("SAVINGSACCOUNT");
}
public boolean isWithdrawSavingAmount() {
return this.actionName.equalsIgnoreCase("WITHDRAWAL") && this.entityName.equalsIgnoreCase("SAVINGSACCOUNT");
}
public boolean isWithdrawOfSavingApplicatin() {
return this.actionName.equalsIgnoreCase("WITHDRAW") && this.entityName.equalsIgnoreCase("SAVINGSACCOUNT");
}
public boolean isUndoApprovalOfSavingAccount() {
return this.actionName.equalsIgnoreCase("APPROVALUNDO") && this.entityName.equalsIgnoreCase("SAVINGSACCOUNT");
}
public boolean isCalendarResource() {
return this.entityName.equalsIgnoreCase("CALENDAR");
}
public boolean isNoteResource() {
boolean isnoteResource = false;
if(this.entityName.equalsIgnoreCase("CLIENTNOTE") ||
this.entityName.equalsIgnoreCase("LOANNOTE") ||
this.entityName.equalsIgnoreCase("LOANTRANSACTIONNOTE") ||
this.entityName.equalsIgnoreCase("DEPOSITNOTE") ||
this.entityName.equalsIgnoreCase("SAVINGNOTE") ||
this.entityName.equalsIgnoreCase("GROUPNOTE")){
if (this.entityName.equalsIgnoreCase("CLIENTNOTE") || this.entityName.equalsIgnoreCase("LOANNOTE")
|| this.entityName.equalsIgnoreCase("LOANTRANSACTIONNOTE") || this.entityName.equalsIgnoreCase("DEPOSITNOTE")
|| this.entityName.equalsIgnoreCase("SAVINGNOTE") || this.entityName.equalsIgnoreCase("GROUPNOTE")) {
isnoteResource = true;
}
return isnoteResource;
}
public boolean isGroupResource() {
return this.entityName.equalsIgnoreCase("GROUP");
}
}
@@ -13,6 +13,7 @@ public class CommandWrapperBuilder {
private Long groupId;
private Long clientId;
private Long loanId;
private Long savingsId;
private String actionName;
private String entityName;
private Long entityId;
@@ -25,16 +26,11 @@ public class CommandWrapperBuilder {
private Long supportedEntityId;
public CommandWrapper build() {
return new CommandWrapper(this.officeId, this.groupId, this.clientId, this.loanId, this.actionName, this.entityName, this.entityId, this.subentityId,
this.codeId, this.supportedEntityType, this.supportedEntityId, this.href, this.json,
this.transactionId);
return new CommandWrapper(this.officeId, this.groupId, this.clientId, this.loanId, this.savingsId, this.actionName,
this.entityName, this.entityId, this.subentityId, this.codeId, this.supportedEntityType, this.supportedEntityId, this.href,
this.json, this.transactionId);
}
// public CommandWrapperBuilder withEntityId(final Long withId) {
// this.entityId = withId;
// return this;
// }
public CommandWrapperBuilder withLoanId(final Long withLoanId) {
this.loanId = withLoanId;
return this;
@@ -325,7 +321,7 @@ public class CommandWrapperBuilder {
return this;
}
public CommandWrapperBuilder createDatatable(final String datatable, final Long apptableId, final Long datatableId) {
public CommandWrapperBuilder createDatatable(final String datatable, final Long apptableId, final Long datatableId) {
this.actionName = "CREATE";
commonDatatableSettings(datatable, apptableId, datatableId);
return this;
@@ -343,9 +339,8 @@ public class CommandWrapperBuilder {
return this;
}
private void commonDatatableSettings(final String datatable, final Long apptableId, final Long datatableId) {
this.entityName = datatable;
this.entityId = apptableId;
this.subentityId = datatableId;
@@ -355,8 +350,7 @@ public class CommandWrapperBuilder {
this.href = "/datatables/" + datatable + "/" + apptableId + "/" + datatableId;
}
}
public CommandWrapperBuilder createLoanCharge(final Long loanId) {
this.actionName = "CREATE";
this.entityName = "LOANCHARGE";
@@ -644,110 +638,6 @@ public class CommandWrapperBuilder {
return this;
}
public CommandWrapperBuilder createDepositProduct() {
this.actionName = "CREATE";
this.entityName = "DEPOSITPRODUCT";
this.entityId = null;
this.href = "/depositproducts/template";
return this;
}
public CommandWrapperBuilder updateDepositProduct(final Long productId) {
this.actionName = "UPDATE";
this.entityName = "DEPOSITPRODUCT";
this.entityId = 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";
this.entityName = "DEPOSITACCOUNT";
this.entityId = null;
this.href = "/depositaccounts/template";
return this;
}
public CommandWrapperBuilder updateDepositAccount(final Long accountId) {
this.actionName = "UPDATE";
this.entityName = "DEPOSITACCOUNT";
this.entityId = accountId;
this.href = "/depositaccounts/" + accountId;
return this;
}
public CommandWrapperBuilder deleteDepositAccount(final Long accountId) {
this.actionName = "DELETE";
this.entityName = "DEPOSITACCOUNT";
this.entityId = accountId;
this.href = "/depositaccounts/" + accountId;
return this;
}
public CommandWrapperBuilder approveDepositApplication(final Long accountId) {
this.actionName = "APPROVE";
this.entityName = "DEPOSITACCOUNT";
this.entityId = accountId;
this.href = "/depositaccounts/" + accountId;
return this;
}
public CommandWrapperBuilder withdrawDepositAmount(final Long accountId) {
this.actionName = "WITHDRAWAL";
this.entityName = "DEPOSITACCOUNT";
this.entityId = accountId;
this.href = "/depositaccounts/" + accountId;
return this;
}
public CommandWrapperBuilder withdrawInterestDepositAmount(final Long accountId) {
this.actionName = "INTEREST";
this.entityName = "DEPOSITACCOUNT";
this.entityId = accountId;
this.href = "/depositaccounts/" + accountId;
return this;
}
public CommandWrapperBuilder renewDepositAccount(final Long accountId) {
this.actionName = "RENEW";
this.entityName = "DEPOSITACCOUNT";
this.entityId = accountId;
this.href = "/depositaccounts/" + accountId;
return this;
}
public CommandWrapperBuilder rejectDepositAccount(final Long accountId) {
this.actionName = "REJECT";
this.entityName = "DEPOSITACCOUNT";
this.entityId = accountId;
this.href = "/depositaccounts/" + accountId;
return this;
}
public CommandWrapperBuilder withdrawDepositApplication(final Long accountId) {
this.actionName = "WITHDRAW";
this.entityName = "DEPOSITACCOUNT";
this.entityId = accountId;
this.href = "/depositaccounts/" + accountId;
return this;
}
public CommandWrapperBuilder undoDepositApplicationApproval(final Long accountId) {
this.actionName = "APPROVALUNDO";
this.entityName = "DEPOSITACCOUNT";
this.entityId = accountId;
this.href = "/depositaccounts/" + accountId;
return this;
}
public CommandWrapperBuilder createSavingProduct() {
this.actionName = "CREATE";
this.entityName = "SAVINGSPRODUCT";
@@ -796,19 +686,21 @@ public class CommandWrapperBuilder {
return this;
}
public CommandWrapperBuilder depositOfSavingAmount(final Long accountId) {
public CommandWrapperBuilder savingsAccountDeposit(final Long accountId) {
this.actionName = "DEPOSIT";
this.entityName = "SAVINGSACCOUNT";
this.entityId = accountId;
this.href = "/savingsaccounts/" + accountId;
this.loanId = accountId;
this.entityId = null;
this.href = "/savingsaccounts/" + accountId + "/transactions";
return this;
}
public CommandWrapperBuilder withdrawSavingAmount(final Long accountId) {
public CommandWrapperBuilder savingsAccountWithdrawal(final Long accountId) {
this.actionName = "WITHDRAWAL";
this.entityName = "SAVINGSACCOUNT";
this.entityId = accountId;
this.href = "/savingsaccounts/" + accountId;
this.loanId = accountId;
this.entityId = null;
this.href = "/savingsaccounts/" + accountId + "/transactions";
return this;
}
@@ -40,15 +40,18 @@ public class PortfolioCommandSourceWritePlatformServiceImpl implements Portfolio
@Override
public CommandProcessingResult logCommandSource(final CommandWrapper wrapper) {
boolean isApprovedByChecker = false;
// check if is update of own account details
if (wrapper.isUpdateOfOwnUserDetails(context.authenticatedUser().getId())) {
// then allow this operation to proceed.
// maker checker doesnt mean anything here.
isApprovedByChecker = true; // set to true in case permissions have been maker-checker enabled by accident.
isApprovedByChecker = true; // set to true in case permissions have
// been maker-checker enabled by
// accident.
} else {
// if not user changing their own details - check user has permission to perform specific task.
// if not user changing their own details - check user has
// permission to perform specific task.
context.authenticatedUser().validateHasPermissionTo(wrapper.getTaskPermissionName());
}
@@ -57,7 +60,9 @@ public class PortfolioCommandSourceWritePlatformServiceImpl implements Portfolio
try {
final JsonElement parsedCommand = this.fromApiJsonHelper.parse(json);
final JsonCommand command = JsonCommand.from(json, parsedCommand, this.fromApiJsonHelper, wrapper.getEntityName(),
wrapper.getEntityId(), wrapper.getSubentityId(), wrapper.getGroupId(), wrapper.getClientId(), wrapper.getLoanId(), wrapper.getCodeId(), wrapper.getSupportedEntityType(), wrapper.getSupportedEntityId(), wrapper.getTransactionId());
wrapper.getEntityId(), wrapper.getSubentityId(), wrapper.getGroupId(), wrapper.getClientId(), wrapper.getLoanId(),
wrapper.getSavingsId(), wrapper.getCodeId(), wrapper.getSupportedEntityType(), wrapper.getSupportedEntityId(),
wrapper.getTransactionId());
result = this.processAndLogCommandService.processAndLogCommand(wrapper, command, isApprovedByChecker);
} catch (RollbackTransactionAsCommandIsNotApprovedByCheckerException e) {
@@ -67,7 +72,9 @@ public class PortfolioCommandSourceWritePlatformServiceImpl implements Portfolio
final JsonElement parsedCommand = this.fromApiJsonHelper.parse(jsonToUse);
final JsonCommand command = JsonCommand.from(jsonToUse, parsedCommand, this.fromApiJsonHelper, wrapper.getEntityName(),
wrapper.getEntityId(), wrapper.getSubentityId(), wrapper.getGroupId(), wrapper.getClientId(), wrapper.getLoanId(), wrapper.getCodeId(), wrapper.getSupportedEntityType(), wrapper.getSupportedEntityId(), wrapper.getTransactionId());
wrapper.getEntityId(), wrapper.getSubentityId(), wrapper.getGroupId(), wrapper.getClientId(), wrapper.getLoanId(),
wrapper.getSavingsId(), wrapper.getCodeId(), wrapper.getSupportedEntityType(), wrapper.getSupportedEntityId(),
wrapper.getTransactionId());
result = this.processAndLogCommandService.logCommand(wrapper, command);
}
@@ -83,11 +90,13 @@ public class PortfolioCommandSourceWritePlatformServiceImpl implements Portfolio
context.authenticatedUser().validateHasCheckerPermissionTo(commandSourceInput.getPermissionCode());
final CommandWrapper wrapper = CommandWrapper.fromExistingCommand(commandId, commandSourceInput.getActionName(),
commandSourceInput.getEntityName(), commandSourceInput.resourceId(), commandSourceInput.subresourceId(), commandSourceInput.getResourceGetUrl());
commandSourceInput.getEntityName(), commandSourceInput.resourceId(), commandSourceInput.subresourceId(),
commandSourceInput.getResourceGetUrl());
final JsonElement parsedCommand = this.fromApiJsonHelper.parse(commandSourceInput.json());
final JsonCommand command = JsonCommand.fromExistingCommand(commandId, commandSourceInput.json(), parsedCommand,
this.fromApiJsonHelper, commandSourceInput.getEntityName(), commandSourceInput.resourceId(), commandSourceInput.subresourceId());
this.fromApiJsonHelper, commandSourceInput.getEntityName(), commandSourceInput.resourceId(),
commandSourceInput.subresourceId());
final boolean makerCheckerApproval = true;
return this.processAndLogCommandService.processAndLogCommand(wrapper, command, makerCheckerApproval);
@@ -338,43 +338,9 @@ public class SynchronousCommandProcessingService implements CommandProcessingSer
handler = applicationContext.getBean("reverseJournalEntryCommandHandler", NewCommandSourceHandler.class);
} else {
throw new UnsupportedCommandException(wrapper.commandName());
}
} else if (wrapper.isDepositProductResource()) {
if (wrapper.isCreate()) {
handler = applicationContext.getBean("createDepositProductCommandHandler", NewCommandSourceHandler.class);
} else if (wrapper.isUpdate()) {
handler = applicationContext.getBean("updateDepositProductCommandHandler", NewCommandSourceHandler.class);
} else if (wrapper.isDelete()) {
handler = applicationContext.getBean("deleteDepositProductCommandHandler", NewCommandSourceHandler.class);
} else {
throw new UnsupportedCommandException(wrapper.commandName());
}
} else if (wrapper.isDepositAccountResource()) {
if (wrapper.isCreate()) {
handler = applicationContext.getBean("createDepositAccountCommandHandler", NewCommandSourceHandler.class);
} else if (wrapper.isUpdate()) {
handler = applicationContext.getBean("updateDepositAccountCommandHandler", NewCommandSourceHandler.class);
} else if (wrapper.isDelete()) {
handler = applicationContext.getBean("deleteDepositAccountCommandHandler", NewCommandSourceHandler.class);
} else if (wrapper.isApprovalOfDeposit()) {
handler = applicationContext.getBean("approveDepositAccountCommandHandler", NewCommandSourceHandler.class);
} else if (wrapper.isWithdrawDepositAmount()) {
handler = applicationContext.getBean("withdrawDepositAccountAmountCommandHandler", NewCommandSourceHandler.class);
} else if (wrapper.isWithdrawInterest()) {
handler = applicationContext.getBean("withdrawInterestDepositAccountAmountCommandHandler", NewCommandSourceHandler.class);
} else if (wrapper.isRenewOfDepositApplicaion()) {
handler = applicationContext.getBean("renewDepositAccountCommandHandler", NewCommandSourceHandler.class);
} else if (wrapper.isRejectionOfDepositApplicaion()) {
handler = applicationContext.getBean("rejectDepositAccountCommandHandler", NewCommandSourceHandler.class);
} else if (wrapper.isWithdrawByApplicant()) {
handler = applicationContext.getBean("withDrawByApplicantDepositAccountCommandHandler", NewCommandSourceHandler.class);
} else if (wrapper.isUndoApprovalOfDepositApplication()) {
handler = applicationContext.getBean("undoApprovalDepositAccountCommandHandler", NewCommandSourceHandler.class);
} else {
throw new UnsupportedCommandException(wrapper.commandName());
}
} else if (wrapper.isSavingProductResource()) {
if (wrapper.isCreate()) {
} else if (wrapper.isSavingsProductResource()) {
if (wrapper.isCreate()) {
handler = applicationContext.getBean("createSavingsProductCommandHandler", NewCommandSourceHandler.class);
} else if (wrapper.isUpdate()) {
handler = applicationContext.getBean("updateSavingsProductCommandHandler", NewCommandSourceHandler.class);
@@ -383,13 +349,17 @@ public class SynchronousCommandProcessingService implements CommandProcessingSer
} else {
throw new UnsupportedCommandException(wrapper.commandName());
}
} else if (wrapper.isSavingAccountResource()) {
if (wrapper.isCreate()) {
} else if (wrapper.isSavingsAccountResource()) {
if (wrapper.isCreate()) {
handler = applicationContext.getBean("createSavingsAccountCommandHandler", NewCommandSourceHandler.class);
} else if (wrapper.isUpdate()) {
handler = applicationContext.getBean("updateSavingsAccountCommandHandler", NewCommandSourceHandler.class);
} else if (wrapper.isDelete()) {
handler = applicationContext.getBean("deleteSavingsAccountCommandHandler", NewCommandSourceHandler.class);
} else if (wrapper.isSavingsAccountDeposit()) {
handler = applicationContext.getBean("depositSavingsAccountCommandHandler", NewCommandSourceHandler.class);
} else if (wrapper.isSavingsAccountWithdrawal()) {
handler = applicationContext.getBean("withdrawSavingsAccountCommandHandler", NewCommandSourceHandler.class);
} else {
throw new UnsupportedCommandException(wrapper.commandName());
}
@@ -415,7 +385,7 @@ public class SynchronousCommandProcessingService implements CommandProcessingSer
} else {
throw new UnsupportedCommandException(wrapper.commandName());
}
} else {
throw new UnsupportedCommandException(wrapper.commandName());
}
@@ -37,6 +37,7 @@ public final class JsonCommand {
private final Long groupId;
private final Long clientId;
private final Long loanId;
private final Long savingsId;
private final String entityName;
private final Long codeId;
private final String supportedEntityType;
@@ -44,22 +45,22 @@ public final class JsonCommand {
private final String transactionId;
public static JsonCommand from(final String jsonCommand, final JsonElement parsedCommand, final FromJsonHelper fromApiJsonHelper,
final String entityName, final Long resourceId, final Long subresourceId, final Long groupId, final Long clientId, final Long loanId,
final Long codeId, final String supportedEntityType,
final Long supportedEntityId, final String transactionId) {
return new JsonCommand(null, jsonCommand, parsedCommand, fromApiJsonHelper, entityName, resourceId, subresourceId, groupId, clientId, loanId,
codeId, supportedEntityType, supportedEntityId, transactionId);
final String entityName, final Long resourceId, final Long subresourceId, final Long groupId, final Long clientId,
final Long loanId, final Long savingsId, final Long codeId, final String supportedEntityType, final Long supportedEntityId,
final String transactionId) {
return new JsonCommand(null, jsonCommand, parsedCommand, fromApiJsonHelper, entityName, resourceId, subresourceId, groupId,
clientId, loanId, savingsId, codeId, supportedEntityType, supportedEntityId, transactionId);
}
public static JsonCommand fromExistingCommand(final Long commandId, final String jsonCommand, final JsonElement parsedCommand,
final FromJsonHelper fromApiJsonHelper, final String entityName, final Long resourceId, final Long subresourceId) {
return new JsonCommand(commandId, jsonCommand, parsedCommand, fromApiJsonHelper, entityName, resourceId, subresourceId, null, null, null, null,
null, null, null);
return new JsonCommand(commandId, jsonCommand, parsedCommand, fromApiJsonHelper, entityName, resourceId, subresourceId, null, null,
null, null, null, null, null, null);
}
public JsonCommand(final Long commandId, final String jsonCommand, final JsonElement parsedCommand,
final FromJsonHelper fromApiJsonHelper, final String entityName, final Long resourceId, final Long subresourceId, final Long groupId,
final Long clientId, final Long loanId, final Long codeId,
final FromJsonHelper fromApiJsonHelper, final String entityName, final Long resourceId, final Long subresourceId,
final Long groupId, final Long clientId, final Long loanId, final Long savingsId, final Long codeId,
final String supportedEntityType, final Long supportedEntityId, final String transactionId) {
this.commandId = commandId;
this.jsonCommand = jsonCommand;
@@ -71,6 +72,7 @@ public final class JsonCommand {
this.groupId = groupId;
this.clientId = clientId;
this.loanId = loanId;
this.savingsId = savingsId;
this.codeId = codeId;
this.supportedEntityType = supportedEntityType;
this.supportedEntityId = supportedEntityId;
@@ -105,7 +107,7 @@ public final class JsonCommand {
public Long entityId() {
return this.resourceId;
}
public Long subentityId() {
return this.subresourceId;
}
@@ -122,6 +124,10 @@ public final class JsonCommand {
return this.loanId;
}
public Long getSavingsId() {
return this.savingsId;
}
public Long getCodeId() {
return this.codeId;
}
@@ -19,6 +19,7 @@ public class CommandProcessingResult {
private final Long groupId;
private final Long clientId;
private final Long loanId;
private final Long savingsId;
private final Long resourceId;
private final String transactionId;
private final Map<String, Object> changes;
@@ -26,10 +27,10 @@ public class CommandProcessingResult {
private final String resourceIdentifier;
public static CommandProcessingResult fromDetails(final Long commandId, final Long officeId, final Long groupId, final Long clientId,
final Long loanId, final String resourceIdentifier, final Long entityId, final String transactionId,
final Long loanId, final Long savingsId, final String resourceIdentifier, final Long entityId, final String transactionId,
final Map<String, Object> changes) {
return new CommandProcessingResult(commandId, officeId, groupId, clientId, loanId, resourceIdentifier, entityId, transactionId,
changes);
return new CommandProcessingResult(commandId, officeId, groupId, clientId, loanId, savingsId, resourceIdentifier, entityId,
transactionId, changes);
}
public static CommandProcessingResult commandOnlyResult(final Long commandId) {
@@ -75,17 +76,20 @@ public class CommandProcessingResult {
this.groupId = null;
this.clientId = null;
this.loanId = null;
this.savingsId = null;
this.transactionId = null;
this.changes = new HashMap<String, Object>();
}
private CommandProcessingResult(final Long commandId, final Long officeId, final Long groupId, final Long clientId, final Long loanId,
final String resourceIdentifier, final Long resourceId, final String transactionId, final Map<String, Object> changesOnly) {
final Long savingsId, final String resourceIdentifier, final Long resourceId, final String transactionId,
final Map<String, Object> changesOnly) {
this.commandId = commandId;
this.officeId = officeId;
this.groupId = groupId;
this.clientId = clientId;
this.loanId = loanId;
this.savingsId = savingsId;
this.resourceIdentifier = resourceIdentifier;
this.resourceId = resourceId;
this.changes = changesOnly;
@@ -103,6 +107,7 @@ public class CommandProcessingResult {
this.groupId = null;
this.clientId = null;
this.loanId = null;
this.savingsId = null;
this.transactionId = null;
this.commandId = commandId;
this.changes = changesOnly;
@@ -136,6 +141,10 @@ public class CommandProcessingResult {
return this.loanId;
}
public Long getSavingsId() {
return this.savingsId;
}
public String getTransactionId() {
return this.transactionId;
}
@@ -18,13 +18,14 @@ public class CommandProcessingResultBuilder {
private Long groupId;
private Long clientId;
private Long loanId;
private Long savingsId;
private String resourceIdentifier;
private Long entityId;
private String transactionId;
private Map<String, Object> changes;
public CommandProcessingResult build() {
return CommandProcessingResult.fromDetails(commandId, officeId, groupId, clientId, loanId, resourceIdentifier, entityId,
return CommandProcessingResult.fromDetails(commandId, officeId, groupId, clientId, loanId, savingsId, resourceIdentifier, entityId,
transactionId, changes);
}
@@ -68,6 +69,11 @@ public class CommandProcessingResultBuilder {
return this;
}
public CommandProcessingResultBuilder withSavingsId(final Long withSavingsId) {
this.savingsId = withSavingsId;
return this;
}
public CommandProcessingResultBuilder withTransactionId(final String withTransactionId) {
this.transactionId = withTransactionId;
return this;
@@ -67,7 +67,7 @@ public class JdbcSupport {
private static BigDecimal defaultToNullIfZero(final BigDecimal value) {
BigDecimal result = value;
if (BigDecimal.ZERO.compareTo(value) == 0) {
if (value != null && BigDecimal.ZERO.compareTo(value) == 0) {
result = null;
}
return result;
@@ -15,7 +15,7 @@ public abstract class AbstractPlatformDomainRuleException extends RuntimeExcepti
private final String defaultUserMessage;
private final Object[] defaultUserMessageArgs;
public AbstractPlatformDomainRuleException(String globalisationMessageCode, String defaultUserMessage, Object... defaultUserMessageArgs) {
public AbstractPlatformDomainRuleException(final String globalisationMessageCode, final String defaultUserMessage, final Object... defaultUserMessageArgs) {
this.globalisationMessageCode = globalisationMessageCode;
this.defaultUserMessage = defaultUserMessage;
this.defaultUserMessageArgs = defaultUserMessageArgs;
@@ -10,7 +10,7 @@ public class UnrecognizedQueryParamException extends RuntimeException {
private final String queryParamKey;
private final String queryParamValue;
public UnrecognizedQueryParamException(String queryParamKey, String queryParamValue) {
public UnrecognizedQueryParamException(final String queryParamKey, final String queryParamValue) {
this.queryParamKey = queryParamKey;
this.queryParamValue = queryParamValue;
}
@@ -93,8 +93,8 @@ public class Money implements Comparable<Money> {
}
public Money plus(final BigDecimal amountToAdd) {
if (amountToAdd.compareTo(BigDecimal.ZERO) == 0) { return this; }
BigDecimal newAmount = this.amount.add(amountToAdd);
if (amountToAdd == null || amountToAdd.compareTo(BigDecimal.ZERO) == 0) { return this; }
final BigDecimal newAmount = this.amount.add(amountToAdd);
return Money.of(monetaryCurrency(), newAmount);
}
@@ -110,8 +110,8 @@ public class Money implements Comparable<Money> {
}
public Money minus(final BigDecimal amountToSubtract) {
if (amountToSubtract.compareTo(BigDecimal.ZERO) == 0) { return this; }
BigDecimal newAmount = this.amount.subtract(amountToSubtract);
if (amountToSubtract == null || amountToSubtract.compareTo(BigDecimal.ZERO) == 0) { return this; }
final BigDecimal newAmount = this.amount.subtract(amountToSubtract);
return Money.of(monetaryCurrency(), newAmount);
}
@@ -223,6 +223,18 @@ public class Money implements Comparable<Money> {
return this.amount;
}
public BigDecimal getAmountDefaultedToNullIfZero() {
return defaultToNullIfZero(this.amount);
}
private static BigDecimal defaultToNullIfZero(final BigDecimal value) {
BigDecimal result = value;
if (value != null && BigDecimal.ZERO.compareTo(value) == 0) {
result = null;
}
return result;
}
@Override
public String toString() {
return new StringBuilder().append(this.currencyCode).append(' ').append(this.amount.toPlainString()).toString();
@@ -114,19 +114,6 @@ public class ClientAccountSummaryCollectionData {
this.anyLoanCount = countOf(this.pendingApprovalLoanCount, this.awaitingDisbursalLoanCount, this.activeLoanCount,
this.closedLoanCount);
//
// , this.pendingApprovalDepositAccountsCount,
// this.approvedDepositAccountsCount
// , this.withdrawnByClientDepositAccountsCount,
// this.closedDepositAccountsCount, this.rejectedDepositAccountsCount
// , this.preclosedDepositAccountsCount,
// this.maturedDepositAccountsCount,
// this.pendingApprovalSavingAccountsCount
// , this.approvedSavingAccountsCount,
// this.withdrawnByClientSavingAccountsCount,
// this.rejectedSavingAccountsCount
// , this.closedSavingAccountsCount);
}
private Integer countOf(final Integer... objects) {
@@ -240,71 +240,24 @@ 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);
// }
// }
// }
List<ClientAccountSummaryData> pendingApprovalSavingAccounts = new ArrayList<ClientAccountSummaryData>();
List<ClientAccountSummaryData> approvedSavingAccounts = new ArrayList<ClientAccountSummaryData>();
List<ClientAccountSummaryData> withdrawnByClientSavingAccounts = new ArrayList<ClientAccountSummaryData>();
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);
// }
// }
final ClientSavingsAccountSummaryDataMapper savingsAccountSummaryDataMapper = new ClientSavingsAccountSummaryDataMapper();
final String savingsSql = "select " + savingsAccountSummaryDataMapper.schema() + " where sa.client_id = ?";
final List<ClientAccountSummaryData> savingsAccounts = this.jdbcTemplate.query(savingsSql, savingsAccountSummaryDataMapper,
new Object[] { clientId });
approvedSavingAccounts.addAll(savingsAccounts);
return new ClientAccountSummaryCollectionData(pendingApprovalLoans, awaitingDisbursalLoans, openLoans, closedLoans,
pendingApprovalDepositAccounts, approvedDepositAccounts, withdrawnByClientDespositAccounts, rejectedDepositAccounts,
closedDepositAccounts, preclosedDepositAccounts, maturedDepositAccounts, pendingApprovalSavingAccounts,
approvedSavingAccounts, withdrawnByClientSavingAccounts, rejectedSavingAccounts, closedSavingAccounts);
} catch (EmptyResultDataAccessException e) {
throw new ClientNotFoundException(clientId);
}
@@ -327,6 +280,38 @@ public class ClientReadPlatformServiceImpl implements ClientReadPlatformService
return loanAccounts;
}
private static final class ClientSavingsAccountSummaryDataMapper implements RowMapper<ClientAccountSummaryData> {
final String schemaSql;
public ClientSavingsAccountSummaryDataMapper() {
StringBuilder accountsSummary = new StringBuilder();
accountsSummary.append("sa.id as id, sa.account_no as accountNo, sa.external_id as externalId,");
accountsSummary.append("sa.product_id as productId, p.name as productName ");
accountsSummary.append("from m_savings_account sa ");
accountsSummary.append("join m_savings_product as p on p.id = sa.product_id ");
this.schemaSql = accountsSummary.toString();
}
public String schema() {
return this.schemaSql;
}
@Override
public ClientAccountSummaryData mapRow(final ResultSet rs, @SuppressWarnings("unused") final int rowNum) throws SQLException {
final Long id = JdbcSupport.getLong(rs, "id");
final String accountNo = rs.getString("accountNo");
final String externalId = rs.getString("externalId");
final Long productId = JdbcSupport.getLong(rs, "productId");
final String loanProductName = rs.getString("productName");
final LoanStatusEnumData loanStatus = null;
return new ClientAccountSummaryData(id, accountNo, externalId, productId, loanProductName, loanStatus);
}
}
private static final class ClientLoanAccountSummaryDataMapper implements RowMapper<ClientAccountSummaryData> {
public String loanAccountSummarySchema() {
@@ -0,0 +1,103 @@
/**
* 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 javax.ws.rs.Consumes;
import javax.ws.rs.GET;
import javax.ws.rs.POST;
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.ApiRequestParameterHelper;
import org.mifosplatform.infrastructure.core.data.CommandProcessingResult;
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.security.service.PlatformSecurityContext;
import org.mifosplatform.portfolio.savings.data.SavingsAccountTransactionData;
import org.mifosplatform.portfolio.savings.service.SavingsAccountReadPlatformService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Scope;
import org.springframework.stereotype.Component;
@Path("/savingsaccounts/{savingsId}/transactions")
@Component
@Scope("singleton")
public class SavingsAccountTransactionsApiResource {
private final PlatformSecurityContext context;
private final DefaultToApiJsonSerializer<SavingsAccountTransactionData> toApiJsonSerializer;
private final PortfolioCommandSourceWritePlatformService commandsSourceWritePlatformService;
private final ApiRequestParameterHelper apiRequestParameterHelper;
private final SavingsAccountReadPlatformService savingsAccountReadPlatformService;
@Autowired
public SavingsAccountTransactionsApiResource(final PlatformSecurityContext context,
final DefaultToApiJsonSerializer<SavingsAccountTransactionData> toApiJsonSerializer,
final PortfolioCommandSourceWritePlatformService commandsSourceWritePlatformService,
final ApiRequestParameterHelper apiRequestParameterHelper,
final SavingsAccountReadPlatformService savingsAccountReadPlatformService) {
this.context = context;
this.toApiJsonSerializer = toApiJsonSerializer;
this.commandsSourceWritePlatformService = commandsSourceWritePlatformService;
this.apiRequestParameterHelper = apiRequestParameterHelper;
this.savingsAccountReadPlatformService = savingsAccountReadPlatformService;
}
private boolean is(final String commandParam, final String commandValue) {
return StringUtils.isNotBlank(commandParam) && commandParam.trim().equalsIgnoreCase(commandValue);
}
@GET
@Path("template")
@Consumes({ MediaType.APPLICATION_JSON })
@Produces({ MediaType.APPLICATION_JSON })
public String retrieveTemplate(@PathParam("savingsId") final Long savingsId, @QueryParam("command") final String commandParam,
@Context final UriInfo uriInfo) {
context.authenticatedUser().validateHasReadPermission(SavingsApiConstants.SAVINGS_ACCOUNT_RESOURCE_NAME);
// FIXME - KW - for now just send back generic default information for
// both deposit/withdrawal templates
final SavingsAccountTransactionData savingsAccount = this.savingsAccountReadPlatformService
.retrieveDepositTransactionTemplate(savingsId);
final ApiRequestJsonSerializationSettings settings = apiRequestParameterHelper.process(uriInfo.getQueryParameters());
return this.toApiJsonSerializer.serialize(settings, savingsAccount,
SavingsApiConstants.SAVINGS_TRANSACTION_RESPONSE_DATA_PARAMETERS);
}
@POST
@Consumes({ MediaType.APPLICATION_JSON })
@Produces({ MediaType.APPLICATION_JSON })
public String transaction(@PathParam("savingsId") final Long savingsId, @QueryParam("command") final String commandParam,
final String apiRequestBodyAsJson) {
final CommandWrapperBuilder builder = new CommandWrapperBuilder().withJson(apiRequestBodyAsJson);
CommandProcessingResult result = null;
if (is(commandParam, "deposit")) {
final CommandWrapper commandRequest = builder.savingsAccountDeposit(savingsId).build();
result = this.commandsSourceWritePlatformService.logCommandSource(commandRequest);
} else if (is(commandParam, "withdrawal")) {
final CommandWrapper commandRequest = builder.savingsAccountWithdrawal(savingsId).build();
result = this.commandsSourceWritePlatformService.logCommandSource(commandRequest);
}
if (result == null) { throw new UnrecognizedQueryParamException("command", commandParam); }
return this.toApiJsonSerializer.serialize(result);
}
}
@@ -5,7 +5,10 @@
*/
package org.mifosplatform.portfolio.savings.api;
import java.util.Arrays;
import java.util.Collection;
import java.util.HashSet;
import java.util.Set;
import javax.ws.rs.Consumes;
import javax.ws.rs.DELETE;
@@ -23,6 +26,7 @@ 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.ApiParameterHelper;
import org.mifosplatform.infrastructure.core.api.ApiRequestParameterHelper;
import org.mifosplatform.infrastructure.core.data.CommandProcessingResult;
import org.mifosplatform.infrastructure.core.data.EnumOptionData;
@@ -30,6 +34,7 @@ import org.mifosplatform.infrastructure.core.serialization.ApiRequestJsonSeriali
import org.mifosplatform.infrastructure.core.serialization.DefaultToApiJsonSerializer;
import org.mifosplatform.infrastructure.security.service.PlatformSecurityContext;
import org.mifosplatform.portfolio.savings.data.SavingsAccountData;
import org.mifosplatform.portfolio.savings.data.SavingsAccountTransactionData;
import org.mifosplatform.portfolio.savings.data.SavingsProductData;
import org.mifosplatform.portfolio.savings.service.SavingsAccountReadPlatformService;
import org.mifosplatform.portfolio.savings.service.SavingsDropdownReadPlatformService;
@@ -37,6 +42,7 @@ import org.mifosplatform.portfolio.savings.service.SavingsProductReadPlatformSer
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Scope;
import org.springframework.stereotype.Component;
import org.springframework.util.CollectionUtils;
@Path("/savingsaccounts")
@Component
@@ -67,77 +73,6 @@ public class SavingsAccountsApiResource {
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 })
@@ -153,6 +88,101 @@ public class SavingsAccountsApiResource {
return this.toApiJsonSerializer.serialize(settings, savingsAccount, SavingsApiConstants.SAVINGS_ACCOUNT_RESPONSE_DATA_PARAMETERS);
}
@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);
}
@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);
}
@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);
final SavingsAccountData savingsAccount = this.savingsAccountReadPlatformService.retrieveOne(accountId);
final Set<String> mandatoryResponseParameters = new HashSet<String>();
SavingsAccountData savingsAccountTemplate = populateTemplateAndAssociations(accountId, savingsAccount, uriInfo,
mandatoryResponseParameters);
final ApiRequestJsonSerializationSettings settings = apiRequestParameterHelper.process(uriInfo.getQueryParameters(),
mandatoryResponseParameters);
return this.toApiJsonSerializer.serialize(settings, savingsAccountTemplate,
SavingsApiConstants.SAVINGS_ACCOUNT_RESPONSE_DATA_PARAMETERS);
}
private SavingsAccountData populateTemplateAndAssociations(final Long accountId, final SavingsAccountData savingsAccount,
final UriInfo uriInfo, final Set<String> mandatoryResponseParameters) {
Collection<SavingsAccountTransactionData> transactions = null;
Collection<SavingsProductData> productOptions = null;
Collection<EnumOptionData> interestRatePeriodFrequencyTypeOptions = null;
Collection<EnumOptionData> lockinPeriodFrequencyTypeOptions = null;
final Set<String> associationParameters = ApiParameterHelper.extractAssociationsForResponseIfProvided(uriInfo.getQueryParameters());
if (!associationParameters.isEmpty()) {
if (associationParameters.contains("all")) {
associationParameters.addAll(Arrays.asList("transactions"));
}
if (associationParameters.contains("transactions")) {
mandatoryResponseParameters.add("transactions");
final Collection<SavingsAccountTransactionData> currentTransactions = this.savingsAccountReadPlatformService
.retrieveAllTransactions(accountId);
if (!CollectionUtils.isEmpty(currentTransactions)) {
transactions = currentTransactions;
}
}
}
final ApiRequestJsonSerializationSettings settings = apiRequestParameterHelper.process(uriInfo.getQueryParameters());
if (settings.isTemplate()) {
productOptions = this.savingsProductReadPlatformService.retrieveAllForLookup();
interestRatePeriodFrequencyTypeOptions = this.dropdownReadPlatformService.retrieveInterestRatePeriodFrequencyTypeOptions();
lockinPeriodFrequencyTypeOptions = this.dropdownReadPlatformService.retrieveLockinPeriodFrequencyTypeOptions();
}
return SavingsAccountData.withTemplateOptions(savingsAccount, productOptions, interestRatePeriodFrequencyTypeOptions,
lockinPeriodFrequencyTypeOptions, transactions);
}
@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);
}
@DELETE
@Path("{accountId}")
@Consumes({ MediaType.APPLICATION_JSON })
@@ -11,8 +11,13 @@ 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 SAVINGS_ACCOUNT_TRANSACTION_RESOURCE_NAME = "savingsaccount.transaction";
// general
public static final String localeParamName = "locale";
public static final String dateFormatParamName = "dateFormat";
// savings product and account parameters
public static final String idParamName = "id";
public static final String accountNoParamName = "accountNo";
public static final String externalIdParamName = "externalId";
@@ -29,6 +34,10 @@ public class SavingsApiConstants {
public static final String lockinPeriodFrequencyParamName = "lockinPeriodFrequency";
public static final String lockinPeriodFrequencyTypeParamName = "lockinPeriodFrequencyType";
// transaction parameters
public static final String transactionDateParamName = "transactionDate";
public static final String transactionAmountParamName = "transactionAmount";
public static final Set<String> SAVINGS_PRODUCT_REQUEST_DATA_PARAMETERS = new HashSet<String>(Arrays.asList(localeParamName,
nameParamName, descriptionParamName, currencyCodeParamName, digitsAfterDecimalParamName, interestRateParamName,
interestRatePeriodFrequencyTypeParamName, minRequiredOpeningBalanceParamName, lockinPeriodFrequencyParamName,
@@ -60,4 +69,10 @@ public class SavingsApiConstants {
"savingsProductName", "currency", interestRateParamName, interestRatePeriodFrequencyTypeParamName, "annualInterestRate",
minRequiredOpeningBalanceParamName, lockinPeriodFrequencyParamName, lockinPeriodFrequencyTypeParamName, "productOptions",
"interestRatePeriodFrequencyTypeOptions", "lockinPeriodFrequencyTypeOptions"));
public static final Set<String> SAVINGS_ACCOUNT_TRANSACTION_REQUEST_DATA_PARAMETERS = new HashSet<String>(Arrays.asList(
localeParamName, dateFormatParamName, transactionDateParamName, transactionAmountParamName));
public static final Set<String> SAVINGS_TRANSACTION_RESPONSE_DATA_PARAMETERS = new HashSet<String>(Arrays.asList(idParamName,
"accountId", accountNoParamName, "currency", "amount"));
}
@@ -34,6 +34,10 @@ public class SavingsAccountData {
private final Integer lockinPeriodFrequency;
private final EnumOptionData lockinPeriodFrequencyType;
// associations
private final SavingsAccountSummaryData summary;
private final Collection<SavingsAccountTransactionData> transactions;
// template
private final Collection<SavingsProductData> productOptions;
private final Collection<EnumOptionData> interestRatePeriodFrequencyTypeOptions;
@@ -43,27 +47,28 @@ public class SavingsAccountData {
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 EnumOptionData lockinPeriodFrequencyType, final SavingsAccountSummaryData summary) {
final Collection<SavingsProductData> productOptions = null;
final Collection<EnumOptionData> interestRatePeriodFrequencyTypeOptions = null;
final Collection<EnumOptionData> lockinPeriodFrequencyTypeOptions = null;
final Collection<SavingsAccountTransactionData> transactions = null;
return new SavingsAccountData(id, accountNo, externalId, groupId, groupName, clientId, clientName, productId, productName,
currency, interestRate, interestRatePeriodFrequencyType, annualInterestRate, minRequiredOpeningBalance,
lockinPeriodFrequency, lockinPeriodFrequencyType, productOptions, interestRatePeriodFrequencyTypeOptions,
lockinPeriodFrequencyTypeOptions);
lockinPeriodFrequency, lockinPeriodFrequencyType, summary, productOptions, interestRatePeriodFrequencyTypeOptions,
lockinPeriodFrequencyTypeOptions, transactions);
}
public static SavingsAccountData withTemplateOptions(final SavingsAccountData account,
final Collection<SavingsProductData> productOptions, final Collection<EnumOptionData> interestRatePeriodFrequencyTypeOptions,
final Collection<EnumOptionData> lockinPeriodFrequencyTypeOptions) {
final Collection<EnumOptionData> lockinPeriodFrequencyTypeOptions, final Collection<SavingsAccountTransactionData> transactions) {
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);
account.minRequiredOpeningBalance, account.lockinPeriodFrequency, account.lockinPeriodFrequencyType, account.summary,
productOptions, interestRatePeriodFrequencyTypeOptions, lockinPeriodFrequencyTypeOptions, transactions);
}
public static SavingsAccountData withClientTemplate(final Long clientId, final String clientName, final Long groupId,
@@ -81,24 +86,26 @@ public class SavingsAccountData {
final BigDecimal minRequiredOpeningBalance = null;
final Integer lockinPeriodFrequency = null;
final EnumOptionData lockinPeriodFrequencyType = null;
final SavingsAccountSummaryData summary = null;
final Collection<SavingsProductData> productOptions = null;
final Collection<CurrencyData> currencyOptions = null;
final Collection<EnumOptionData> interestRatePeriodFrequencyTypeOptions = null;
final Collection<EnumOptionData> lockinPeriodFrequencyTypeOptions = null;
final Collection<SavingsAccountTransactionData> transactions = null;
return new SavingsAccountData(id, accountNo, externalId, groupId, groupName, clientId, clientName, productId, productName,
currency, interestRate, interestRatePeriodFrequencyType, annualInterestRate, minRequiredOpeningBalance,
lockinPeriodFrequency, lockinPeriodFrequencyType, productOptions, interestRatePeriodFrequencyTypeOptions,
lockinPeriodFrequencyTypeOptions);
lockinPeriodFrequency, lockinPeriodFrequencyType, summary, productOptions, interestRatePeriodFrequencyTypeOptions,
lockinPeriodFrequencyTypeOptions, transactions);
}
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) {
final EnumOptionData lockinPeriodFrequencyType, final SavingsAccountSummaryData summary,
final Collection<SavingsProductData> productOptions, final Collection<EnumOptionData> interestRatePeriodFrequencyTypeOptions,
final Collection<EnumOptionData> lockinPeriodFrequencyTypeOptions, final Collection<SavingsAccountTransactionData> transactions) {
this.id = id;
this.accountNo = accountNo;
this.externalId = externalId;
@@ -115,9 +122,11 @@ public class SavingsAccountData {
this.minRequiredOpeningBalance = minRequiredOpeningBalance;
this.lockinPeriodFrequency = lockinPeriodFrequency;
this.lockinPeriodFrequencyType = lockinPeriodFrequencyType;
this.summary = summary;
this.productOptions = productOptions;
this.interestRatePeriodFrequencyTypeOptions = interestRatePeriodFrequencyTypeOptions;
this.lockinPeriodFrequencyTypeOptions = lockinPeriodFrequencyTypeOptions;
this.transactions = transactions;
}
}
@@ -0,0 +1,32 @@
/**
* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this file,
* You can obtain one at http://mozilla.org/MPL/2.0/.
*/
package org.mifosplatform.portfolio.savings.data;
import java.math.BigDecimal;
import org.mifosplatform.organisation.monetary.data.CurrencyData;
/**
* Immutable data object representing loan summary information.
*/
@SuppressWarnings("unused")
public class SavingsAccountSummaryData {
private final CurrencyData currency;
private final BigDecimal totalDeposits;
private final BigDecimal totalWithdrawals;
private final BigDecimal totalInterestPosted;
private final BigDecimal accountBalance;
public SavingsAccountSummaryData(final CurrencyData currency, final BigDecimal totalDeposits, final BigDecimal totalWithdrawals,
final BigDecimal totalInterestPosted, final BigDecimal accountBalance) {
this.currency = currency;
this.totalDeposits = totalDeposits;
this.totalWithdrawals = totalWithdrawals;
this.totalInterestPosted = totalInterestPosted;
this.accountBalance = accountBalance;
}
}
@@ -0,0 +1,50 @@
/**
* 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 org.joda.time.LocalDate;
import org.mifosplatform.organisation.monetary.data.CurrencyData;
/**
* Immutable data object representing a savings account transaction.
*/
@SuppressWarnings("unused")
public class SavingsAccountTransactionData {
private final Long id;
private final SavingsAccountTransactionEnumData transactionType;
private final Long accountId;
private final String accountNo;
private final LocalDate date;
private final CurrencyData currency;
private final BigDecimal amount;
public static SavingsAccountTransactionData create(final Long id, final SavingsAccountTransactionEnumData transactionType,
final Long savingsId, final String savingsAccountNo, final LocalDate date, final CurrencyData currency, final BigDecimal amount) {
return new SavingsAccountTransactionData(id, transactionType, savingsId, savingsAccountNo, date, currency, amount);
}
public static SavingsAccountTransactionData template(final Long savingsId, final String savingsAccountNo,
final LocalDate defaultLocalDate, final CurrencyData currency) {
final Long id = null;
final SavingsAccountTransactionEnumData transactionType = null;
final BigDecimal amount = null;
return new SavingsAccountTransactionData(id, transactionType, savingsId, savingsAccountNo, defaultLocalDate, currency, amount);
}
private SavingsAccountTransactionData(final Long id, final SavingsAccountTransactionEnumData transactionType, final Long savingsId,
final String savingsAccountNo, final LocalDate date, final CurrencyData currency, final BigDecimal amount) {
this.id = id;
this.transactionType = transactionType;
this.accountId = savingsId;
this.accountNo = savingsAccountNo;
this.date = date;
this.currency = currency;
this.amount = amount;
}
}
@@ -0,0 +1,66 @@
package org.mifosplatform.portfolio.savings.data;
import static org.mifosplatform.portfolio.savings.api.SavingsApiConstants.transactionAmountParamName;
import static org.mifosplatform.portfolio.savings.api.SavingsApiConstants.transactionDateParamName;
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.joda.time.LocalDate;
import org.mifosplatform.infrastructure.core.api.JsonCommand;
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 SavingsAccountTransactionDataValidator {
private final FromJsonHelper fromApiJsonHelper;
@Autowired
public SavingsAccountTransactionDataValidator(final FromJsonHelper fromApiJsonHelper) {
this.fromApiJsonHelper = fromApiJsonHelper;
}
public void validate(final JsonCommand command) {
final String json = command.json();
if (StringUtils.isBlank(json)) { throw new InvalidJsonException(); }
final Type typeOfMap = new TypeToken<Map<String, Object>>() {}.getType();
fromApiJsonHelper.checkForUnsupportedParameters(typeOfMap, json,
SavingsApiConstants.SAVINGS_ACCOUNT_TRANSACTION_REQUEST_DATA_PARAMETERS);
final List<ApiParameterError> dataValidationErrors = new ArrayList<ApiParameterError>();
final DataValidatorBuilder baseDataValidator = new DataValidatorBuilder(dataValidationErrors)
.resource(SavingsApiConstants.SAVINGS_ACCOUNT_TRANSACTION_RESOURCE_NAME);
final JsonElement element = command.parsedJson();
final LocalDate transactionDate = fromApiJsonHelper.extractLocalDateNamed(transactionDateParamName, element);
baseDataValidator.reset().parameter(transactionDateParamName).value(transactionDate).notNull();
final BigDecimal transactionAmount = fromApiJsonHelper.extractBigDecimalWithLocaleNamed(transactionAmountParamName, element);
baseDataValidator.reset().parameter(transactionAmountParamName).value(transactionAmount).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); }
}
}
@@ -0,0 +1,24 @@
/**
* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this file,
* You can obtain one at http://mozilla.org/MPL/2.0/.
*/
package org.mifosplatform.portfolio.savings.data;
/**
* Immutable data object represent savings account transaction type
* enumerations.
*/
@SuppressWarnings("unused")
public class SavingsAccountTransactionEnumData {
private final Long id;
private final String code;
private final String value;
public SavingsAccountTransactionEnumData(final Long id, final String code, final String value) {
this.id = id;
this.code = code;
this.value = value;
}
}
@@ -6,19 +6,28 @@
package org.mifosplatform.portfolio.savings.domain;
import java.math.BigDecimal;
import java.util.ArrayList;
import java.util.List;
import java.util.Map;
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.Transient;
import javax.persistence.UniqueConstraint;
import org.apache.commons.lang.StringUtils;
import org.hibernate.annotations.LazyCollection;
import org.hibernate.annotations.LazyCollectionOption;
import org.joda.time.LocalDate;
import org.mifosplatform.infrastructure.core.api.JsonCommand;
import org.mifosplatform.infrastructure.core.service.DateUtils;
import org.mifosplatform.infrastructure.security.service.RandomPasswordGenerator;
import org.mifosplatform.organisation.monetary.domain.MonetaryCurrency;
import org.mifosplatform.organisation.monetary.domain.Money;
@@ -26,6 +35,8 @@ 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.mifosplatform.portfolio.savings.exception.InsufficientAccountBalanceException;
import org.mifosplatform.portfolio.savings.exception.InvalidSavingsAccountTransactionException;
import org.springframework.data.jpa.domain.AbstractPersistable;
@Entity
@@ -73,8 +84,18 @@ public class SavingsAccount extends AbstractPersistable<Long> {
@Column(name = "lockin_period_frequency_enum", nullable = false)
private Integer lockinPeriodFrequencyType;
@Embedded
private SavingsAccountSummary summary;
@OrderBy(value = "dateOf, id")
@LazyCollection(LazyCollectionOption.FALSE)
@OneToMany(cascade = CascadeType.ALL, mappedBy = "savingsAccount", orphanRemoval = true)
private final List<SavingsAccountTransaction> transactions = new ArrayList<SavingsAccountTransaction>();
@Transient
private boolean accountNumberRequiresAutoGeneration = false;
@Transient
private SavingsAccountTransactionSummaryWrapper savingsAccountTransactionSummaryWrapper;
protected SavingsAccount() {
//
@@ -113,6 +134,73 @@ public class SavingsAccount extends AbstractPersistable<Long> {
if (lockinPeriodFrequencyType != null) {
this.lockinPeriodFrequencyType = lockinPeriodFrequencyType.getValue();
}
this.summary = new SavingsAccountSummary();
}
/**
* Used after fetching/hydrating a {@link SavingsAccount} object to inject
* helper services/components used for update summary details after
* events/transactions on a loan.
*/
public void setHelpers(final SavingsAccountTransactionSummaryWrapper savingsAccountTransactionSummaryWrapper) {
this.savingsAccountTransactionSummaryWrapper = savingsAccountTransactionSummaryWrapper;
}
public SavingsAccountTransaction deposit(final LocalDate transactionDate, final BigDecimal transactionAmount) {
final Money amount = Money.of(this.currency, transactionAmount);
// FIXME - kw - check transactionDate is not before savings account
// activation date.
if (isTransactionInTheFuture(transactionDate)) {
final String defaultUserMessage = "Transaction date cannot be in the future.";
throw new InvalidSavingsAccountTransactionException("in.the.future", defaultUserMessage, "transactionDate", transactionDate);
}
final SavingsAccountTransaction transaction = SavingsAccountTransaction.deposit(this, transactionDate, amount);
this.transactions.add(transaction);
this.summary.updateSummary(this.currency, this.savingsAccountTransactionSummaryWrapper, this.transactions);
return transaction;
}
public SavingsAccountTransaction withdrawal(final LocalDate transactionDate, final BigDecimal transactionAmount) {
final Money amount = Money.of(this.currency, transactionAmount);
// FIXME - kw - check transactionDate is not before savings account
// activation date.
if (isTransactionInTheFuture(transactionDate)) {
final String defaultUserMessage = "Transaction date cannot be in the future.";
throw new InvalidSavingsAccountTransactionException("in.the.future", defaultUserMessage, "transactionDate", transactionDate);
}
if (isNotAllowedToWithdraw(amount)) {
//
throw new InsufficientAccountBalanceException("transactionAmount", getAccountBalance(), transactionAmount);
}
final SavingsAccountTransaction transaction = SavingsAccountTransaction.withdrawal(this, transactionDate, amount);
this.transactions.add(transaction);
this.summary.updateSummary(this.currency, this.savingsAccountTransactionSummaryWrapper, this.transactions);
return transaction;
}
private boolean isTransactionInTheFuture(final LocalDate transactionDate) {
return transactionDate.isAfter(DateUtils.getLocalDateOfTenant());
}
private BigDecimal getAccountBalance() {
return this.summary.getAccountBalance(this.currency).getAmount();
}
private boolean isNotAllowedToWithdraw(final Money amount) {
return this.summary.isLessThanOrEqualToAccountBalance(amount);
}
public void update(final JsonCommand command, final Map<String, Object> actualChanges) {
@@ -32,6 +32,7 @@ import com.google.gson.JsonElement;
@Service
public class SavingsAccountAssembler {
private final SavingsAccountTransactionSummaryWrapper savingsAccountTransactionSummaryWrapper;
private final ClientRepository clientRepository;
private final GroupRepository groupRepository;
private final SavingsProductRepository savingProductRepository;
@@ -39,9 +40,11 @@ public class SavingsAccountAssembler {
private final AprCalculator aprCalculator;
@Autowired
public SavingsAccountAssembler(final ClientRepository clientRepository, final GroupRepository groupRepository,
public SavingsAccountAssembler(final SavingsAccountTransactionSummaryWrapper savingsAccountTransactionSummaryWrapper,
final ClientRepository clientRepository, final GroupRepository groupRepository,
final SavingsProductRepository savingProductRepository, final AprCalculator aprCalculator,
final FromJsonHelper fromApiJsonHelper) {
this.savingsAccountTransactionSummaryWrapper = savingsAccountTransactionSummaryWrapper;
this.clientRepository = clientRepository;
this.groupRepository = groupRepository;
this.savingProductRepository = savingProductRepository;
@@ -106,7 +109,7 @@ public class SavingsAccountAssembler {
} else {
minRequiredOpeningBalance = product.minRequiredOpeningBalance();
}
Integer lockinPeriodFrequency = null;
if (command.parameterExists(lockinPeriodFrequencyParamName)) {
lockinPeriodFrequency = command.integerValueOfParameterNamed(lockinPeriodFrequencyParamName);
@@ -125,8 +128,11 @@ public class SavingsAccountAssembler {
lockinPeriodFrequencyType = product.lockinPeriodFrequencyType();
}
return SavingsAccount.createNewAccount(client, group, product, accountNo, externalId, interestRate,
final SavingsAccount account = SavingsAccount.createNewAccount(client, group, product, accountNo, externalId, interestRate,
interestRatePeriodFrequencyType, annualInterestRate, minRequiredOpeningBalance, lockinPeriodFrequency,
lockinPeriodFrequencyType);
account.setHelpers(this.savingsAccountTransactionSummaryWrapper);
return account;
}
}
@@ -0,0 +1,57 @@
/**
* 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 org.mifosplatform.portfolio.savings.exception.SavingsAccountNotFoundException;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
/**
* <p>
* Wrapper for {@link SavingsAccountRepository} that is responsible for checking
* if {@link SavingsAccount} is returned when using <code>findOne</code>
* repository method and throwing an appropriate not found exception.
* </p>
*
* <p>
* This is to avoid need for checking and throwing in multiple areas of code
* base where {@link SavingsAccountRepository} is required.
* </p>
*/
@Service
public class SavingsAccountRepositoryWrapper {
private final SavingsAccountRepository repository;
private final SavingsAccountTransactionSummaryWrapper savingsAccountTransactionSummaryWrapper;
@Autowired
public SavingsAccountRepositoryWrapper(final SavingsAccountRepository repository,
final SavingsAccountTransactionSummaryWrapper savingsAccountTransactionSummaryWrapper) {
this.repository = repository;
this.savingsAccountTransactionSummaryWrapper = savingsAccountTransactionSummaryWrapper;
}
public SavingsAccount findOneWithNotFoundDetection(final Long savingsId) {
final SavingsAccount account = this.repository.findOne(savingsId);
if (account == null) { throw new SavingsAccountNotFoundException(savingsId); }
account.setHelpers(this.savingsAccountTransactionSummaryWrapper);
return account;
}
public void save(final SavingsAccount account) {
this.repository.save(account);
}
public void delete(final SavingsAccount account) {
this.repository.delete(account);
}
public void saveAndFlush(final SavingsAccount account) {
this.repository.saveAndFlush(account);
}
}
@@ -0,0 +1,54 @@
package org.mifosplatform.portfolio.savings.domain;
import java.math.BigDecimal;
import java.util.List;
import javax.persistence.Column;
import javax.persistence.Embeddable;
import org.mifosplatform.organisation.monetary.domain.MonetaryCurrency;
import org.mifosplatform.organisation.monetary.domain.Money;
/**
* {@link SavingsAccountSummary} encapsulates all the summary details of a
* {@link SavingsAccount}.
*/
@Embeddable
public final class SavingsAccountSummary {
@Column(name = "total_deposits_derived", scale = 6, precision = 19)
private BigDecimal totalDeposits;
@Column(name = "total_withdrawals_derived", scale = 6, precision = 19)
private BigDecimal totalWithdrawals;
@Column(name = "total_interest_posted_derived", scale = 6, precision = 19)
private BigDecimal totalInterestPosted;
@Column(name = "account_balance_derived", scale = 6, precision = 19)
private BigDecimal accountBalance = BigDecimal.ZERO;
protected SavingsAccountSummary() {
//
}
public void updateSummary(final MonetaryCurrency currency, final SavingsAccountTransactionSummaryWrapper wrapper,
final List<SavingsAccountTransaction> transactions) {
this.totalDeposits = wrapper.calculateTotalDeposits(currency, transactions);
this.totalWithdrawals = wrapper.calculateTotalWithdrawals(currency, transactions);
this.totalInterestPosted = wrapper.calculateTotalInterestPosted(currency, transactions);
this.accountBalance = Money.of(currency, this.totalDeposits).plus(this.totalInterestPosted).minus(this.totalWithdrawals)
.getAmount();
}
public boolean isLessThanOrEqualToAccountBalance(final Money amount) {
final Money accountBalance = getAccountBalance(amount.getCurrency());
return accountBalance.isGreaterThanOrEqualTo(accountBalance);
}
public Money getAccountBalance(final MonetaryCurrency currency) {
return Money.of(currency, this.accountBalance);
}
}
@@ -0,0 +1,102 @@
/**
* 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.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.joda.time.LocalDate;
import org.mifosplatform.organisation.monetary.domain.MonetaryCurrency;
import org.mifosplatform.organisation.monetary.domain.Money;
import org.springframework.data.jpa.domain.AbstractPersistable;
/**
* All monetary transactions against a savings account are modelled through this
* entity.
*/
@Entity
@Table(name = "m_savings_account_transaction")
public final class SavingsAccountTransaction extends AbstractPersistable<Long> {
@SuppressWarnings("unused")
@ManyToOne(optional = false)
@JoinColumn(name = "savings_account_id", nullable = false)
private SavingsAccount savingsAccount;
@Column(name = "transaction_type_enum", nullable = false)
private final Integer typeOf;
@SuppressWarnings("unused")
@Temporal(TemporalType.DATE)
@Column(name = "transaction_date", nullable = false)
private final Date dateOf;
@Column(name = "amount", scale = 6, precision = 19, nullable = false)
private BigDecimal amount;
@Column(name = "is_reversed", nullable = false)
private boolean reversed;
protected SavingsAccountTransaction() {
this.dateOf = null;
this.typeOf = null;
}
public static SavingsAccountTransaction deposit(final SavingsAccount savingsAccount, final LocalDate date, final Money amount) {
final boolean isReversed = false;
return new SavingsAccountTransaction(savingsAccount, SavingsAccountTransactionType.DEPOSIT.getValue(), date, amount, isReversed);
}
public static SavingsAccountTransaction withdrawal(final SavingsAccount savingsAccount, final LocalDate date, final Money amount) {
final boolean isReversed = false;
return new SavingsAccountTransaction(savingsAccount, SavingsAccountTransactionType.WITHDRAWAL.getValue(), date, amount, isReversed);
}
private SavingsAccountTransaction(final SavingsAccount savingsAccount, final Integer typeOf, final LocalDate dateOf,
final Money amount, final boolean isReversed) {
this.savingsAccount = savingsAccount;
this.typeOf = typeOf;
this.dateOf = dateOf.toDate();
this.amount = amount.getAmount();
this.reversed = isReversed;
}
public void reverse() {
this.reversed = true;
}
public Money getAmount(final MonetaryCurrency currency) {
return Money.of(currency, this.amount);
}
public boolean isDeposit() {
return SavingsAccountTransactionType.fromInt(this.typeOf).isDeposit();
}
public boolean isWithdrawal() {
return SavingsAccountTransactionType.fromInt(this.typeOf).isWithdrawal();
}
public boolean isInterestPosting() {
return SavingsAccountTransactionType.fromInt(this.typeOf).isInterestPosting();
}
public boolean isNotReversed() {
return !isReversed();
}
public boolean isReversed() {
return this.reversed;
}
}
@@ -0,0 +1,14 @@
/**
* 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 org.springframework.data.jpa.repository.JpaRepository;
import org.springframework.data.jpa.repository.JpaSpecificationExecutor;
public interface SavingsAccountTransactionRepository extends JpaRepository<SavingsAccountTransaction, Long>,
JpaSpecificationExecutor<SavingsAccountTransaction> {
}
@@ -0,0 +1,46 @@
package org.mifosplatform.portfolio.savings.domain;
import java.math.BigDecimal;
import java.util.List;
import org.mifosplatform.organisation.monetary.domain.MonetaryCurrency;
import org.mifosplatform.organisation.monetary.domain.Money;
import org.springframework.stereotype.Component;
/**
* A wrapper for dealing with side-effect free functionality related to a
* {@link SavingsAccount}'s {@link SavingsAccountTransaction}'s.
*/
@Component
public final class SavingsAccountTransactionSummaryWrapper {
public BigDecimal calculateTotalDeposits(final MonetaryCurrency currency, final List<SavingsAccountTransaction> transactions) {
Money total = Money.zero(currency);
for (SavingsAccountTransaction transaction : transactions) {
if (transaction.isDeposit() && transaction.isNotReversed()) {
total = total.plus(transaction.getAmount(currency));
}
}
return total.getAmountDefaultedToNullIfZero();
}
public BigDecimal calculateTotalWithdrawals(final MonetaryCurrency currency, final List<SavingsAccountTransaction> transactions) {
Money total = Money.zero(currency);
for (SavingsAccountTransaction transaction : transactions) {
if (transaction.isWithdrawal() && transaction.isNotReversed()) {
total = total.plus(transaction.getAmount(currency));
}
}
return total.getAmountDefaultedToNullIfZero();
}
public BigDecimal calculateTotalInterestPosted(final MonetaryCurrency currency, final List<SavingsAccountTransaction> transactions) {
Money total = Money.zero(currency);
for (SavingsAccountTransaction transaction : transactions) {
if (transaction.isInterestPosting() && transaction.isNotReversed()) {
total = total.plus(transaction.getAmount(currency));
}
}
return total.getAmountDefaultedToNullIfZero();
}
}
@@ -0,0 +1,65 @@
/**
* 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;
/**
* An enumeration of different transactions that can occur on a
* {@link SavingsAccount}.
*/
public enum SavingsAccountTransactionType {
INVALID(0, "savingsAccountTransactionType.invalid"), //
DEPOSIT(1, "savingsAccountTransactionType.deposit"), //
WITHDRAWAL(2, "savingsAccountTransactionType.withdrawal"), //
INTEREST_POSTING(3, "savingsAccountTransactionType.interestPosting");
private final Integer value;
private final String code;
private SavingsAccountTransactionType(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 SavingsAccountTransactionType fromInt(final Integer transactionType) {
if (transactionType == null) { return SavingsAccountTransactionType.INVALID; }
SavingsAccountTransactionType loanTransactionType = SavingsAccountTransactionType.INVALID;
switch (transactionType) {
case 1:
loanTransactionType = SavingsAccountTransactionType.DEPOSIT;
break;
case 2:
loanTransactionType = SavingsAccountTransactionType.WITHDRAWAL;
break;
case 3:
loanTransactionType = SavingsAccountTransactionType.INTEREST_POSTING;
break;
}
return loanTransactionType;
}
public boolean isDeposit() {
return this.value.equals(SavingsAccountTransactionType.DEPOSIT.getValue());
}
public boolean isWithdrawal() {
return this.value.equals(SavingsAccountTransactionType.WITHDRAWAL.getValue());
}
public boolean isInterestPosting() {
return this.value.equals(SavingsAccountTransactionType.INTEREST_POSTING.getValue());
}
}
@@ -0,0 +1,17 @@
package org.mifosplatform.portfolio.savings.exception;
import java.math.BigDecimal;
import org.mifosplatform.infrastructure.core.exception.AbstractPlatformDomainRuleException;
/**
* Thrown when an attempt is made to withdraw money that is greater than the
* account balance.
*/
public class InsufficientAccountBalanceException extends AbstractPlatformDomainRuleException {
public InsufficientAccountBalanceException(final String paramName, final BigDecimal accountBalance, final BigDecimal withdrawalRequested) {
super("error.msg.savingsaccount.transaction.insufficient.account.balance", "Insufficient account balance.", paramName,
accountBalance, withdrawalRequested);
}
}
@@ -0,0 +1,15 @@
package org.mifosplatform.portfolio.savings.exception;
import org.mifosplatform.infrastructure.core.exception.AbstractPlatformDomainRuleException;
/**
* Thrown when an attempt is made to withdraw money that is greater than the
* account balance.
*/
public class InvalidSavingsAccountTransactionException extends AbstractPlatformDomainRuleException {
public InvalidSavingsAccountTransactionException(final String errorCode, final String defaultErrorMessage, final String paramName,
final Object... defaultUserMessageArgs) {
super("error.msg.savingsaccount.transaction." + errorCode, defaultErrorMessage, paramName, defaultUserMessageArgs);
}
}
@@ -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 DepositSavingsAccountCommandHandler implements NewCommandSourceHandler {
private final SavingsAccountWritePlatformService savingAccountWritePlatformService;
@Autowired
public DepositSavingsAccountCommandHandler(final SavingsAccountWritePlatformService savingAccountWritePlatformService) {
this.savingAccountWritePlatformService = savingAccountWritePlatformService;
}
@Transactional
@Override
public CommandProcessingResult processCommand(final JsonCommand command) {
return this.savingAccountWritePlatformService.deposit(command.getLoanId(), command);
}
}
@@ -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 WithdrawSavingsAccountCommandHandler implements NewCommandSourceHandler {
private final SavingsAccountWritePlatformService savingAccountWritePlatformService;
@Autowired
public WithdrawSavingsAccountCommandHandler(final SavingsAccountWritePlatformService savingAccountWritePlatformService) {
this.savingAccountWritePlatformService = savingAccountWritePlatformService;
}
@Transactional
@Override
public CommandProcessingResult processCommand(final JsonCommand command) {
return this.savingAccountWritePlatformService.withdrawal(command.getLoanId(), command);
}
}
@@ -8,12 +8,17 @@ package org.mifosplatform.portfolio.savings.service;
import java.util.Collection;
import org.mifosplatform.portfolio.savings.data.SavingsAccountData;
import org.mifosplatform.portfolio.savings.data.SavingsAccountTransactionData;
public interface SavingsAccountReadPlatformService {
Collection<SavingsAccountData> retrieveAll();
SavingsAccountData retrieveOne(Long accountId);
SavingsAccountData retrieveOne(Long savingsId);
SavingsAccountData retrieveTemplate(Long clientId, Long groupId, Long productId);
SavingsAccountTransactionData retrieveDepositTransactionTemplate(Long savingsId);
Collection<SavingsAccountTransactionData> retrieveAllTransactions(Long savingsId);
}
@@ -10,8 +10,10 @@ import java.sql.ResultSet;
import java.sql.SQLException;
import java.util.Collection;
import org.joda.time.LocalDate;
import org.mifosplatform.infrastructure.core.data.EnumOptionData;
import org.mifosplatform.infrastructure.core.domain.JdbcSupport;
import org.mifosplatform.infrastructure.core.service.DateUtils;
import org.mifosplatform.infrastructure.core.service.TenantAwareRoutingDataSource;
import org.mifosplatform.infrastructure.security.service.PlatformSecurityContext;
import org.mifosplatform.organisation.monetary.data.CurrencyData;
@@ -21,6 +23,9 @@ 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.SavingsAccountSummaryData;
import org.mifosplatform.portfolio.savings.data.SavingsAccountTransactionData;
import org.mifosplatform.portfolio.savings.data.SavingsAccountTransactionEnumData;
import org.mifosplatform.portfolio.savings.data.SavingsProductData;
import org.mifosplatform.portfolio.savings.exception.SavingsAccountNotFoundException;
import org.springframework.beans.factory.annotation.Autowired;
@@ -38,6 +43,8 @@ public class SavingsAccountReadPlatformServiceImpl implements SavingsAccountRead
private final GroupReadPlatformService groupReadPlatformService;
private final SavingsProductReadPlatformService savingsProductReadPlatformService;
private final SavingsDropdownReadPlatformService dropdownReadPlatformService;
private final SavingsAccountTransactionTemplateMapper transactionTemplateMapper;
private final SavingsAccountTransactionsMapper transactionsMapper;
@Autowired
public SavingsAccountReadPlatformServiceImpl(final PlatformSecurityContext context, final TenantAwareRoutingDataSource dataSource,
@@ -50,6 +57,8 @@ public class SavingsAccountReadPlatformServiceImpl implements SavingsAccountRead
this.groupReadPlatformService = groupReadPlatformService;
this.savingsProductReadPlatformService = savingProductReadPlatformService;
this.dropdownReadPlatformService = dropdownReadPlatformService;
transactionTemplateMapper = new SavingsAccountTransactionTemplateMapper();
transactionsMapper = new SavingsAccountTransactionsMapper();
}
@Override
@@ -59,7 +68,6 @@ public class SavingsAccountReadPlatformServiceImpl implements SavingsAccountRead
final SavingAccountMapper mapper = new SavingAccountMapper();
final String sql = "select " + mapper.schema();
return this.jdbcTemplate.query(sql, mapper, new Object[] {});
}
@Override
@@ -88,14 +96,18 @@ public class SavingsAccountReadPlatformServiceImpl implements SavingsAccountRead
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("curr.name as currencyName, curr.internationalized_name_code as currencyNameCode, ");
sqlBuilder.append("curr.display_symbol as currencyDisplaySymbol, ");
sqlBuilder.append("sa.nominal_interest_rate_per_period as interestRate, ");
sqlBuilder.append("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("sa.lockin_period_frequency as lockinPeriodFrequency,");
sqlBuilder.append("sa.lockin_period_frequency_enum as lockinPeriodFrequencyType, ");
sqlBuilder.append("sa.total_deposits_derived as totalDeposits, ");
sqlBuilder.append("sa.total_withdrawals_derived as totalWithdrawals, ");
sqlBuilder.append("sa.total_interest_posted_derived as totalInterestPosted, ");
sqlBuilder.append("sa.account_balance_derived as accountBalance ");
sqlBuilder.append("from m_savings_account sa ");
sqlBuilder.append("left outer join m_client c ON c.id = sa.client_id ");
sqlBuilder.append("left outer join m_group g ON g.id = sa.group_id ");
@@ -137,7 +149,7 @@ public class SavingsAccountReadPlatformServiceImpl implements SavingsAccountRead
.fromInt(JdbcSupport.getInteger(rs, "interestRatePeriodFrequencyType")));
final BigDecimal annualInterestRate = rs.getBigDecimal("annualInterestRate");
final BigDecimal minRequiredOpeningBalance = rs.getBigDecimal("minRequiredOpeningBalance");
final BigDecimal minRequiredOpeningBalance = JdbcSupport.getBigDecimalDefaultToNullIfZero(rs, "minRequiredOpeningBalance");
final Integer lockinPeriodFrequency = JdbcSupport.getInteger(rs, "lockinPeriodFrequency");
EnumOptionData lockinPeriodFrequencyType = null;
@@ -147,9 +159,17 @@ public class SavingsAccountReadPlatformServiceImpl implements SavingsAccountRead
.fromInt(lockinPeriodFrequencyTypeValue));
}
final BigDecimal totalDeposits = JdbcSupport.getBigDecimalDefaultToNullIfZero(rs, "totalDeposits");
final BigDecimal totalWithdrawals = JdbcSupport.getBigDecimalDefaultToNullIfZero(rs, "totalWithdrawals");
final BigDecimal totalInterestPosted = JdbcSupport.getBigDecimalDefaultToNullIfZero(rs, "totalInterestPosted");
final BigDecimal accountBalance = JdbcSupport.getBigDecimalDefaultToZeroIfNull(rs, "accountBalance");
final SavingsAccountSummaryData summary = new SavingsAccountSummaryData(currency, totalDeposits, totalWithdrawals,
totalInterestPosted, accountBalance);
return SavingsAccountData.instance(id, accountNo, externalId, groupId, groupName, clientId, clientName, productId, productName,
currency, interestRate, interestRatePeriodFrequencyType, annualInterestRate, minRequiredOpeningBalance,
lockinPeriodFrequency, lockinPeriodFrequencyType);
lockinPeriodFrequency, lockinPeriodFrequencyType, summary);
}
}
@@ -181,9 +201,10 @@ public class SavingsAccountReadPlatformServiceImpl implements SavingsAccountRead
.retrieveInterestRatePeriodFrequencyTypeOptions();
final Collection<EnumOptionData> lockinPeriodFrequencyTypeOptions = this.dropdownReadPlatformService
.retrieveLockinPeriodFrequencyTypeOptions();
final Collection<SavingsAccountTransactionData> transactions = null;
template = SavingsAccountData.withTemplateOptions(template, productOptions, interestRatePeriodFrequencyTypeOptions,
lockinPeriodFrequencyTypeOptions);
lockinPeriodFrequencyTypeOptions, transactions);
} else {
String clientName = null;
@@ -200,13 +221,124 @@ public class SavingsAccountReadPlatformServiceImpl implements SavingsAccountRead
final Collection<EnumOptionData> interestRatePeriodFrequencyTypeOptions = null;
final Collection<EnumOptionData> lockinPeriodFrequencyTypeOptions = null;
final Collection<SavingsAccountTransactionData> transactions = null;
template = SavingsAccountData.withTemplateOptions(template, productOptions, interestRatePeriodFrequencyTypeOptions,
lockinPeriodFrequencyTypeOptions);
lockinPeriodFrequencyTypeOptions, transactions);
}
return template;
}
@Override
public SavingsAccountTransactionData retrieveDepositTransactionTemplate(final Long savingsId) {
try {
this.context.authenticatedUser();
final String sql = "select " + transactionTemplateMapper.schema() + " where sa.id = ?";
return this.jdbcTemplate.queryForObject(sql, transactionTemplateMapper, new Object[] { savingsId });
} catch (EmptyResultDataAccessException e) {
throw new SavingsAccountNotFoundException(savingsId);
}
}
@Override
public Collection<SavingsAccountTransactionData> retrieveAllTransactions(final Long savingsId) {
final String sql = "select " + this.transactionsMapper.schema() + " where sa.id = ?";
return this.jdbcTemplate.query(sql, this.transactionsMapper, new Object[] { savingsId });
}
private static final class SavingsAccountTransactionsMapper implements RowMapper<SavingsAccountTransactionData> {
private final String schemaSql;
public SavingsAccountTransactionsMapper() {
final StringBuilder sqlBuilder = new StringBuilder(400);
sqlBuilder.append("tr.id as transactionId, tr.transaction_type_enum as transactionType, ");
sqlBuilder.append("tr.transaction_date as transactionDate, tr.amount as transactionAmount,");
sqlBuilder.append("sa.id as savingsId, sa.account_no as accountNo, ");
sqlBuilder.append("sa.currency_code as currencyCode, sa.currency_digits as currencyDigits, ");
sqlBuilder.append("curr.name as currencyName, curr.internationalized_name_code as currencyNameCode, ");
sqlBuilder.append("curr.display_symbol as currencyDisplaySymbol ");
sqlBuilder.append("from m_savings_account sa ");
sqlBuilder.append("join m_savings_account_transaction tr on tr.savings_account_id = sa.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 SavingsAccountTransactionData mapRow(final ResultSet rs, @SuppressWarnings("unused") final int rowNum) throws SQLException {
final Long id = rs.getLong("transactionId");
final int transactionTypeInt = JdbcSupport.getInteger(rs, "transactionType");
final SavingsAccountTransactionEnumData transactionType = SavingsEnumerations.transactionType(transactionTypeInt);
final LocalDate date = JdbcSupport.getLocalDate(rs, "transactionDate");
final BigDecimal amount = JdbcSupport.getBigDecimalDefaultToZeroIfNull(rs, "transactionAmount");
final Long savingsId = rs.getLong("savingsId");
final String accountNo = rs.getString("accountNo");
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);
return SavingsAccountTransactionData.create(id, transactionType, savingsId, accountNo, date, currency, amount);
}
}
private static final class SavingsAccountTransactionTemplateMapper implements RowMapper<SavingsAccountTransactionData> {
private final String schemaSql;
public SavingsAccountTransactionTemplateMapper() {
final StringBuilder sqlBuilder = new StringBuilder(400);
sqlBuilder.append("sa.id as id, sa.account_no as accountNo, ");
sqlBuilder.append("sa.currency_code as currencyCode, sa.currency_digits as currencyDigits, ");
sqlBuilder.append("curr.name as currencyName, curr.internationalized_name_code as currencyNameCode, ");
sqlBuilder.append("curr.display_symbol as currencyDisplaySymbol, ");
sqlBuilder.append("sa.min_required_opening_balance as minRequiredOpeningBalance ");
sqlBuilder.append("from m_savings_account sa ");
sqlBuilder.append("join m_currency curr on curr.code = sa.currency_code ");
this.schemaSql = sqlBuilder.toString();
}
public String schema() {
return this.schemaSql;
}
@Override
public SavingsAccountTransactionData mapRow(final ResultSet rs, @SuppressWarnings("unused") final int rowNum) throws SQLException {
final Long savingsId = rs.getLong("id");
final String accountNo = rs.getString("accountNo");
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);
return SavingsAccountTransactionData.template(savingsId, accountNo, DateUtils.getLocalDateOfTenant(), currency);
}
}
private static final class SavingAccountTemplateMapper implements RowMapper<SavingsAccountData> {
private final ClientData client;
@@ -257,7 +389,7 @@ public class SavingsAccountReadPlatformServiceImpl implements SavingsAccountRead
.fromInt(JdbcSupport.getInteger(rs, "interestRatePeriodFrequencyType")));
final BigDecimal annualInterestRate = null;
final BigDecimal minRequiredOpeningBalance = rs.getBigDecimal("minRequiredOpeningBalance");
final BigDecimal minRequiredOpeningBalance = JdbcSupport.getBigDecimalDefaultToNullIfZero(rs, "minRequiredOpeningBalance");
final Integer lockinPeriodFrequency = JdbcSupport.getInteger(rs, "lockinPeriodFrequency");
EnumOptionData lockinPeriodFrequencyType = null;
@@ -281,9 +413,10 @@ public class SavingsAccountReadPlatformServiceImpl implements SavingsAccountRead
groupName = group.getName();
}
final SavingsAccountSummaryData summary = null;
return SavingsAccountData.instance(null, null, null, groupId, groupName, clientId, clientName, productId, productName,
currency, interestRate, interestRatePeriodFrequencyType, annualInterestRate, minRequiredOpeningBalance,
lockinPeriodFrequency, lockinPeriodFrequencyType);
lockinPeriodFrequency, lockinPeriodFrequencyType, summary);
}
}
}
@@ -14,9 +14,9 @@ public interface SavingsAccountWritePlatformService {
CommandProcessingResult updateSavingAccount(Long accountId, JsonCommand command);
CommandProcessingResult deposit(JsonCommand command);
CommandProcessingResult withdraw(JsonCommand command);
CommandProcessingResult deleteSavingAccount(Long accountId);
CommandProcessingResult deposit(Long savingsId, JsonCommand command);
CommandProcessingResult withdrawal(Long savingsId, JsonCommand command);
}
@@ -5,9 +5,11 @@
*/
package org.mifosplatform.portfolio.savings.service;
import java.math.BigDecimal;
import java.util.LinkedHashMap;
import java.util.Map;
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;
@@ -23,12 +25,14 @@ 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.data.SavingsAccountTransactionDataValidator;
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.SavingsAccountRepositoryWrapper;
import org.mifosplatform.portfolio.savings.domain.SavingsAccountTransaction;
import org.mifosplatform.portfolio.savings.domain.SavingsAccountTransactionRepository;
import org.mifosplatform.portfolio.savings.domain.SavingsProduct;
import org.mifosplatform.portfolio.savings.domain.SavingsProductRepository;
import org.mifosplatform.portfolio.savings.exception.SavingsAccountNotFoundException;
import org.mifosplatform.portfolio.savings.exception.SavingsProductNotFoundException;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
@@ -43,9 +47,11 @@ public class SavingsAccountWritePlatformServiceJpaRepositoryImpl implements Savi
private final static Logger logger = LoggerFactory.getLogger(SavingsAccountWritePlatformServiceJpaRepositoryImpl.class);
private final PlatformSecurityContext context;
private final SavingsAccountRepository savingAccountRepository;
private final SavingsAccountRepositoryWrapper savingAccountRepository;
private final SavingsAccountTransactionRepository savingsAccountTransactionRepository;
private final SavingsAccountAssembler savingAccountAssembler;
private final SavingsAccountDataValidator savingsAccountDataValidator;
private final SavingsAccountTransactionDataValidator savingsAccountTransactionDataValidator;
private final AccountNumberGeneratorFactory accountIdentifierGeneratorFactory;
private final ClientRepository clientRepository;
private final GroupRepository groupRepository;
@@ -53,13 +59,18 @@ public class SavingsAccountWritePlatformServiceJpaRepositoryImpl implements Savi
@Autowired
public SavingsAccountWritePlatformServiceJpaRepositoryImpl(final PlatformSecurityContext context,
final SavingsAccountRepository savingAccountRepository, final SavingsAccountAssembler savingAccountAssembler,
final SavingsAccountRepositoryWrapper savingAccountRepository,
final SavingsAccountTransactionRepository savingsAccountTransactionRepository,
final SavingsAccountAssembler savingAccountAssembler,
final SavingsAccountDataValidator savingsAccountDataValidator,
final SavingsAccountTransactionDataValidator savingsAccountTransactionDataValidator,
final AccountNumberGeneratorFactory accountIdentifierGeneratorFactory, final ClientRepository clientRepository,
final GroupRepository groupRepository, final SavingsProductRepository savingsProductRepository) {
this.context = context;
this.savingAccountRepository = savingAccountRepository;
this.savingsAccountTransactionRepository = savingsAccountTransactionRepository;
this.savingAccountAssembler = savingAccountAssembler;
this.savingsAccountTransactionDataValidator = savingsAccountTransactionDataValidator;
this.accountIdentifierGeneratorFactory = accountIdentifierGeneratorFactory;
this.savingsAccountDataValidator = savingsAccountDataValidator;
this.clientRepository = clientRepository;
@@ -136,8 +147,7 @@ public class SavingsAccountWritePlatformServiceJpaRepositoryImpl implements Savi
final Map<String, Object> changes = new LinkedHashMap<String, Object>(20);
final SavingsAccount account = this.savingAccountRepository.findOne(accountId);
if (account == null) { throw new SavingsAccountNotFoundException(accountId); }
final SavingsAccount account = this.savingAccountRepository.findOneWithNotFoundDetection(accountId);
account.update(command, changes);
@@ -192,54 +202,13 @@ public class SavingsAccountWritePlatformServiceJpaRepositoryImpl implements Savi
}
}
@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); }
final SavingsAccount account = this.savingAccountRepository.findOneWithNotFoundDetection(accountId);
this.savingAccountRepository.delete(account);
@@ -250,4 +219,60 @@ public class SavingsAccountWritePlatformServiceJpaRepositoryImpl implements Savi
.withGroupId(account.groupId()) //
.build();
}
@Transactional
@Override
public CommandProcessingResult deposit(final Long savingsId, final JsonCommand command) {
this.context.authenticatedUser();
this.savingsAccountTransactionDataValidator.validate(command);
final SavingsAccount account = this.savingAccountRepository.findOneWithNotFoundDetection(savingsId);
final LocalDate transactionDate = command.localDateValueOfParameterNamed("transactionDate");
final BigDecimal transactionAmount = command.bigDecimalValueOfParameterNamed("transactionAmount");
final SavingsAccountTransaction deposit = account.deposit(transactionDate, transactionAmount);
final Long transactionId = saveTransactionToGenerateTransactionId(deposit);
this.savingAccountRepository.save(account);
return new CommandProcessingResultBuilder() //
.withEntityId(transactionId) //
.withOfficeId(account.officeId()) //
.withClientId(account.clientId()) //
.withGroupId(account.groupId()) //
.withSavingsId(savingsId) //
.build();
}
private Long saveTransactionToGenerateTransactionId(final SavingsAccountTransaction transaction) {
this.savingsAccountTransactionRepository.save(transaction);
return transaction.getId();
}
@Transactional
@Override
public CommandProcessingResult withdrawal(final Long savingsId, final JsonCommand command) {
this.context.authenticatedUser();
final SavingsAccount account = this.savingAccountRepository.findOneWithNotFoundDetection(savingsId);
final LocalDate transactionDate = command.localDateValueOfParameterNamed("transactionDate");
final BigDecimal transactionAmount = command.bigDecimalValueOfParameterNamed("transactionAmount");
final SavingsAccountTransaction withdrawal = account.withdrawal(transactionDate, transactionAmount);
final Long transactionId = saveTransactionToGenerateTransactionId(withdrawal);
this.savingAccountRepository.save(account);
return new CommandProcessingResultBuilder() //
.withEntityId(transactionId) //
.withOfficeId(account.officeId()) //
.withClientId(account.clientId()) //
.withGroupId(account.groupId()) //
.withSavingsId(savingsId) //
.build();
}
}
@@ -7,6 +7,8 @@ package org.mifosplatform.portfolio.savings.service;
import org.mifosplatform.infrastructure.core.data.EnumOptionData;
import org.mifosplatform.portfolio.loanproduct.domain.PeriodFrequencyType;
import org.mifosplatform.portfolio.savings.data.SavingsAccountTransactionEnumData;
import org.mifosplatform.portfolio.savings.domain.SavingsAccountTransactionType;
public class SavingsEnumerations {
@@ -71,4 +73,34 @@ public class SavingsEnumerations {
}
return optionData;
}
public static SavingsAccountTransactionEnumData transactionType(final int transactionType) {
return transactionType(SavingsAccountTransactionType.fromInt(transactionType));
}
public static SavingsAccountTransactionEnumData transactionType(final SavingsAccountTransactionType type) {
SavingsAccountTransactionEnumData optionData = new SavingsAccountTransactionEnumData(SavingsAccountTransactionType.INVALID
.getValue().longValue(), SavingsAccountTransactionType.INVALID.getCode(), "Invalid");
switch (type) {
case INVALID:
optionData = new SavingsAccountTransactionEnumData(SavingsAccountTransactionType.INVALID.getValue().longValue(),
SavingsAccountTransactionType.INVALID.getCode(), "Invalid");
break;
case DEPOSIT:
optionData = new SavingsAccountTransactionEnumData(SavingsAccountTransactionType.DEPOSIT.getValue().longValue(),
SavingsAccountTransactionType.DEPOSIT.getCode(), "Deposit");
break;
case WITHDRAWAL:
optionData = new SavingsAccountTransactionEnumData(SavingsAccountTransactionType.WITHDRAWAL.getValue().longValue(),
SavingsAccountTransactionType.WITHDRAWAL.getCode(), "Withdrawal");
break;
case INTEREST_POSTING:
optionData = new SavingsAccountTransactionEnumData(SavingsAccountTransactionType.INTEREST_POSTING.getValue().longValue(),
SavingsAccountTransactionType.INTEREST_POSTING.getCode(), "Interest posting");
break;
}
return optionData;
}
}