From 253c444a4537dae71cf1fb1bcf1c7d8c2deafd81 Mon Sep 17 00:00:00 2001 From: Chandrika Date: Wed, 24 Sep 2014 17:38:37 -0400 Subject: [PATCH] MIFOSX-1252 Squashing all previous commits.Savings Officer changes --- api-docs/apiLive.htm | 32 ++-- .../V202__savings_officer_history_table.sql | 20 ++ .../commands/domain/CommandWrapper.java | 8 +- .../service/CommandWrapperBuilder.java | 12 +- .../SynchronousCommandProcessingService.java | 8 +- .../staff/exception/StaffRoleException.java | 2 +- .../savings/SavingsApiConstants.java | 2 +- .../api/SavingsAccountsApiResource.java | 10 +- .../data/SavingsAccountDataValidator.java | 60 +++--- .../savings/domain/FixedDepositAccount.java | 2 +- .../domain/RecurringDepositAccount.java | 2 +- .../savings/domain/SavingsAccount.java | 175 ++++++++++++++++-- .../SavingsOfficerAssignmentHistory.java | 106 +++++++++++ ...SavingsOfficerAssignmentDateException.java | 16 ++ .../SavingsOfficerAssignmentException.java | 16 ++ ...vingsOfficerUnassignmentDateException.java | 17 ++ .../SavingsOfficerUnassignmentException.java | 15 ++ ...> RemoveSavingsOfficerCommandHandler.java} | 4 +- ...> UpdateSavingsOfficerCommandHandler.java} | 4 +- ...WritePlatformServiceJpaRepositoryImpl.java | 68 ++++--- 20 files changed, 466 insertions(+), 113 deletions(-) create mode 100644 mifosng-db/migrations/core_db/V202__savings_officer_history_table.sql create mode 100644 mifosng-provider/src/main/java/org/mifosplatform/portfolio/savings/domain/SavingsOfficerAssignmentHistory.java create mode 100644 mifosng-provider/src/main/java/org/mifosplatform/portfolio/savings/exception/SavingsOfficerAssignmentDateException.java create mode 100644 mifosng-provider/src/main/java/org/mifosplatform/portfolio/savings/exception/SavingsOfficerAssignmentException.java create mode 100644 mifosng-provider/src/main/java/org/mifosplatform/portfolio/savings/exception/SavingsOfficerUnassignmentDateException.java create mode 100644 mifosng-provider/src/main/java/org/mifosplatform/portfolio/savings/exception/SavingsOfficerUnassignmentException.java rename mifosng-provider/src/main/java/org/mifosplatform/portfolio/savings/handler/{UnassignFieldOfficerSavingsAccountCommandHandler.java => RemoveSavingsOfficerCommandHandler.java} (82%) rename mifosng-provider/src/main/java/org/mifosplatform/portfolio/savings/handler/{AssignFieldOfficerSavingsAccountCommandHandler.java => UpdateSavingsOfficerCommandHandler.java} (83%) diff --git a/api-docs/apiLive.htm b/api-docs/apiLive.htm index a36cab86c..5a3735fc1 100644 --- a/api-docs/apiLive.htm +++ b/api-docs/apiLive.htm @@ -427,7 +427,7 @@ - savingsaccounts/{accountId}?command=assignFieldOfficer + savingsaccounts/{accountId}?command=assignSavingsOfficer Assign Savings Officer @@ -435,7 +435,7 @@ - savingsaccounts/{accountId}?command=unassignFieldOfficer + savingsaccounts/{accountId}?command=unassignSavingsOfficer Unassign Savings Officer @@ -19167,20 +19167,24 @@ Request Body:

Allows you to assign Savings Officer for existing Savings Account.

- POST https://Domain Name/api/v1/savingsaccounts/{savingsId}?command=assignFieldOfficer - POST savingsaccounts/1?command=assignFieldOfficer + POST https://Domain Name/api/v1/savingsaccounts/{savingsId}?command=assignSavingsOfficer + POST savingsaccounts/1?command=assignSavingsOfficer Content-Type: application/json Request Body: { - "staffId":1 + assignmentDate : "04 September 2014" + dateFormat : "dd MMMM yyyy" + fromSavingsOfficerId : "" + locale : "en" + toSavingsOfficerId : 2 } { "officeId":2, - "clientId":8, + "savingsId":8, "resourceId":8, - "changes":{"staffId":1} + "changes":{"savingsOfficerId":2} }
@@ -19193,12 +19197,14 @@ Request Body:

Allows you to unassign the Savings Officer.

- POST https://Domain Name/api/v1/savingsaccounts/{savingsId}?command=unassignFieldOfficer - POST savingsaccounts/1?command=unassignFieldOfficer + POST https://Domain Name/api/v1/savingsaccounts/{savingsId}?command=unassignSavingsOfficer + POST savingsaccounts/1?command=unassignSavingsOfficer Content-Type: application/json Request Body: { - "staffId":1 + dateFormat : "dd MMMM yyyy" + locale : "en" + unassignedDate : "05 September 2014" } @@ -19206,7 +19212,7 @@ Request Body: "officeId":2, "clientId":8, "resourceId":8, - "changes":{"staffId":1} + "changes":{} }
@@ -33777,7 +33783,7 @@ No Request Body: - savingsaccounts/{accountId}?command=assignFieldOfficer + savingsaccounts/{accountId}?command=assignSavingsOfficer Assign Savings Officer @@ -33785,7 +33791,7 @@ No Request Body: - savingsaccounts/{accountId}?command=unassignFieldOfficer + savingsaccounts/{accountId}?command=unassignSavingsOfficer Unassign Savings Officer diff --git a/mifosng-db/migrations/core_db/V202__savings_officer_history_table.sql b/mifosng-db/migrations/core_db/V202__savings_officer_history_table.sql new file mode 100644 index 000000000..0ffcb82d4 --- /dev/null +++ b/mifosng-db/migrations/core_db/V202__savings_officer_history_table.sql @@ -0,0 +1,20 @@ +CREATE TABLE `m_savings_officer_assignment_history` ( + `id` bigint(20) NOT NULL AUTO_INCREMENT, + `account_id` bigint(20) NOT NULL, + `savings_officer_id` bigint(20) DEFAULT NULL, + `start_date` date NOT NULL, + `end_date` date DEFAULT NULL, + `createdby_id` bigint(20) DEFAULT NULL, + `created_date` datetime DEFAULT NULL, + `lastmodified_date` datetime DEFAULT NULL, + `lastmodifiedby_id` bigint(20) DEFAULT NULL, + PRIMARY KEY (`id`), + KEY `fk_m_savings_officer_assignment_history_0001` (`account_id`), + KEY `fk_m_savings_officer_assignment_history_0002` (`savings_officer_id`), + CONSTRAINT `fk_m_savings_officer_assignment_history_0001` FOREIGN KEY (`account_id`) REFERENCES `m_savings_account` (`id`), + CONSTRAINT `fk_m_savings_officer_assignment_history_0002` FOREIGN KEY (`savings_officer_id`) REFERENCES `m_staff` (`id`) +) ENGINE=InnoDB DEFAULT CHARSET=utf8; + +insert into m_permission (grouping,code,entity_name,action_name) values ('portfolio','REMOVESAVINGSOFFICER_SAVINGSACCOUNT','SAVINGSACCOUNT','REMOVESAVINGSOFFICER'); +insert into m_permission (grouping,code,entity_name,action_name) values ('portfolio','UPDATESAVINGSOFFICER_SAVINGSACCOUNT','SAVINGSACCOUNT','UPDATESAVINGSOFFICER'); + diff --git a/mifosng-provider/src/main/java/org/mifosplatform/commands/domain/CommandWrapper.java b/mifosng-provider/src/main/java/org/mifosplatform/commands/domain/CommandWrapper.java index dd201c989..6c2f3aa4b 100755 --- a/mifosng-provider/src/main/java/org/mifosplatform/commands/domain/CommandWrapper.java +++ b/mifosng-provider/src/main/java/org/mifosplatform/commands/domain/CommandWrapper.java @@ -589,12 +589,12 @@ public class CommandWrapper { return this.actionName.equalsIgnoreCase("ADJUSTTRANSACTION") && this.entityName.equalsIgnoreCase("SAVINGSACCOUNT"); } - public boolean isAssignStaffSavingsAccount(){ - return this.actionName.equalsIgnoreCase("ASSIGNFIELDOFFICER") && this.entityName.equalsIgnoreCase("SAVINGSACCOUNT"); + public boolean isUpdateSavingsOfficer(){ + return this.actionName.equalsIgnoreCase("UPDATESAVINGSOFFICER") && this.entityName.equalsIgnoreCase("SAVINGSACCOUNT"); } - public boolean isUnAssignStaffSavingsAccount(){ - return this.actionName.equalsIgnoreCase("UNASSIGNFIELDOFFICER") && this.entityName.equalsIgnoreCase("SAVINGSACCOUNT"); + public boolean isRemoveSavingsOfficer(){ + return this.actionName.equalsIgnoreCase("REMOVESAVINGSOFFICER") && this.entityName.equalsIgnoreCase("SAVINGSACCOUNT"); } public boolean isSavingsAccountChargeResource() { diff --git a/mifosng-provider/src/main/java/org/mifosplatform/commands/service/CommandWrapperBuilder.java b/mifosng-provider/src/main/java/org/mifosplatform/commands/service/CommandWrapperBuilder.java index c63e1219c..9f15a214e 100755 --- a/mifosng-provider/src/main/java/org/mifosplatform/commands/service/CommandWrapperBuilder.java +++ b/mifosng-provider/src/main/java/org/mifosplatform/commands/service/CommandWrapperBuilder.java @@ -2073,19 +2073,19 @@ public class CommandWrapperBuilder { this.entityId = entityId; return this; } - public CommandWrapperBuilder assignFieldOfficer(final Long accountId) { - this.actionName = "ASSIGNFIELDOFFICER"; + public CommandWrapperBuilder assignSavingsOfficer(final Long accountId) { + this.actionName = "UPDATESAVINGSOFFICER"; this.entityName = "SAVINGSACCOUNT"; this.entityId = accountId; - this.href = "/savingsaccounts/" + accountId + "?command=assignFieldOfficer"; + this.href = "/savingsaccounts/" + accountId + "?command=assignSavingsOfficer"; return this; } - public CommandWrapperBuilder unassignFieldOfficer(final Long accountId) { - this.actionName = "UNASSIGNFIELDOFFICER"; + public CommandWrapperBuilder unassignSavingsOfficer(final Long accountId) { + this.actionName = "REMOVESAVINGSOFFICER"; this.entityName = "SAVINGSACCOUNT"; this.entityId = accountId; - this.href = "/savingsaccounts/" + accountId + "?command=unassignFieldOfficer"; + this.href = "/savingsaccounts/" + accountId + "?commad=unassignSavingsOfficer"; return this; } diff --git a/mifosng-provider/src/main/java/org/mifosplatform/commands/service/SynchronousCommandProcessingService.java b/mifosng-provider/src/main/java/org/mifosplatform/commands/service/SynchronousCommandProcessingService.java index 2e7e942ba..bb146845e 100755 --- a/mifosng-provider/src/main/java/org/mifosplatform/commands/service/SynchronousCommandProcessingService.java +++ b/mifosng-provider/src/main/java/org/mifosplatform/commands/service/SynchronousCommandProcessingService.java @@ -512,10 +512,10 @@ public class SynchronousCommandProcessingService implements CommandProcessingSer handler = this.applicationContext.getBean("savingsTransactionAdjustmentCommandHandler", NewCommandSourceHandler.class); } else if (wrapper.isSavingsAccountClose()) { handler = this.applicationContext.getBean("closeSavingsAccountCommandHandler", NewCommandSourceHandler.class); - }else if(wrapper.isAssignStaffSavingsAccount()) { - handler = this.applicationContext.getBean("assignFieldOfficerSavingsAccountCommandHandler", NewCommandSourceHandler.class); - }else if(wrapper.isUnAssignStaffSavingsAccount()) { - handler = this.applicationContext.getBean("unassignFieldOfficerSavingsAccountCommandHandler", NewCommandSourceHandler.class); + }else if(wrapper.isUpdateSavingsOfficer()) { + handler = this.applicationContext.getBean("updateSavingsOfficerCommandHandler", NewCommandSourceHandler.class); + }else if(wrapper.isRemoveSavingsOfficer()) { + handler = this.applicationContext.getBean("removeSavingsOfficerCommandHandler", NewCommandSourceHandler.class); } else { throw new UnsupportedCommandException(wrapper.commandName()); diff --git a/mifosng-provider/src/main/java/org/mifosplatform/organisation/staff/exception/StaffRoleException.java b/mifosng-provider/src/main/java/org/mifosplatform/organisation/staff/exception/StaffRoleException.java index 1ea7ddfa6..6d585d2cc 100644 --- a/mifosng-provider/src/main/java/org/mifosplatform/organisation/staff/exception/StaffRoleException.java +++ b/mifosng-provider/src/main/java/org/mifosplatform/organisation/staff/exception/StaffRoleException.java @@ -13,7 +13,7 @@ import org.mifosplatform.infrastructure.core.exception.AbstractPlatformResourceN public class StaffRoleException extends AbstractPlatformResourceNotFoundException { public static enum STAFF_ROLE { - LOAN_OFFICER, BRANCH_MANAGER; + LOAN_OFFICER, BRANCH_MANAGER,SAVINGS_OFFICER; @Override public String toString() { diff --git a/mifosng-provider/src/main/java/org/mifosplatform/portfolio/savings/SavingsApiConstants.java b/mifosng-provider/src/main/java/org/mifosplatform/portfolio/savings/SavingsApiConstants.java index 070149964..9cf393ff7 100644 --- a/mifosng-provider/src/main/java/org/mifosplatform/portfolio/savings/SavingsApiConstants.java +++ b/mifosng-provider/src/main/java/org/mifosplatform/portfolio/savings/SavingsApiConstants.java @@ -48,7 +48,7 @@ public class SavingsApiConstants { public static final String localeParamName = "locale"; public static final String dateFormatParamName = "dateFormat"; public static final String monthDayFormatParamName = "monthDayFormat"; - public static final String staffIdParamName = "staffId"; + public static final String staffIdParamName = "savingsOfficerId"; // savings product and account parameters public static final String idParamName = "id"; diff --git a/mifosng-provider/src/main/java/org/mifosplatform/portfolio/savings/api/SavingsAccountsApiResource.java b/mifosng-provider/src/main/java/org/mifosplatform/portfolio/savings/api/SavingsAccountsApiResource.java index 176b6363b..b8a1d1bcc 100644 --- a/mifosng-provider/src/main/java/org/mifosplatform/portfolio/savings/api/SavingsAccountsApiResource.java +++ b/mifosng-provider/src/main/java/org/mifosplatform/portfolio/savings/api/SavingsAccountsApiResource.java @@ -248,12 +248,12 @@ public class SavingsAccountsApiResource { } else if (is(commandParam, "close")) { final CommandWrapper commandRequest = builder.closeSavingsAccountApplication(accountId).build(); result = this.commandsSourceWritePlatformService.logCommandSource(commandRequest); - } else if (is(commandParam, "assignFieldOfficer")) { - final CommandWrapper commandRequest = builder.assignFieldOfficer(accountId).build(); + } else if (is(commandParam, "assignSavingsOfficer")) { + final CommandWrapper commandRequest = builder.assignSavingsOfficer(accountId).build(); result = this.commandsSourceWritePlatformService.logCommandSource(commandRequest); return this.toApiJsonSerializer.serialize(result); - } else if (is(commandParam, "unassignFieldOfficer")) { - final CommandWrapper commandRequest = builder.unassignFieldOfficer(accountId).build(); + } else if (is(commandParam, "unassignSavingsOfficer")) { + final CommandWrapper commandRequest = builder.unassignSavingsOfficer(accountId).build(); result = this.commandsSourceWritePlatformService.logCommandSource(commandRequest); return this.toApiJsonSerializer.serialize(result); } @@ -262,7 +262,7 @@ public class SavingsAccountsApiResource { // throw new UnrecognizedQueryParamException("command", commandParam, new Object[] { "reject", "withdrawnByApplicant", "approve", "undoapproval", "activate", "calculateInterest", - "postInterest", "close", "assignFieldOfficer", "unassignFieldOfficer" }); + "postInterest", "close", "assignSavingsOfficer", "unassignSavingsOfficer" }); } return this.toApiJsonSerializer.serialize(result); diff --git a/mifosng-provider/src/main/java/org/mifosplatform/portfolio/savings/data/SavingsAccountDataValidator.java b/mifosng-provider/src/main/java/org/mifosplatform/portfolio/savings/data/SavingsAccountDataValidator.java index 5ef646bda..e65f1ea36 100644 --- a/mifosng-provider/src/main/java/org/mifosplatform/portfolio/savings/data/SavingsAccountDataValidator.java +++ b/mifosng-provider/src/main/java/org/mifosplatform/portfolio/savings/data/SavingsAccountDataValidator.java @@ -391,50 +391,56 @@ public class SavingsAccountDataValidator { } - public void validateForAssignFieldOfficer(final String json) { + public void validateForAssignSavingsOfficer(final String json) { if (StringUtils.isBlank(json)) { throw new InvalidJsonException(); } + + final Set supportedParameters = new HashSet<>(Arrays.asList("fromSavingsOfficerId","toSavingsOfficerId","assignmentDate","locale","dateFormat")); final Type typeOfMap = new TypeToken>() {}.getType(); - - final Set supportedParametersUnassignStaff = new HashSet<>(Arrays.asList(SavingsApiConstants.staffIdParamName)); - - this.fromApiJsonHelper.checkForUnsupportedParameters(typeOfMap, json, supportedParametersUnassignStaff); - final JsonElement element = this.fromApiJsonHelper.parse(json); + this.fromApiJsonHelper.checkForUnsupportedParameters(typeOfMap, json, supportedParameters); final List dataValidationErrors = new ArrayList<>(); + final DataValidatorBuilder baseDataValidator = new DataValidatorBuilder(dataValidationErrors).resource(SavingsApiConstants.SAVINGS_ACCOUNT_RESOURCE_NAME); - final DataValidatorBuilder baseDataValidator = new DataValidatorBuilder(dataValidationErrors) - .resource(SavingsApiConstants.SAVINGS_ACCOUNT_RESOURCE_NAME); + final JsonElement element = this.fromApiJsonHelper.parse(json); - final String staffIdParameterName = SavingsApiConstants.staffIdParamName; - final Long staffId = this.fromApiJsonHelper.extractLongNamed(staffIdParameterName, element); - baseDataValidator.reset().parameter(staffIdParameterName).value(staffId).notNull().longGreaterThanZero(); + final Long toSavingsOfficerId = this.fromApiJsonHelper.extractLongNamed("toSavingsOfficerId", element); + baseDataValidator.reset().parameter("toSavingsOfficerId").value(toSavingsOfficerId).notNull().integerGreaterThanZero(); - if (!dataValidationErrors.isEmpty()) { throw new PlatformApiDataValidationException(dataValidationErrors); } + final String assignmentDateStr = this.fromApiJsonHelper.extractStringNamed("assignmentDate", element); + baseDataValidator.reset().parameter("assignmentDate").value(assignmentDateStr).notBlank(); + + if (!StringUtils.isBlank(assignmentDateStr)) { + final LocalDate assignmentDate = this.fromApiJsonHelper.extractLocalDateNamed("assignmentDate", element); + baseDataValidator.reset().parameter("assignmentDate").value(assignmentDate).notNull(); + } + if (!dataValidationErrors.isEmpty()) { throw new PlatformApiDataValidationException("validation.msg.validation.errors.exist", + "Validation errors exist.", dataValidationErrors); } } - public void validateForUnAssignFieldOfficer(final String json) { - if (StringUtils.isBlank(json)) { throw new InvalidJsonException(); } + public void validateForUnAssignSavingsOfficer(final String json) { + if (StringUtils.isBlank(json)) { throw new InvalidJsonException(); } + + final Set supportedParameters = new HashSet<>(Arrays.asList("unassignedDate","locale","dateFormat")); final Type typeOfMap = new TypeToken>() {}.getType(); - - final Set supportedParametersUnassignStaff = new HashSet<>(Arrays.asList(SavingsApiConstants.staffIdParamName)); - - this.fromApiJsonHelper.checkForUnsupportedParameters(typeOfMap, json, supportedParametersUnassignStaff); - final JsonElement element = this.fromApiJsonHelper.parse(json); + this.fromApiJsonHelper.checkForUnsupportedParameters(typeOfMap, json, supportedParameters); final List dataValidationErrors = new ArrayList<>(); + final DataValidatorBuilder baseDataValidator = new DataValidatorBuilder(dataValidationErrors).resource(SavingsApiConstants.SAVINGS_ACCOUNT_RESOURCE_NAME); - final DataValidatorBuilder baseDataValidator = new DataValidatorBuilder(dataValidationErrors) - .resource(SavingsApiConstants.SAVINGS_ACCOUNT_RESOURCE_NAME); + final JsonElement element = this.fromApiJsonHelper.parse(json); - final String staffIdParameterName = SavingsApiConstants.staffIdParamName; - final Long staffId = this.fromApiJsonHelper.extractLongNamed(staffIdParameterName, element); - baseDataValidator.reset().parameter(staffIdParameterName).value(staffId).notNull().longGreaterThanZero(); + final String unassignedDateStr = this.fromApiJsonHelper.extractStringNamed("unassignedDate", element); + baseDataValidator.reset().parameter("unassignedDate").value(unassignedDateStr).notBlank(); - if (!dataValidationErrors.isEmpty()) { throw new PlatformApiDataValidationException(dataValidationErrors); } - - } + if (!StringUtils.isBlank(unassignedDateStr)) { + final LocalDate unassignedDate = this.fromApiJsonHelper.extractLocalDateNamed("unassignedDate", element); + baseDataValidator.reset().parameter("unassignedDate").value(unassignedDate).notNull(); + } + if (!dataValidationErrors.isEmpty()) { throw new PlatformApiDataValidationException("validation.msg.validation.errors.exist", + "Validation errors exist.", dataValidationErrors); } +} } \ No newline at end of file diff --git a/mifosng-provider/src/main/java/org/mifosplatform/portfolio/savings/domain/FixedDepositAccount.java b/mifosng-provider/src/main/java/org/mifosplatform/portfolio/savings/domain/FixedDepositAccount.java index 8b0b72e34..4c5a53536 100644 --- a/mifosng-provider/src/main/java/org/mifosplatform/portfolio/savings/domain/FixedDepositAccount.java +++ b/mifosng-provider/src/main/java/org/mifosplatform/portfolio/savings/domain/FixedDepositAccount.java @@ -728,7 +728,7 @@ public class FixedDepositAccount extends SavingsAccount { final boolean withdrawalFeeApplicableForTransfer = false; final String accountNumber = null; final FixedDepositAccount reInvestedAccount = FixedDepositAccount - .createNewApplicationForSubmittal(client, group, product, fieldOfficer, accountNumber, externalId, accountType, + .createNewApplicationForSubmittal(client, group, product, savingsOfficer, accountNumber, externalId, accountType, getClosedOnDate(), closedBy, interestRate, compoundingPeriodType, postingPeriodType, interestCalculationType, daysInYearType, minRequiredOpeningBalance, lockinPeriodFrequency, lockinPeriodFrequencyType, withdrawalFeeApplicableForTransfer, savingsAccountCharges, newAccountTermAndPreClosure, newChart); diff --git a/mifosng-provider/src/main/java/org/mifosplatform/portfolio/savings/domain/RecurringDepositAccount.java b/mifosng-provider/src/main/java/org/mifosplatform/portfolio/savings/domain/RecurringDepositAccount.java index 7a988d52f..326d38692 100644 --- a/mifosng-provider/src/main/java/org/mifosplatform/portfolio/savings/domain/RecurringDepositAccount.java +++ b/mifosng-provider/src/main/java/org/mifosplatform/portfolio/savings/domain/RecurringDepositAccount.java @@ -1006,7 +1006,7 @@ public class RecurringDepositAccount extends SavingsAccount { newAccountTermAndPreClosure.updateExpectedFirstDepositDate(now); - RecurringDepositAccount rdAccount = RecurringDepositAccount.createNewActivatedAccount(client, group, product, fieldOfficer, + RecurringDepositAccount rdAccount = RecurringDepositAccount.createNewActivatedAccount(client, group, product, savingsOfficer, accountNumber, externalId, accountType, getClosedOnDate(), closedBy, interestRate, compoundingPeriodType, postingPeriodType, interestCalculationType, daysInYearType, minRequiredOpeningBalance, lockinPeriodFrequency, lockinPeriodFrequencyType, withdrawalFeeApplicableForTransfer, savingsAccountCharges, newAccountTermAndPreClosure, diff --git a/mifosng-provider/src/main/java/org/mifosplatform/portfolio/savings/domain/SavingsAccount.java b/mifosng-provider/src/main/java/org/mifosplatform/portfolio/savings/domain/SavingsAccount.java index b36157080..07f818b73 100644 --- a/mifosng-provider/src/main/java/org/mifosplatform/portfolio/savings/domain/SavingsAccount.java +++ b/mifosng-provider/src/main/java/org/mifosplatform/portfolio/savings/domain/SavingsAccount.java @@ -75,6 +75,8 @@ import org.mifosplatform.portfolio.charge.exception.SavingsAccountChargeNotFound import org.mifosplatform.portfolio.client.domain.Client; import org.mifosplatform.portfolio.common.domain.PeriodFrequencyType; import org.mifosplatform.portfolio.group.domain.Group; +import org.mifosplatform.portfolio.savings.exception.SavingsOfficerAssignmentDateException; +import org.mifosplatform.portfolio.savings.domain.SavingsOfficerAssignmentHistory; import org.mifosplatform.portfolio.savings.DepositAccountType; import org.mifosplatform.portfolio.savings.SavingsApiConstants; import org.mifosplatform.portfolio.savings.SavingsCompoundingInterestPeriodType; @@ -87,6 +89,7 @@ import org.mifosplatform.portfolio.savings.domain.interest.PostingPeriod; import org.mifosplatform.portfolio.savings.exception.InsufficientAccountBalanceException; import org.mifosplatform.portfolio.savings.exception.SavingsAccountTransactionNotFoundException; import org.mifosplatform.portfolio.savings.exception.SavingsActivityPriorToClientTransferException; +import org.mifosplatform.portfolio.savings.exception.SavingsOfficerUnassignmentDateException; import org.mifosplatform.portfolio.savings.exception.SavingsTransferTransactionsCannotBeUndoneException; import org.mifosplatform.portfolio.savings.service.SavingsEnumerations; import org.mifosplatform.useradministration.domain.AppUser; @@ -123,7 +126,7 @@ public class SavingsAccount extends AbstractPersistable { @ManyToOne @JoinColumn(name = "field_officer_id", nullable = true) - protected Staff fieldOfficer; + protected Staff savingsOfficer; @Column(name = "status_enum", nullable = false) protected Integer status; @@ -263,6 +266,10 @@ public class SavingsAccount extends AbstractPersistable { @OneToMany(cascade = CascadeType.ALL, mappedBy = "savingsAccount", orphanRemoval = true) protected Set charges = new HashSet<>(); + @LazyCollection(LazyCollectionOption.FALSE) + @OneToMany(cascade = CascadeType.ALL, mappedBy = "savingsAccount", orphanRemoval = true) + private Set savingsOfficerHistory; + @Transient protected boolean accountNumberRequiresAutoGeneration = false; @Transient @@ -279,7 +286,7 @@ public class SavingsAccount extends AbstractPersistable { protected SavingsAccount() { // } - + public static SavingsAccount createNewApplicationForSubmittal(final Client client, final Group group, final SavingsProduct product, final Staff fieldOfficer, final String accountNo, final String externalId, final AccountType accountType, final LocalDate submittedOnDate, final AppUser submittedBy, final BigDecimal interestRate, @@ -314,7 +321,7 @@ public class SavingsAccount extends AbstractPersistable { withdrawalFeeApplicableForTransfer, savingsAccountCharges, allowOverdraft, overdraftLimit, false, null); } - protected SavingsAccount(final Client client, final Group group, final SavingsProduct product, final Staff fieldOfficer, + protected SavingsAccount(final Client client, final Group group, final SavingsProduct product, final Staff savingsOfficer, final String accountNo, final String externalId, final SavingsAccountStatusType status, final AccountType accountType, final LocalDate submittedOnDate, final AppUser submittedBy, final BigDecimal nominalAnnualInterestRate, final SavingsCompoundingInterestPeriodType interestCompoundingPeriodType, @@ -327,7 +334,7 @@ public class SavingsAccount extends AbstractPersistable { this.client = client; this.group = group; this.product = product; - this.fieldOfficer = fieldOfficer; + this.savingsOfficer = savingsOfficer; if (StringUtils.isBlank(accountNo)) { this.accountNumber = new RandomPasswordGenerator(19).generate(); this.accountNumberRequiresAutoGeneration = true; @@ -364,6 +371,7 @@ public class SavingsAccount extends AbstractPersistable { this.enforceMinRequiredBalance = enforceMinRequiredBalance; this.minRequiredBalance = minRequiredBalance; this.minBalanceForInterestCalculation = product.minBalanceForInterestCalculation(); + this.savingsOfficerHistory = null; } /** @@ -991,7 +999,7 @@ public class SavingsAccount extends AbstractPersistable { actualChanges.put(SavingsApiConstants.productIdParamName, newValue); } - if (command.isChangeInLongParameterNamed(SavingsApiConstants.fieldOfficerIdParamName, fieldOfficerId())) { + if (command.isChangeInLongParameterNamed(SavingsApiConstants.fieldOfficerIdParamName, hasSavingsOfficerId())) { final Long newValue = command.longValueOfParameterNamed(SavingsApiConstants.fieldOfficerIdParamName); actualChanges.put(SavingsApiConstants.fieldOfficerIdParamName, newValue); } @@ -1196,8 +1204,8 @@ public class SavingsAccount extends AbstractPersistable { this.minBalanceForInterestCalculation = product.minBalanceForInterestCalculation(); } - public void update(final Staff fieldOfficer) { - this.fieldOfficer = fieldOfficer; + public void update(final Staff savingsOfficer) { + this.savingsOfficer = savingsOfficer; } public void updateAccountNo(final String newAccountNo) { @@ -1241,16 +1249,16 @@ public class SavingsAccount extends AbstractPersistable { return office; } - public Staff getFieldOfficer() { - return this.fieldOfficer; + public Staff getSavingsOfficer() { + return this.savingsOfficer; } - public void unassignFieldOfficer() { - this.fieldOfficer = null; + public void unassignSavingsOfficer() { + this.savingsOfficer = null; } - public void assignFieldOfficer(final Staff fieldOfficer) { - this.fieldOfficer = fieldOfficer; + public void assignSavingsOfficer(final Staff fieldOfficer) { + this.savingsOfficer = fieldOfficer; } public Long clientId() { @@ -1269,14 +1277,149 @@ public class SavingsAccount extends AbstractPersistable { return id; } - public Long fieldOfficerId() { + public Long hasSavingsOfficerId() { Long id = null; - if (this.fieldOfficer != null) { - id = this.fieldOfficer.getId(); + if (this.savingsOfficer != null) { + id = this.savingsOfficer.getId(); } return id; } + + + public boolean hasSavingsOfficer(final Staff fromSavingsOfficer) { + boolean matchesCurrentSavingsOfficer = false; + if (this.savingsOfficer != null) { + matchesCurrentSavingsOfficer = this.savingsOfficer.identifiedBy(fromSavingsOfficer); + } else { + matchesCurrentSavingsOfficer = fromSavingsOfficer == null; + } + return matchesCurrentSavingsOfficer; + } + + public void reassignSavingsOfficer(final Staff newSavingsOfficer,final LocalDate assignmentDate) { + final SavingsOfficerAssignmentHistory latestHistoryRecord = findLatestIncompleteHistoryRecord(); + final SavingsOfficerAssignmentHistory lastAssignmentRecord = findLastAssignmentHistoryRecord(newSavingsOfficer); + + // assignment date should not be less than savings account submitted date + if (isSubmittedOnDateAfter(assignmentDate)) { + + final String errorMessage = "The Savings Officer assignment date (" + assignmentDate.toString() + + ") cannot be before savings submitted date (" + getSubmittedOnDate().toString() + ")."; + + throw new SavingsOfficerAssignmentDateException("cannot.be.before.savings.submitted.date", errorMessage, assignmentDate, + getSubmittedOnDate()); + + } else if (lastAssignmentRecord != null && lastAssignmentRecord.isEndDateAfter(assignmentDate)) { + + final String errorMessage = "The Savings Officer assignment date (" + assignmentDate + + ") cannot be before previous Savings Officer unassigned date (" + lastAssignmentRecord.getEndDate() + ")."; + + throw new SavingsOfficerAssignmentDateException("cannot.be.before.previous.unassignement.date", errorMessage, assignmentDate, + lastAssignmentRecord.getEndDate()); + + } else if (DateUtils.getLocalDateOfTenant().isBefore(assignmentDate)) { + + final String errorMessage = "The Savings Officer assignment date (" + assignmentDate + ") cannot be in the future."; + + throw new SavingsOfficerAssignmentDateException("cannot.be.a.future.date", errorMessage, assignmentDate); + + } else if (latestHistoryRecord != null && this.savingsOfficer.identifiedBy(newSavingsOfficer)) { + latestHistoryRecord.updateStartDate(assignmentDate); + } else if (latestHistoryRecord != null && latestHistoryRecord.matchesStartDateOf(assignmentDate)) { + latestHistoryRecord.updateSavingsOfficer(newSavingsOfficer); + this.savingsOfficer = newSavingsOfficer; + } else if (latestHistoryRecord != null && latestHistoryRecord.hasStartDateBefore(assignmentDate)) { + final String errorMessage = "Savings account with identifier " + getId() + " was already assigned before date " + assignmentDate; + throw new SavingsOfficerAssignmentDateException("is.before.last.assignment.date", errorMessage, getId(), assignmentDate); + } else { + if (latestHistoryRecord != null) { + // savings officer correctly changed from previous savings officer to + // new savings officer + latestHistoryRecord.updateEndDate(assignmentDate); + } + this.savingsOfficer = newSavingsOfficer; + if (isNotSubmittedAndPendingApproval()) { + final SavingsOfficerAssignmentHistory savingsOfficerAssignmentHistory = + SavingsOfficerAssignmentHistory.createNew(this,this.savingsOfficer,assignmentDate); + this.savingsOfficerHistory.add(savingsOfficerAssignmentHistory); + } + } + } + + + private SavingsOfficerAssignmentHistory findLastAssignmentHistoryRecord(final Staff newSavingsOfficer) { + + SavingsOfficerAssignmentHistory lastAssignmentRecordLatestEndDate = null; + for (final SavingsOfficerAssignmentHistory historyRecord : this.savingsOfficerHistory) { + + if (historyRecord.isCurrentRecord() && !historyRecord.isSameSavingsOfficer(newSavingsOfficer)) { + lastAssignmentRecordLatestEndDate = historyRecord; + break; + } + + if (lastAssignmentRecordLatestEndDate == null) { + lastAssignmentRecordLatestEndDate = historyRecord; + } else if (historyRecord.isEndDateAfter(lastAssignmentRecordLatestEndDate.getEndDate()) + && !historyRecord.isSameSavingsOfficer(newSavingsOfficer)) { + lastAssignmentRecordLatestEndDate = historyRecord; + } + } + return lastAssignmentRecordLatestEndDate; + } + + public boolean isSubmittedOnDateAfter(final LocalDate compareDate) { + return this.submittedOnDate == null ? false : new LocalDate(this.submittedOnDate).isAfter(compareDate); + } + + public LocalDate getSubmittedOnDate() { + return (LocalDate) ObjectUtils.defaultIfNull(new LocalDate(this.submittedOnDate), null); + } + + + public void removeSavingsOfficer(final LocalDate unassignDate) { + + final SavingsOfficerAssignmentHistory latestHistoryRecord = findLatestIncompleteHistoryRecord(); + + if (latestHistoryRecord != null) { + validateUnassignDate(latestHistoryRecord, unassignDate); + latestHistoryRecord.updateEndDate(unassignDate); + } + this.savingsOfficer = null; + } + + private SavingsOfficerAssignmentHistory findLatestIncompleteHistoryRecord() { + + SavingsOfficerAssignmentHistory latestRecordWithNoEndDate = null; + for (final SavingsOfficerAssignmentHistory historyRecord : this.savingsOfficerHistory) { + if (historyRecord.isCurrentRecord()) { + latestRecordWithNoEndDate = historyRecord; + break; + } + } + return latestRecordWithNoEndDate; + } + + private void validateUnassignDate(final SavingsOfficerAssignmentHistory latestHistoryRecord, final LocalDate unassignDate) { + + final LocalDate today = DateUtils.getLocalDateOfTenant(); + + if (latestHistoryRecord.getStartDate().isAfter(unassignDate)) { + + final String errorMessage = "The Savings officer Unassign date(" + unassignDate + ") cannot be before its assignment date (" + + latestHistoryRecord.getStartDate() + ")."; + + throw new SavingsOfficerUnassignmentDateException("cannot.be.before.assignment.date", errorMessage, getId(), getSavingsOfficer() + .getId(), latestHistoryRecord.getStartDate(), unassignDate); + + } else if (unassignDate.isAfter(today)) { + + final String errorMessage = "The Savings Officer Unassign date (" + unassignDate + ") cannot be in the future."; + + throw new SavingsOfficerUnassignmentDateException("cannot.be.a.future.date", errorMessage, unassignDate); + } + } + public MonetaryCurrency getCurrency() { return this.currency; } diff --git a/mifosng-provider/src/main/java/org/mifosplatform/portfolio/savings/domain/SavingsOfficerAssignmentHistory.java b/mifosng-provider/src/main/java/org/mifosplatform/portfolio/savings/domain/SavingsOfficerAssignmentHistory.java new file mode 100644 index 000000000..ba2cd3a2f --- /dev/null +++ b/mifosng-provider/src/main/java/org/mifosplatform/portfolio/savings/domain/SavingsOfficerAssignmentHistory.java @@ -0,0 +1,106 @@ +/** + * 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.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.apache.commons.lang.ObjectUtils; +import org.joda.time.LocalDate; +import org.mifosplatform.infrastructure.core.domain.AbstractAuditableCustom; +import org.mifosplatform.organisation.staff.domain.Staff; +import org.mifosplatform.useradministration.domain.AppUser; + +@Entity +@Table(name = "m_savings_officer_assignment_history") +public class SavingsOfficerAssignmentHistory extends AbstractAuditableCustom { + + @ManyToOne + @JoinColumn(name = "account_id", nullable = false) + private SavingsAccount savingsAccount; + + @ManyToOne + @JoinColumn(name = "savings_officer_id", nullable = true) + private Staff savingsOfficer; + + @Temporal(TemporalType.DATE) + @Column(name = "start_date") + private Date startDate; + + @Temporal(TemporalType.DATE) + @Column(name = "end_date") + private Date endDate; + + public static SavingsOfficerAssignmentHistory createNew(final SavingsAccount account, final Staff savingsOfficer,final LocalDate assignmentDate) { + return new SavingsOfficerAssignmentHistory(account, savingsOfficer,assignmentDate.toDate(),null); + } + + protected SavingsOfficerAssignmentHistory() { + // + } + + private SavingsOfficerAssignmentHistory(final SavingsAccount account, final Staff savingsOfficer,final Date startDate, final Date endDate) { + this.savingsAccount = account; + this.savingsOfficer = savingsOfficer; + this.startDate = startDate; + this.endDate = endDate; + } + + public void updateSavingsOfficer(final Staff savingsOfficer) { + this.savingsOfficer = savingsOfficer; + } + + public boolean isSameSavingsOfficer(final Staff staff) { + return this.savingsOfficer.identifiedBy(staff); + } + + + public void updateStartDate(final LocalDate startDate) { + this.startDate = startDate.toDate(); + } + + public void updateEndDate(final LocalDate endDate) { + this.endDate = endDate.toDate(); + } + + public boolean matchesStartDateOf(final LocalDate matchingDate) { + return getStartDate().isEqual(matchingDate); + } + + public LocalDate getStartDate() { + return new LocalDate(this.startDate); + } + + public boolean hasStartDateBefore(final LocalDate matchingDate) { + return matchingDate.isBefore(getStartDate()); + } + + public boolean isCurrentRecord() { + return this.endDate == null; + } + + /** + * If endDate is null then return false. + * + * @param compareDate + * @return + */ + public boolean isEndDateAfter(final LocalDate compareDate) { + return this.endDate == null ? false : new LocalDate(this.endDate).isAfter(compareDate); + } + + public LocalDate getEndDate() { + return (LocalDate) ObjectUtils.defaultIfNull(new LocalDate(this.endDate), null); + } + + } diff --git a/mifosng-provider/src/main/java/org/mifosplatform/portfolio/savings/exception/SavingsOfficerAssignmentDateException.java b/mifosng-provider/src/main/java/org/mifosplatform/portfolio/savings/exception/SavingsOfficerAssignmentDateException.java new file mode 100644 index 000000000..a06732480 --- /dev/null +++ b/mifosng-provider/src/main/java/org/mifosplatform/portfolio/savings/exception/SavingsOfficerAssignmentDateException.java @@ -0,0 +1,16 @@ +/** + * 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.exception; + +import org.mifosplatform.infrastructure.core.exception.AbstractPlatformDomainRuleException; + +public class SavingsOfficerAssignmentDateException extends AbstractPlatformDomainRuleException { + + public SavingsOfficerAssignmentDateException(final String postFix, final String defaultUserMessage, final Object... defaultUserMessageArgs) { + super("error.msg.savings.assignment.date." + postFix, defaultUserMessage, defaultUserMessageArgs); + } + +} \ No newline at end of file diff --git a/mifosng-provider/src/main/java/org/mifosplatform/portfolio/savings/exception/SavingsOfficerAssignmentException.java b/mifosng-provider/src/main/java/org/mifosplatform/portfolio/savings/exception/SavingsOfficerAssignmentException.java new file mode 100644 index 000000000..c79563eac --- /dev/null +++ b/mifosng-provider/src/main/java/org/mifosplatform/portfolio/savings/exception/SavingsOfficerAssignmentException.java @@ -0,0 +1,16 @@ +/** + * 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.exception; + +import org.mifosplatform.infrastructure.core.exception.AbstractPlatformDomainRuleException; + +public class SavingsOfficerAssignmentException extends AbstractPlatformDomainRuleException { + + public SavingsOfficerAssignmentException(final Long accountId, final Long fromSavingsOfficerId) { + super("error.msg.savings.account.not.assigned.to.savings.officer", "Savings Account Identifier " + accountId + + " is not assigned to Savings Officer with identifier " + fromSavingsOfficerId + ".", accountId); + } +} diff --git a/mifosng-provider/src/main/java/org/mifosplatform/portfolio/savings/exception/SavingsOfficerUnassignmentDateException.java b/mifosng-provider/src/main/java/org/mifosplatform/portfolio/savings/exception/SavingsOfficerUnassignmentDateException.java new file mode 100644 index 000000000..d2357cd93 --- /dev/null +++ b/mifosng-provider/src/main/java/org/mifosplatform/portfolio/savings/exception/SavingsOfficerUnassignmentDateException.java @@ -0,0 +1,17 @@ +/** + * 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.exception; + + +import org.mifosplatform.infrastructure.core.exception.AbstractPlatformDomainRuleException; + +public class SavingsOfficerUnassignmentDateException extends AbstractPlatformDomainRuleException { + + public SavingsOfficerUnassignmentDateException(final String postFix, final String defaultUserMessage, + final Object... defaultUserMessageArgs) { + super("error.msg.savings.savingsofficer.unassign.date." + postFix, defaultUserMessage, defaultUserMessageArgs); + } +} diff --git a/mifosng-provider/src/main/java/org/mifosplatform/portfolio/savings/exception/SavingsOfficerUnassignmentException.java b/mifosng-provider/src/main/java/org/mifosplatform/portfolio/savings/exception/SavingsOfficerUnassignmentException.java new file mode 100644 index 000000000..a7cf2eaf8 --- /dev/null +++ b/mifosng-provider/src/main/java/org/mifosplatform/portfolio/savings/exception/SavingsOfficerUnassignmentException.java @@ -0,0 +1,15 @@ +/** + * 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.exception; + +import org.mifosplatform.infrastructure.core.exception.AbstractPlatformDomainRuleException; + +public class SavingsOfficerUnassignmentException extends AbstractPlatformDomainRuleException { + + public SavingsOfficerUnassignmentException(final Long accountId) { + super("error.msg.savings.account.not.assigned.to.savings.officer", "Savings Account Identifier" + accountId + " is not assigned to any savings officer."); + } +} diff --git a/mifosng-provider/src/main/java/org/mifosplatform/portfolio/savings/handler/UnassignFieldOfficerSavingsAccountCommandHandler.java b/mifosng-provider/src/main/java/org/mifosplatform/portfolio/savings/handler/RemoveSavingsOfficerCommandHandler.java similarity index 82% rename from mifosng-provider/src/main/java/org/mifosplatform/portfolio/savings/handler/UnassignFieldOfficerSavingsAccountCommandHandler.java rename to mifosng-provider/src/main/java/org/mifosplatform/portfolio/savings/handler/RemoveSavingsOfficerCommandHandler.java index b9056ed85..4186ab07c 100644 --- a/mifosng-provider/src/main/java/org/mifosplatform/portfolio/savings/handler/UnassignFieldOfficerSavingsAccountCommandHandler.java +++ b/mifosng-provider/src/main/java/org/mifosplatform/portfolio/savings/handler/RemoveSavingsOfficerCommandHandler.java @@ -14,12 +14,12 @@ import org.springframework.stereotype.Service; import org.springframework.transaction.annotation.Transactional; @Service -public class UnassignFieldOfficerSavingsAccountCommandHandler implements NewCommandSourceHandler { +public class RemoveSavingsOfficerCommandHandler implements NewCommandSourceHandler { private final SavingsAccountWritePlatformService savingsWritePlatformService; @Autowired - public UnassignFieldOfficerSavingsAccountCommandHandler(final SavingsAccountWritePlatformService savingAccountWritePlatformService) { + public RemoveSavingsOfficerCommandHandler(final SavingsAccountWritePlatformService savingAccountWritePlatformService) { this.savingsWritePlatformService = savingAccountWritePlatformService; } diff --git a/mifosng-provider/src/main/java/org/mifosplatform/portfolio/savings/handler/AssignFieldOfficerSavingsAccountCommandHandler.java b/mifosng-provider/src/main/java/org/mifosplatform/portfolio/savings/handler/UpdateSavingsOfficerCommandHandler.java similarity index 83% rename from mifosng-provider/src/main/java/org/mifosplatform/portfolio/savings/handler/AssignFieldOfficerSavingsAccountCommandHandler.java rename to mifosng-provider/src/main/java/org/mifosplatform/portfolio/savings/handler/UpdateSavingsOfficerCommandHandler.java index d1647be4b..8155caca7 100644 --- a/mifosng-provider/src/main/java/org/mifosplatform/portfolio/savings/handler/AssignFieldOfficerSavingsAccountCommandHandler.java +++ b/mifosng-provider/src/main/java/org/mifosplatform/portfolio/savings/handler/UpdateSavingsOfficerCommandHandler.java @@ -14,12 +14,12 @@ import org.springframework.stereotype.Service; import org.springframework.transaction.annotation.Transactional; @Service -public class AssignFieldOfficerSavingsAccountCommandHandler implements NewCommandSourceHandler { +public class UpdateSavingsOfficerCommandHandler implements NewCommandSourceHandler { private final SavingsAccountWritePlatformService savingsWritePlatformService; @Autowired - public AssignFieldOfficerSavingsAccountCommandHandler(final SavingsAccountWritePlatformService savingAccountWritePlatformService) { + public UpdateSavingsOfficerCommandHandler(final SavingsAccountWritePlatformService savingAccountWritePlatformService) { this.savingsWritePlatformService = savingAccountWritePlatformService; } diff --git a/mifosng-provider/src/main/java/org/mifosplatform/portfolio/savings/service/SavingsAccountWritePlatformServiceJpaRepositoryImpl.java b/mifosng-provider/src/main/java/org/mifosplatform/portfolio/savings/service/SavingsAccountWritePlatformServiceJpaRepositoryImpl.java index cf774ea88..821dadddb 100644 --- a/mifosng-provider/src/main/java/org/mifosplatform/portfolio/savings/service/SavingsAccountWritePlatformServiceJpaRepositoryImpl.java +++ b/mifosng-provider/src/main/java/org/mifosplatform/portfolio/savings/service/SavingsAccountWritePlatformServiceJpaRepositoryImpl.java @@ -81,6 +81,8 @@ import org.mifosplatform.portfolio.savings.domain.SavingsAccountTransaction; import org.mifosplatform.portfolio.savings.domain.SavingsAccountTransactionRepository; import org.mifosplatform.portfolio.savings.exception.SavingsAccountClosingNotAllowedException; import org.mifosplatform.portfolio.savings.exception.SavingsAccountTransactionNotFoundException; +import org.mifosplatform.portfolio.savings.exception.SavingsOfficerAssignmentException; +import org.mifosplatform.portfolio.savings.exception.SavingsOfficerUnassignmentException; import org.mifosplatform.portfolio.savings.exception.TransactionUpdateNotAllowedException; import org.mifosplatform.useradministration.domain.AppUser; import org.springframework.beans.factory.annotation.Autowired; @@ -1021,66 +1023,72 @@ public class SavingsAccountWritePlatformServiceJpaRepositoryImpl implements Savi return null; } + @Transactional @Override public CommandProcessingResult assignFieldOfficer(Long savingsAccountId, JsonCommand command) { this.context.authenticatedUser(); - final Map actualChanges = new LinkedHashMap<>(5); - this.fromApiJsonDeserializer.validateForAssignFieldOfficer(command.json()); + Staff fromSavingsOfficer = null; + Staff toSavingsOfficer = null; + this.fromApiJsonDeserializer.validateForAssignSavingsOfficer(command.json()); final SavingsAccount savingsForUpdate = this.savingsRepository.findOneWithNotFoundDetection(savingsAccountId); - - Staff staff = null; - final Long staffId = command.longValueOfParameterNamed(SavingsApiConstants.staffIdParamName); - if (staffId != null) { - staff = this.staffRepository.findByOfficeHierarchyWithNotFoundDetection(staffId, savingsForUpdate.office().getHierarchy()); - - savingsForUpdate.assignFieldOfficer(staff); + final Long fromSavingsOfficerId = command.longValueOfParameterNamed("fromSavingsOfficerId"); + final Long toSavingsOfficerId = command.longValueOfParameterNamed("toSavingsOfficerId"); + final LocalDate dateOfSavingsOfficerAssignment = command.localDateValueOfParameterNamed("assignmentDate"); + + if(fromSavingsOfficerId != null) + { + fromSavingsOfficer = this.staffRepository.findByOfficeHierarchyWithNotFoundDetection(fromSavingsOfficerId, savingsForUpdate.office().getHierarchy()); } + if(toSavingsOfficerId != null) + { + toSavingsOfficer = this.staffRepository.findByOfficeHierarchyWithNotFoundDetection(toSavingsOfficerId, savingsForUpdate.office().getHierarchy()); + } + if (!savingsForUpdate.hasSavingsOfficer(fromSavingsOfficer)) { throw new SavingsOfficerAssignmentException(savingsAccountId, fromSavingsOfficerId); } + + savingsForUpdate.reassignSavingsOfficer(toSavingsOfficer,dateOfSavingsOfficerAssignment); this.savingsRepository.saveAndFlush(savingsForUpdate); - actualChanges.put(SavingsApiConstants.staffIdParamName, staffId); + actualChanges.put("toSavingsOfficerId", toSavingsOfficer.getId()); return new CommandProcessingResultBuilder() // .withCommandId(command.commandId()) // .withOfficeId(savingsForUpdate.officeId()) // .withEntityId(savingsForUpdate.getId()) // - .withClientId(savingsAccountId) // + .withSavingsId(savingsAccountId) // .with(actualChanges) // .build(); } + @Transactional @Override public CommandProcessingResult unassignFieldOfficer(Long savingsAccountId, JsonCommand command) { - this.context.authenticatedUser(); + + this.context.authenticatedUser(); - final Map actualChanges = new LinkedHashMap<>(5); + final Map actualChanges = new LinkedHashMap<>(5); + this.fromApiJsonDeserializer.validateForUnAssignSavingsOfficer(command.json()); + + final SavingsAccount savingsForUpdate = this.savingsRepository.findOneWithNotFoundDetection(savingsAccountId); + if (savingsForUpdate.getSavingsOfficer() == null) { throw new SavingsOfficerUnassignmentException(savingsAccountId); } - this.fromApiJsonDeserializer.validateForUnAssignFieldOfficer(command.json()); + final LocalDate dateOfSavingsOfficerUnassigned = command.localDateValueOfParameterNamed("unassignedDate"); + + savingsForUpdate.removeSavingsOfficer(dateOfSavingsOfficerUnassigned); - final SavingsAccount savingsForUpdate = this.savingsRepository.findOneWithNotFoundDetection(savingsAccountId); - - final Staff presentStaff = savingsForUpdate.getFieldOfficer(); - Long presentStaffId = null; - if (presentStaff == null) { throw new ClientHasNoStaffException(savingsAccountId); } - presentStaffId = presentStaff.getId(); - final String staffIdParamName = SavingsApiConstants.staffIdParamName; - if (!command.isChangeInLongParameterNamed(staffIdParamName, presentStaffId)) { - savingsForUpdate.unassignFieldOfficer(); - } this.savingsRepository.saveAndFlush(savingsForUpdate); - actualChanges.put(staffIdParamName, presentStaffId); - + actualChanges.put("toSavingsOfficerId", null); + return new CommandProcessingResultBuilder() // .withCommandId(command.commandId()) // .withOfficeId(savingsForUpdate.officeId()) // .withEntityId(savingsForUpdate.getId()) // - .withClientId(savingsAccountId) // + .withSavingsId(savingsAccountId) // .with(actualChanges) // - .build(); - } - + .build(); + } } \ No newline at end of file