Customer Self Service : APIs for Third Party Beneficiary management and Third Party Account Transfers
Project: http://git-wip-us.apache.org/repos/asf/incubator-fineract/repo Commit: http://git-wip-us.apache.org/repos/asf/incubator-fineract/commit/2bd3b062 Tree: http://git-wip-us.apache.org/repos/asf/incubator-fineract/tree/2bd3b062 Diff: http://git-wip-us.apache.org/repos/asf/incubator-fineract/diff/2bd3b062 Branch: refs/heads/develop Commit: 2bd3b0625a182a9e4b300f096c45a2585445e556 Parents: 9d4d901 Author: Adi Narayana Raju <[email protected]> Authored: Wed May 4 13:00:41 2016 +0530 Committer: Adi Narayana Raju <[email protected]> Committed: Wed May 4 13:01:25 2016 +0530 ---------------------------------------------------------------------- api-docs/apiLive.htm | 379 +++++- .../commands/service/CommandWrapperBuilder.java | 25 + .../domain/ConfigurationDomainService.java | 4 + .../domain/ConfigurationDomainServiceJpa.java | 16 + .../service/TenantDatabaseUpgradeService.java | 2 +- ...arWritePlatformServiceJpaRepositoryImpl.java | 4 +- .../AccountTransfersReadPlatformService.java | 5 + ...AccountTransfersReadPlatformServiceImpl.java | 1120 ++++++++++-------- .../loanaccount/domain/LoanRepository.java | 6 +- .../domain/SavingsAccountRepository.java | 3 + .../api/SelfAccountTransferApiResource.java | 95 +- .../api/SelfBeneficiariesTPTApiConstants.java | 53 + .../api/SelfBeneficiariesTPTApiResource.java | 161 +++ .../account/data/SelfAccountTemplateData.java | 9 + .../account/data/SelfAccountTransferData.java | 9 +- .../data/SelfAccountTransferDataValidator.java | 49 +- .../account/data/SelfBeneficiariesTPTData.java | 69 ++ .../data/SelfBeneficiariesTPTDataValidator.java | 165 +++ .../account/domain/SelfBeneficiariesTPT.java | 136 +++ .../domain/SelfBeneficiariesTPTRepository.java | 28 + ...neficiaryTransferLimitExceededException.java | 30 + ...TransactionAmountLimitExceededException.java | 31 + .../InvalidAccountInformationException.java | 32 + .../exception/InvalidBeneficiaryException.java | 29 + .../AddSelfBeneficiariesTPTCommandHandler.java | 46 + ...eleteSelfBeneficiariesTPTCommandHandler.java | 46 + ...pdateSelfBeneficiariesTPTCommandHandler.java | 46 + ...SelfBeneficiariesTPTReadPlatformService.java | 36 + ...BeneficiariesTPTReadPlatformServiceImpl.java | 222 ++++ ...elfBeneficiariesTPTWritePlatformService.java | 32 + ...eneficiariesTPTWritePlatformServiceImpl.java | 212 ++++ ...tomer_self_service_third_party_transfers.sql | 24 + 32 files changed, 2620 insertions(+), 504 deletions(-) ---------------------------------------------------------------------- http://git-wip-us.apache.org/repos/asf/incubator-fineract/blob/2bd3b062/api-docs/apiLive.htm ---------------------------------------------------------------------- diff --git a/api-docs/apiLive.htm b/api-docs/apiLive.htm index c2fa328..3139b1a 100644 --- a/api-docs/apiLive.htm +++ b/api-docs/apiLive.htm @@ -3312,6 +3312,38 @@ <td></td> <td></td> </tr> + <tr> + <td><a href="#selfbentemplate">Beneficiary for Third Party Transfer</a></td> + <td>/self/beneficiaries/tpt/template</td> + <td></td> + <td><a href="#selfbentemplate">Beneficiary TPT Template</a></td> + <td></td> + <td></td> + </tr> + <tr> + <td></td> + <td>/self/beneficiaries/tpt</td> + <td><a href="#selfaddtpt">Add TPT Beneficiary</a></td> + <td><a href="#selfgettpt">Get TPT Beneficiary List</a></td> + <td><a href="#selfputtpt">Update TPT Beneficiary</a></td> + <td><a href="#selfdeletetpt">Delete TPT Beneficiary</a></td> + </tr> + <tr> + <td><a href="#selftpttransfertemplate">Third Party Account Transfers</a></td> + <td>self/accounttransfers/template?type="tpt"</td> + <td></td> + <td><a href="#selftpttransfertemplate">Third Party Account Transfer Template</a></td> + <td></td> + <td></td> + </tr> + <tr> + <td></td> + <td>self/accounttransfers?type="tpt"</td> + <td><a href="#selftpttransfer">Third Party Account Transfer</a></td> + <td></td> + <td></td> + <td></td> + </tr> </table> </div> </div> @@ -42193,7 +42225,35 @@ GET https://DomainName/api/v1/self/savingsaccounts/{accountId}/charges/{savingsA </code> <code class="method-response"> { - "accountOptions": [ + "fromAccountOptions": [ + { + "accountId": 1, + "accountNo": "00000001", + "accountType": { + "id": 2, + "code": "accountType.savings", + "value": "Savings Account" + }, + "clientId": 1, + "clientName": "ABC", + "officeId": 1, + "officeName": "HEAD OFFICE" + }, + { + "accountId": 5, + "accountNo": "00000005", + "accountType": { + "id": 1, + "code": "accountType.loan", + "value": "Loan Account" + }, + "clientId": 2, + "clientName": "XYZ", + "officeId": 3, + "officeName": "REGIONAL OFFICE" + } + ], + "toAccountOptions": [ { "accountId": 1, "accountNo": "00000001", @@ -42221,6 +42281,7 @@ GET https://DomainName/api/v1/self/savingsaccounts/{accountId}/charges/{savingsA "officeName": "REGIONAL OFFICE" } ] + } </code> </div> @@ -42262,6 +42323,322 @@ No Request Body: </div> </div> + <a id="selfbentemplate" name="selfbentemplate" class="old-syle-anchor"> </a> + <div class="method-section"> + <div class="method-description"> + <h2>Beneficiary Third Party Transfer Template</h2> + <p>Returns Account Type enumerations. Self User is expected to know office name and account number to be able to add beneficiary.</p> + <p>Example Requests:</p> + <div class=apiClick>/self/beneficiaries/tpt/template</div> + </div> + <div class="method-example"> + <code class="method-declaration">GET https://DomainName/api/v1/self/beneficiaries/tpt/template + </code> + <code class="method-response"> + { + "accountTypeOptions": + [ + { + "id": 2, + "code": "accountType.savings", + "value": "Savings Account" + }, + { + "id": 1, + "code": "accountType.loan", + "value": "Loan Account" + } + ] + } + </code> + </div> + </div> + + <a id="selfaddtpt" name="selfaddtpt" class="old-syle-anchor"> </a> + <div class="method-section"> + <div class="method-description"> + <h2>Add TPT Beneficiary</h2> + <p>Api to add third party beneficiary linked to current user.</p> + <p>Parameter Definitions</p> + <p>name : Nick name for beneficiary, should be unique for an self service user</p> + <p>officeName : Office Name of beneficiary(not id)</p> + <p>accountNumber : Account Number of beneficiary(not id)</p> + <p>transferLimit : Each transfer initiated to this account will not exceed this amount</p> + <p>Example Requests:</p> + <div class=apiClick>/self/beneficiaries/tpt</div> + <table class=matrixHeading> + <tr class="matrixHeadingBG"> + <td><div class="fineractHeading2">Mandatory Fields</div></td> + </tr> + <tr class=alt> + <td>name, officeName, accountNumber, accountType</td> + </tr> + </table> + <br/> + <table class=matrixHeading> + <tr class="matrixHeadingBG"> + <td><div class="fineractHeading2">Optional Fields</div></td> + </tr> + <tr class=alt> + <td>transferLimit + </td> + </tr> + </table> + </div> + + <div class="method-example"> + <code class="method-declaration">POST https://DomainName/api/v1/self/beneficiaries/tpt + </code> + <code class="method-request"> +POST self/beneficiaries/tpt +Content-Type: application/json +Request Body: +{ + "locale": "en_GB", + "name": "beneficiary nick name", + "officeName": "HEAD OFFICE", + "accountNumber": "0000001", + "accountType": 1, + "transferLimit": 1000 + +} + </code> + <code class="method-response"> +{ + "resourceId": 5 +} + </code> + </div> + </div> + + <a id="selfgettpt" name="selfgettpt" class="old-syle-anchor"> </a> + <div class="method-section"> + <div class="method-description"> + <h2>Get All TPT Beneficiary</h2> + <p>Api to get all third party beneficiary linked to current user.</p> + <p>Example Requests:</p> + <div class=apiClick>/self/beneficiaries/tpt</div> + </div> + + <div class="method-example"> + <code class="method-declaration">GET https://DomainName/api/v1/self/beneficiaries/tpt + </code> + <code class="method-request"> +GET self/beneficiaries/tpt +Content-Type: application/json + </code> + <code class="method-response"> +{ +[ + { + "id": 1, + "name": "Client2Savings", + "officeName": "Test Office", + "clientName": "FN2 LN2", + "accountType": { + "id": 2, + "code": "accountType.savings", + "value": "Savings Account" + }, + "accountNumber": "000000002", + "transferLimit": 0 + }, + { + "id": 4, + "name": "Client2Loan", + "officeName": "Test Office", + "clientName": "FN2 LN2", + "accountType": { + "id": 1, + "code": "accountType.loan", + "value": "Loan Account" + }, + "accountNumber": "000000002", + "transferLimit": 1000 + }] +} + </code> + </div> + </div> + + <a id="selfputtpt" name="selfputtpt" class="old-syle-anchor"> </a> + <div class="method-section"> + <div class="method-description"> + <h2>Update TPT Beneficiary</h2> + <p>Api to update third party beneficiary linked to current user.</p> + <p>Example Requests:</p> + <div class=apiClick>/self/beneficiaries/tpt/{beneficiaryId}</div> + <br/> + <table class=matrixHeading> + <tr class="matrixHeadingBG"> + <td><div class="fineractHeading2">Optional Fields</div></td> + </tr> + <tr class=alt> + <td>name, transferLimit + </td> + </tr> + </table> + </div> + + <div class="method-example"> + <code class="method-declaration">PUT https://DomainName/api/v1/self/beneficiaries/tpt/{beneficiaryId} + </code> + <code class="method-request"> +PUT self/beneficiaries/tpt/5 +Content-Type: application/json +Request Body: +{ + "name": "beneficiary nick name", + "transferLimit": 1000 + +} + </code> + <code class="method-response"> +{ + "resourceId": 5, + "changes": { + "transferLimit": 1000, + "name": "Client22" + } +} + </code> + </div> + </div> + + <a id="selfdeletetpt" name="selfdeletetpt" class="old-syle-anchor"> </a> + <div class="method-section"> + <div class="method-description"> + <h2>Delete TPT Beneficiary</h2> + <p>Api to delete third party beneficiary linked to current user.</p> + <p>Example Requests:</p> + <div class=apiClick>/self/beneficiaries/tpt/{beneficiaryId}</div> + </div> + + <div class="method-example"> + <code class="method-declaration">DELETE https://DomainName/api/v1/self/beneficiaries/tpt/{beneficiaryId} + </code> + <code class="method-request"> +DELETE self/beneficiaries/tpt/5 +Content-Type: application/json + </code> + <code class="method-response"> +{ + "resourceId": 5 +} + </code> + </div> + </div> + + <a id="selftpttransfertemplate" name="selftpttransfertemplate" class="old-syle-anchor"> </a> + <div class="method-section"> + <div class="method-description"> + <h2>Third Party Account Transfer Template</h2> + <p>Returns list of loan/savings accounts that can be used for third party account transfer</p> + <p>Example Requests:</p> + <div class=apiClick>self/accounttransfers/template?type="tpt"</div> + </div> + <div class="method-example"> + <code class="method-declaration">GET https://DomainName/api/v1/self/accounttransfers/template?type="tpt" + </code> + <code class="method-response"> +{ + "fromAccountOptions": [ + { + "accountId": 1, + "accountNo": "00000001", + "accountType": { + "id": 2, + "code": "accountType.savings", + "value": "Savings Account" + }, + "clientId": 1, + "clientName": "ABC", + "officeId": 1, + "officeName": "HEAD OFFICE" + }, + { + "accountId": 5, + "accountNo": "00000005", + "accountType": { + "id": 1, + "code": "accountType.loan", + "value": "Loan Account" + }, + "clientId": 2, + "clientName": "XYZ", + "officeId": 3, + "officeName": "REGIONAL OFFICE" + } + ], + "toAccountOptions": [ + { + "accountId": 2, + "accountNo": "00000002", + "accountType": { + "id": 2, + "code": "accountType.savings", + "value": "Savings Account" + }, + "clientId": 2, + "clientName": "ABC", + "officeId": 1, + "officeName": "HEAD OFFICE" + }, + { + "accountId": 6, + "accountNo": "00000006", + "accountType": { + "id": 1, + "code": "accountType.loan", + "value": "Loan Account" + }, + "clientId": 3, + "clientName": "XYZ", + "officeId": 4, + "officeName": "REGIONAL OFFICE" + } + ] + +} + </code> + </div> + </div> + + <a id="selftpttransfer" name="selftpttransfer" class="old-syle-anchor"> </a> + <div class="method-section"> + <div class="method-description"> + <h2>Third Party Account Transfer</h2> + <p>Ability to create new third party transfer of monetary funds from one account to another.</p> + </div> + <div class="method-example"> + <code class="method-declaration">POST https://DomainName/api/v1/self/accounttransfers?type="tpt"</code> + <code class="method-request">POST self/accounttransfers?type="tpt" +Content-Type: application/json +No Request Body: +{ +"fromOfficeId": 1, +"fromClientId": 1, +"fromAccountType": 2, +"fromAccountId": 1, +"toOfficeId": 1, +"toClientId": 2, +"toAccountType": 2, +"toAccountId": 2, +"dateFormat": "dd MMMM yyyy", +"locale": "en", +"transferDate": "01 August 2011", +"transferAmount": "112.45", +"transferDescription": "A description of the transfer" +} + </code> + <code class="method-response"> +{ + "savingsId": 1, + "resourceId": 1 +} + </code> + </div> + </div> <!-- end of Customer Self Service APIs--> </div> <!-- main-content-wrapper --> http://git-wip-us.apache.org/repos/asf/incubator-fineract/blob/2bd3b062/fineract-provider/src/main/java/org/apache/fineract/commands/service/CommandWrapperBuilder.java ---------------------------------------------------------------------- diff --git a/fineract-provider/src/main/java/org/apache/fineract/commands/service/CommandWrapperBuilder.java b/fineract-provider/src/main/java/org/apache/fineract/commands/service/CommandWrapperBuilder.java index bd13574..5751e0e 100755 --- a/fineract-provider/src/main/java/org/apache/fineract/commands/service/CommandWrapperBuilder.java +++ b/fineract-provider/src/main/java/org/apache/fineract/commands/service/CommandWrapperBuilder.java @@ -2702,4 +2702,29 @@ public class CommandWrapperBuilder { this.href = "/savingsaccounts/" + accountId + "?commad=updateTaxWithHoldTax"; return this; } + + public CommandWrapperBuilder addSelfServiceBeneficiaryTPT() { + this.actionName = "CREATE"; + this.entityName = "SSBENEFICIARYTPT"; + this.entityId = null; + this.href = "/self/beneficiaries/tpt"; + return this; + } + + public CommandWrapperBuilder updateSelfServiceBeneficiaryTPT(final Long beneficiaryId) { + this.actionName = "UPDATE"; + this.entityName = "SSBENEFICIARYTPT"; + this.entityId = beneficiaryId; + this.href = "/self/beneficiaries/tpt/"+beneficiaryId; + return this; + } + + public CommandWrapperBuilder deleteSelfServiceBeneficiaryTPT(final Long beneficiaryId) { + this.actionName = "DELETE"; + this.entityName = "SSBENEFICIARYTPT"; + this.entityId = beneficiaryId; + this.href = "/self/beneficiaries/tpt/"+beneficiaryId; + return this; + } + } \ No newline at end of file http://git-wip-us.apache.org/repos/asf/incubator-fineract/blob/2bd3b062/fineract-provider/src/main/java/org/apache/fineract/infrastructure/configuration/domain/ConfigurationDomainService.java ---------------------------------------------------------------------- diff --git a/fineract-provider/src/main/java/org/apache/fineract/infrastructure/configuration/domain/ConfigurationDomainService.java b/fineract-provider/src/main/java/org/apache/fineract/infrastructure/configuration/domain/ConfigurationDomainService.java index 75aefb2..58494c2 100644 --- a/fineract-provider/src/main/java/org/apache/fineract/infrastructure/configuration/domain/ConfigurationDomainService.java +++ b/fineract-provider/src/main/java/org/apache/fineract/infrastructure/configuration/domain/ConfigurationDomainService.java @@ -79,4 +79,8 @@ public interface ConfigurationDomainService { boolean isChangeEmiIfRepaymentDateSameAsDisbursementDateEnabled(); + boolean isDailyTPTLimitEnabled(); + + Long getDailyTPTLimit(); + } \ No newline at end of file http://git-wip-us.apache.org/repos/asf/incubator-fineract/blob/2bd3b062/fineract-provider/src/main/java/org/apache/fineract/infrastructure/configuration/domain/ConfigurationDomainServiceJpa.java ---------------------------------------------------------------------- diff --git a/fineract-provider/src/main/java/org/apache/fineract/infrastructure/configuration/domain/ConfigurationDomainServiceJpa.java b/fineract-provider/src/main/java/org/apache/fineract/infrastructure/configuration/domain/ConfigurationDomainServiceJpa.java index 356d098..67ebdc5 100644 --- a/fineract-provider/src/main/java/org/apache/fineract/infrastructure/configuration/domain/ConfigurationDomainServiceJpa.java +++ b/fineract-provider/src/main/java/org/apache/fineract/infrastructure/configuration/domain/ConfigurationDomainServiceJpa.java @@ -19,6 +19,7 @@ package org.apache.fineract.infrastructure.configuration.domain; import java.util.Date; + import org.apache.commons.lang.StringUtils; import org.apache.fineract.infrastructure.cache.domain.CacheType; import org.apache.fineract.infrastructure.cache.domain.PlatformCache; @@ -209,6 +210,7 @@ public class ConfigurationDomainServiceJpa implements ConfigurationDomainService return defaultValue; } + @Override public boolean isBackdatePenaltiesEnabled() { final String propertyName = "backdate-penalties-enabled"; final GlobalConfigurationProperty property = this.globalConfigurationRepository.findOneByNameWithNotFoundDetection(propertyName); @@ -263,5 +265,19 @@ public class ConfigurationDomainServiceJpa implements ConfigurationDomainService return property.isEnabled(); } + @Override + public boolean isDailyTPTLimitEnabled() { + final String propertyName = "daily-tpt-limit"; + final GlobalConfigurationProperty property = this.globalConfigurationRepository.findOneByNameWithNotFoundDetection(propertyName); + return property.isEnabled(); + } + + @Override + public Long getDailyTPTLimit() { + final String propertyName = "daily-tpt-limit"; + final GlobalConfigurationProperty property = this.globalConfigurationRepository.findOneByNameWithNotFoundDetection(propertyName); + return property.getValue(); + } + } \ No newline at end of file http://git-wip-us.apache.org/repos/asf/incubator-fineract/blob/2bd3b062/fineract-provider/src/main/java/org/apache/fineract/infrastructure/core/service/TenantDatabaseUpgradeService.java ---------------------------------------------------------------------- diff --git a/fineract-provider/src/main/java/org/apache/fineract/infrastructure/core/service/TenantDatabaseUpgradeService.java b/fineract-provider/src/main/java/org/apache/fineract/infrastructure/core/service/TenantDatabaseUpgradeService.java index 8bf9199..740dcb5 100644 --- a/fineract-provider/src/main/java/org/apache/fineract/infrastructure/core/service/TenantDatabaseUpgradeService.java +++ b/fineract-provider/src/main/java/org/apache/fineract/infrastructure/core/service/TenantDatabaseUpgradeService.java @@ -74,7 +74,7 @@ public class TenantDatabaseUpgradeService { flyway.migrate(); } catch (FlywayException e) { String betterMessage = e.getMessage() + "; for Tenant DB URL: " + connectionProtocol + ", username: " - + connection.getSchemaPassword(); + + connection.getSchemaUsername(); throw new FlywayException(betterMessage, e.getCause()); } } http://git-wip-us.apache.org/repos/asf/incubator-fineract/blob/2bd3b062/fineract-provider/src/main/java/org/apache/fineract/infrastructure/jobs/service/SchedularWritePlatformServiceJpaRepositoryImpl.java ---------------------------------------------------------------------- diff --git a/fineract-provider/src/main/java/org/apache/fineract/infrastructure/jobs/service/SchedularWritePlatformServiceJpaRepositoryImpl.java b/fineract-provider/src/main/java/org/apache/fineract/infrastructure/jobs/service/SchedularWritePlatformServiceJpaRepositoryImpl.java index f4ac6ac..7e5d5de 100644 --- a/fineract-provider/src/main/java/org/apache/fineract/infrastructure/jobs/service/SchedularWritePlatformServiceJpaRepositoryImpl.java +++ b/fineract-provider/src/main/java/org/apache/fineract/infrastructure/jobs/service/SchedularWritePlatformServiceJpaRepositoryImpl.java @@ -136,11 +136,11 @@ public class SchedularWritePlatformServiceJpaRepositoryImpl implements Schedular boolean isStopExecution = false; final ScheduledJobDetail scheduledJobDetail = this.scheduledJobDetailsRepository.findByJobKeyWithLock(jobKey); if (scheduledJobDetail.isCurrentlyRunning() - || (triggerType == SchedulerServiceConstants.TRIGGER_TYPE_CRON && (scheduledJobDetail.getNextRunTime().after(new Date())))) { + || (triggerType.equals(SchedulerServiceConstants.TRIGGER_TYPE_CRON) && (scheduledJobDetail.getNextRunTime().after(new Date())))) { isStopExecution = true; } final SchedulerDetail schedulerDetail = retriveSchedulerDetail(); - if (triggerType == SchedulerServiceConstants.TRIGGER_TYPE_CRON && schedulerDetail.isSuspended()) { + if (triggerType.equals(SchedulerServiceConstants.TRIGGER_TYPE_CRON) && schedulerDetail.isSuspended()) { scheduledJobDetail.updateTriggerMisfired(true); isStopExecution = true; } else if (!isStopExecution) { http://git-wip-us.apache.org/repos/asf/incubator-fineract/blob/2bd3b062/fineract-provider/src/main/java/org/apache/fineract/portfolio/account/service/AccountTransfersReadPlatformService.java ---------------------------------------------------------------------- diff --git a/fineract-provider/src/main/java/org/apache/fineract/portfolio/account/service/AccountTransfersReadPlatformService.java b/fineract-provider/src/main/java/org/apache/fineract/portfolio/account/service/AccountTransfersReadPlatformService.java index c053b01..0434261 100644 --- a/fineract-provider/src/main/java/org/apache/fineract/portfolio/account/service/AccountTransfersReadPlatformService.java +++ b/fineract-provider/src/main/java/org/apache/fineract/portfolio/account/service/AccountTransfersReadPlatformService.java @@ -18,12 +18,14 @@ */ package org.apache.fineract.portfolio.account.service; +import java.math.BigDecimal; import java.util.Collection; import org.apache.fineract.infrastructure.core.service.Page; import org.apache.fineract.infrastructure.core.service.SearchParameters; import org.apache.fineract.portfolio.account.PortfolioAccountType; import org.apache.fineract.portfolio.account.data.AccountTransferData; +import org.joda.time.LocalDate; public interface AccountTransfersReadPlatformService { @@ -42,4 +44,7 @@ public interface AccountTransfersReadPlatformService { AccountTransferData retrieveRefundByTransferTemplate(Long fromOfficeId, Long fromClientId, Long fromAccountId, Integer fromAccountType, Long toOfficeId, Long toClientId, Long toAccountId, Integer toAccountType); + + BigDecimal getTotalTransactionAmount(Long accountId, Integer accountType, + LocalDate transactionDate); } \ No newline at end of file http://git-wip-us.apache.org/repos/asf/incubator-fineract/blob/2bd3b062/fineract-provider/src/main/java/org/apache/fineract/portfolio/account/service/AccountTransfersReadPlatformServiceImpl.java ---------------------------------------------------------------------- diff --git a/fineract-provider/src/main/java/org/apache/fineract/portfolio/account/service/AccountTransfersReadPlatformServiceImpl.java b/fineract-provider/src/main/java/org/apache/fineract/portfolio/account/service/AccountTransfersReadPlatformServiceImpl.java index 9dbe4c9..08af091 100644 --- a/fineract-provider/src/main/java/org/apache/fineract/portfolio/account/service/AccountTransfersReadPlatformServiceImpl.java +++ b/fineract-provider/src/main/java/org/apache/fineract/portfolio/account/service/AccountTransfersReadPlatformServiceImpl.java @@ -45,6 +45,8 @@ import org.apache.fineract.portfolio.account.exception.AccountTransferNotFoundEx import org.apache.fineract.portfolio.client.data.ClientData; import org.apache.fineract.portfolio.client.service.ClientReadPlatformService; import org.joda.time.LocalDate; +import org.joda.time.format.DateTimeFormat; +import org.joda.time.format.DateTimeFormatter; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.dao.EmptyResultDataAccessException; import org.springframework.jdbc.core.JdbcTemplate; @@ -53,485 +55,643 @@ import org.springframework.stereotype.Service; import org.springframework.util.CollectionUtils; @Service -public class AccountTransfersReadPlatformServiceImpl implements AccountTransfersReadPlatformService { - - private final JdbcTemplate jdbcTemplate; - private final ClientReadPlatformService clientReadPlatformService; - private final OfficeReadPlatformService officeReadPlatformService; - private final PortfolioAccountReadPlatformService portfolioAccountReadPlatformService; - - // mapper - private final AccountTransfersMapper accountTransfersMapper; - - // pagination - private final PaginationHelper<AccountTransferData> paginationHelper = new PaginationHelper<>(); - - @Autowired - public AccountTransfersReadPlatformServiceImpl(final RoutingDataSource dataSource, - final ClientReadPlatformService clientReadPlatformService, final OfficeReadPlatformService officeReadPlatformService, - final PortfolioAccountReadPlatformService portfolioAccountReadPlatformService) { - this.jdbcTemplate = new JdbcTemplate(dataSource); - this.clientReadPlatformService = clientReadPlatformService; - this.officeReadPlatformService = officeReadPlatformService; - this.portfolioAccountReadPlatformService = portfolioAccountReadPlatformService; - - this.accountTransfersMapper = new AccountTransfersMapper(); - } - - @Override - public AccountTransferData retrieveTemplate(final Long fromOfficeId, final Long fromClientId, final Long fromAccountId, - final Integer fromAccountType, final Long toOfficeId, final Long toClientId, final Long toAccountId, final Integer toAccountType) { - - final EnumOptionData loanAccountType = AccountTransferEnumerations.accountType(PortfolioAccountType.LOAN); - final EnumOptionData savingsAccountType = AccountTransferEnumerations.accountType(PortfolioAccountType.SAVINGS); - - final Integer mostRelevantFromAccountType = fromAccountType; - final Collection<EnumOptionData> fromAccountTypeOptions = Arrays.asList(savingsAccountType, loanAccountType); - final Collection<EnumOptionData> toAccountTypeOptions; - if (mostRelevantFromAccountType != null && mostRelevantFromAccountType == 1) { - // overpaid loan amt transfer to savings account - toAccountTypeOptions = Arrays.asList(savingsAccountType); - } else { - toAccountTypeOptions = Arrays.asList(loanAccountType, savingsAccountType); - } - final Integer mostRelevantToAccountType = toAccountType; - - final EnumOptionData fromAccountTypeData = AccountTransferEnumerations.accountType(mostRelevantFromAccountType); - final EnumOptionData toAccountTypeData = AccountTransferEnumerations.accountType(mostRelevantToAccountType); - - // from settings - OfficeData fromOffice = null; - ClientData fromClient = null; - PortfolioAccountData fromAccount = null; - - OfficeData toOffice = null; - ClientData toClient = null; - PortfolioAccountData toAccount = null; - - // template - Collection<PortfolioAccountData> fromAccountOptions = null; - Collection<PortfolioAccountData> toAccountOptions = null; - - Long mostRelevantFromOfficeId = fromOfficeId; - Long mostRelevantFromClientId = fromClientId; - - Long mostRelevantToOfficeId = toOfficeId; - Long mostRelevantToClientId = toClientId; - - if (fromAccountId != null) { - Integer accountType; - if (mostRelevantFromAccountType == 1) { - accountType = PortfolioAccountType.LOAN.getValue(); - } else { - accountType = PortfolioAccountType.SAVINGS.getValue(); - } - fromAccount = this.portfolioAccountReadPlatformService.retrieveOne(fromAccountId, accountType); - - // override provided fromClient with client of account - mostRelevantFromClientId = fromAccount.clientId(); - } - - if (mostRelevantFromClientId != null) { - fromClient = this.clientReadPlatformService.retrieveOne(mostRelevantFromClientId); - mostRelevantFromOfficeId = fromClient.officeId(); - long[] loanStatus = null; - if (mostRelevantFromAccountType == 1) { - loanStatus = new long[] { 300, 700 }; - } - PortfolioAccountDTO portfolioAccountDTO = new PortfolioAccountDTO(mostRelevantFromAccountType, mostRelevantFromClientId, - loanStatus); - fromAccountOptions = this.portfolioAccountReadPlatformService.retrieveAllForLookup(portfolioAccountDTO); - } - - Collection<OfficeData> fromOfficeOptions = null; - Collection<ClientData> fromClientOptions = null; - if (mostRelevantFromOfficeId != null) { - fromOffice = this.officeReadPlatformService.retrieveOffice(mostRelevantFromOfficeId); - fromOfficeOptions = this.officeReadPlatformService.retrieveAllOfficesForDropdown(); - fromClientOptions = this.clientReadPlatformService.retrieveAllForLookupByOfficeId(mostRelevantFromOfficeId); - } - - // defaults - final LocalDate transferDate = DateUtils.getLocalDateOfTenant(); - Collection<OfficeData> toOfficeOptions = fromOfficeOptions; - Collection<ClientData> toClientOptions = null; - - if (toAccountId != null && fromAccount != null) { - toAccount = this.portfolioAccountReadPlatformService.retrieveOne(toAccountId, mostRelevantToAccountType, - fromAccount.currencyCode()); - mostRelevantToClientId = toAccount.clientId(); - } - - if (mostRelevantToClientId != null) { - toClient = this.clientReadPlatformService.retrieveOne(mostRelevantToClientId); - mostRelevantToOfficeId = toClient.officeId(); - - toClientOptions = this.clientReadPlatformService.retrieveAllForLookupByOfficeId(mostRelevantToOfficeId); - - toAccountOptions = retrieveToAccounts(fromAccount, mostRelevantToAccountType, mostRelevantToClientId); - } - - if (mostRelevantToOfficeId != null) { - toOffice = this.officeReadPlatformService.retrieveOffice(mostRelevantToOfficeId); - toOfficeOptions = this.officeReadPlatformService.retrieveAllOfficesForDropdown(); - - toClientOptions = this.clientReadPlatformService.retrieveAllForLookupByOfficeId(mostRelevantToOfficeId); - if (toClientOptions != null && toClientOptions.size() == 1) { - toClient = new ArrayList<>(toClientOptions).get(0); - - toAccountOptions = retrieveToAccounts(fromAccount, mostRelevantToAccountType, mostRelevantToClientId); - } - } - - return AccountTransferData.template(fromOffice, fromClient, fromAccountTypeData, fromAccount, transferDate, toOffice, toClient, - toAccountTypeData, toAccount, fromOfficeOptions, fromClientOptions, fromAccountTypeOptions, fromAccountOptions, - toOfficeOptions, toClientOptions, toAccountTypeOptions, toAccountOptions); - } - - private Collection<PortfolioAccountData> retrieveToAccounts(final PortfolioAccountData excludeThisAccountFromOptions, - final Integer toAccountType, final Long toClientId) { - - final String currencyCode = excludeThisAccountFromOptions != null ? excludeThisAccountFromOptions.currencyCode() : null; - - PortfolioAccountDTO portfolioAccountDTO = new PortfolioAccountDTO(toAccountType, toClientId, currencyCode, null, null); - Collection<PortfolioAccountData> accountOptions = this.portfolioAccountReadPlatformService - .retrieveAllForLookup(portfolioAccountDTO); - if (!CollectionUtils.isEmpty(accountOptions)) { - accountOptions.remove(excludeThisAccountFromOptions); - } else { - accountOptions = null; - } - - return accountOptions; - } - - @Override - public Page<AccountTransferData> retrieveAll(final SearchParameters searchParameters, final Long accountDetailId) { - - final StringBuilder sqlBuilder = new StringBuilder(200); - sqlBuilder.append("select SQL_CALC_FOUND_ROWS "); - sqlBuilder.append(this.accountTransfersMapper.schema()); - Object[] finalObjectArray = {}; - if (accountDetailId != null) { - sqlBuilder.append(" where att.account_transfer_details_id=?"); - finalObjectArray = new Object[] { accountDetailId }; - } - - if (searchParameters.isOrderByRequested()) { - sqlBuilder.append(" order by ").append(searchParameters.getOrderBy()); - - if (searchParameters.isSortOrderProvided()) { - sqlBuilder.append(' ').append(searchParameters.getSortOrder()); - } - } - - if (searchParameters.isLimited()) { - sqlBuilder.append(" limit ").append(searchParameters.getLimit()); - if (searchParameters.isOffset()) { - sqlBuilder.append(" offset ").append(searchParameters.getOffset()); - } - } - - final String sqlCountRows = "SELECT FOUND_ROWS()"; - return this.paginationHelper.fetchPage(this.jdbcTemplate, sqlCountRows, sqlBuilder.toString(), finalObjectArray, - this.accountTransfersMapper); - } - - @Override - public AccountTransferData retrieveOne(final Long transferId) { - - try { - final String sql = "select " + this.accountTransfersMapper.schema() + " where att.id = ?"; - - return this.jdbcTemplate.queryForObject(sql, this.accountTransfersMapper, new Object[] { transferId }); - } catch (final EmptyResultDataAccessException e) { - throw new AccountTransferNotFoundException(transferId); - } - } - - @Override - public Collection<Long> fetchPostInterestTransactionIds(final Long accountId) { - final String sql = "select att.from_savings_transaction_id from m_account_transfer_transaction att inner join m_account_transfer_details atd on atd.id = att.account_transfer_details_id where atd.from_savings_account_id=? and att.is_reversed =0 and atd.transfer_type = ?"; - - final List<Long> transactionId = this.jdbcTemplate.queryForList(sql, Long.class, accountId, - AccountTransferType.INTEREST_TRANSFER.getValue()); - - return transactionId; - } - - private static final class AccountTransfersMapper implements RowMapper<AccountTransferData> { - - private final String schemaSql; - - public AccountTransfersMapper() { - final StringBuilder sqlBuilder = new StringBuilder(400); - sqlBuilder.append("att.id as id, att.is_reversed as isReversed,"); - sqlBuilder.append("att.transaction_date as transferDate, att.amount as transferAmount,"); - sqlBuilder.append("att.description as transferDescription,"); - sqlBuilder.append("att.currency_code as currencyCode, att.currency_digits as currencyDigits,"); - sqlBuilder.append("att.currency_multiplesof as inMultiplesOf, "); - sqlBuilder.append("curr.name as currencyName, curr.internationalized_name_code as currencyNameCode, "); - sqlBuilder.append("curr.display_symbol as currencyDisplaySymbol, "); - sqlBuilder.append("fromoff.id as fromOfficeId, fromoff.name as fromOfficeName,"); - sqlBuilder.append("tooff.id as toOfficeId, tooff.name as toOfficeName,"); - sqlBuilder.append("fromclient.id as fromClientId, fromclient.display_name as fromClientName,"); - sqlBuilder.append("toclient.id as toClientId, toclient.display_name as toClientName,"); - sqlBuilder.append("fromsavacc.id as fromSavingsAccountId, fromsavacc.account_no as fromSavingsAccountNo,"); - sqlBuilder.append("fromloanacc.id as fromLoanAccountId, fromloanacc.account_no as fromLoanAccountNo,"); - sqlBuilder.append("tosavacc.id as toSavingsAccountId, tosavacc.account_no as toSavingsAccountNo,"); - sqlBuilder.append("toloanacc.id as toLoanAccountId, toloanacc.account_no as toLoanAccountNo,"); - sqlBuilder.append("fromsavtran.id as fromSavingsAccountTransactionId,"); - sqlBuilder.append("fromsavtran.transaction_type_enum as fromSavingsAccountTransactionType,"); - sqlBuilder.append("tosavtran.id as toSavingsAccountTransactionId,"); - sqlBuilder.append("tosavtran.transaction_type_enum as toSavingsAccountTransactionType"); - sqlBuilder.append(" FROM m_account_transfer_transaction att "); - sqlBuilder.append("left join m_account_transfer_details atd on atd.id = att.account_transfer_details_id "); - sqlBuilder.append("join m_currency curr on curr.code = att.currency_code "); - sqlBuilder.append("join m_office fromoff on fromoff.id = atd.from_office_id "); - sqlBuilder.append("join m_office tooff on tooff.id = atd.to_office_id "); - sqlBuilder.append("join m_client fromclient on fromclient.id = atd.from_client_id "); - sqlBuilder.append("join m_client toclient on toclient.id = atd.to_client_id "); - sqlBuilder.append("left join m_savings_account fromsavacc on fromsavacc.id = atd.from_savings_account_id "); - sqlBuilder.append("left join m_loan fromloanacc on fromloanacc.id = atd.from_loan_account_id "); - sqlBuilder.append("left join m_savings_account tosavacc on tosavacc.id = atd.to_savings_account_id "); - sqlBuilder.append("left join m_loan toloanacc on toloanacc.id = atd.to_loan_account_id "); - sqlBuilder.append("left join m_savings_account_transaction fromsavtran on fromsavtran.id = att.from_savings_transaction_id "); - sqlBuilder.append("left join m_savings_account_transaction tosavtran on tosavtran.id = att.to_savings_transaction_id "); - sqlBuilder.append("left join m_loan_transaction fromloantran on fromloantran.id = att.from_savings_transaction_id "); - sqlBuilder.append("left join m_loan_transaction toloantran on toloantran.id = att.to_savings_transaction_id "); - - this.schemaSql = sqlBuilder.toString(); - } - - public String schema() { - return this.schemaSql; - } - - @Override - public AccountTransferData mapRow(final ResultSet rs, @SuppressWarnings("unused") final int rowNum) throws SQLException { - - final Long id = rs.getLong("id"); - final boolean reversed = rs.getBoolean("isReversed"); - - final LocalDate transferDate = JdbcSupport.getLocalDate(rs, "transferDate"); - final BigDecimal transferAmount = JdbcSupport.getBigDecimalDefaultToZeroIfNull(rs, "transferAmount"); - final String transferDescription = rs.getString("transferDescription"); - - 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 Integer inMultiplesOf = JdbcSupport.getInteger(rs, "inMultiplesOf"); - final CurrencyData currency = new CurrencyData(currencyCode, currencyName, currencyDigits, inMultiplesOf, - currencyDisplaySymbol, currencyNameCode); - - final Long fromOfficeId = JdbcSupport.getLong(rs, "fromOfficeId"); - final String fromOfficeName = rs.getString("fromOfficeName"); - final OfficeData fromOffice = OfficeData.dropdown(fromOfficeId, fromOfficeName, null); - - final Long toOfficeId = JdbcSupport.getLong(rs, "toOfficeId"); - final String toOfficeName = rs.getString("toOfficeName"); - final OfficeData toOffice = OfficeData.dropdown(toOfficeId, toOfficeName, null); - - final Long fromClientId = JdbcSupport.getLong(rs, "fromClientId"); - final String fromClientName = rs.getString("fromClientName"); - final ClientData fromClient = ClientData.lookup(fromClientId, fromClientName, fromOfficeId, fromOfficeName); - - final Long toClientId = JdbcSupport.getLong(rs, "toClientId"); - final String toClientName = rs.getString("toClientName"); - final ClientData toClient = ClientData.lookup(toClientId, toClientName, toOfficeId, toOfficeName); - - final Long fromSavingsAccountId = JdbcSupport.getLong(rs, "fromSavingsAccountId"); - final String fromSavingsAccountNo = rs.getString("fromSavingsAccountNo"); - final Long fromLoanAccountId = JdbcSupport.getLong(rs, "fromLoanAccountId"); - final String fromLoanAccountNo = rs.getString("fromLoanAccountNo"); - PortfolioAccountData fromAccount = null; - EnumOptionData fromAccountType = null; - if (fromSavingsAccountId != null) { - fromAccount = PortfolioAccountData.lookup(fromSavingsAccountId, fromSavingsAccountNo); - fromAccountType = AccountTransferEnumerations.accountType(PortfolioAccountType.SAVINGS); - } else if (fromLoanAccountId != null) { - fromAccount = PortfolioAccountData.lookup(fromLoanAccountId, fromLoanAccountNo); - fromAccountType = AccountTransferEnumerations.accountType(PortfolioAccountType.LOAN); - } - - PortfolioAccountData toAccount = null; - EnumOptionData toAccountType = null; - final Long toSavingsAccountId = JdbcSupport.getLong(rs, "toSavingsAccountId"); - final String toSavingsAccountNo = rs.getString("toSavingsAccountNo"); - final Long toLoanAccountId = JdbcSupport.getLong(rs, "toLoanAccountId"); - final String toLoanAccountNo = rs.getString("toLoanAccountNo"); - - if (toSavingsAccountId != null) { - toAccount = PortfolioAccountData.lookup(toSavingsAccountId, toSavingsAccountNo); - toAccountType = AccountTransferEnumerations.accountType(PortfolioAccountType.SAVINGS); - } else if (toLoanAccountId != null) { - toAccount = PortfolioAccountData.lookup(toLoanAccountId, toLoanAccountNo); - toAccountType = AccountTransferEnumerations.accountType(PortfolioAccountType.LOAN); - } - - return AccountTransferData.instance(id, reversed, transferDate, currency, transferAmount, transferDescription, fromOffice, - toOffice, fromClient, toClient, fromAccountType, fromAccount, toAccountType, toAccount); - } - } - - @Override - public boolean isAccountTransfer(final Long transactionId, final PortfolioAccountType accountType) { - final StringBuilder sql = new StringBuilder("select count(*) from m_account_transfer_transaction at where "); - if (accountType.isLoanAccount()) { - sql.append("at.from_loan_transaction_id=").append(transactionId).append(" or at.to_loan_transaction_id=").append(transactionId); - } else { - sql.append("at.from_savings_transaction_id=").append(transactionId).append(" or at.to_savings_transaction_id=") - .append(transactionId); - } - - @SuppressWarnings("deprecation") - final int count = this.jdbcTemplate.queryForInt(sql.toString()); - return count > 0; - } - - @Override - public Page<AccountTransferData> retrieveByStandingInstruction(final Long id, final SearchParameters searchParameters) { - - final StringBuilder sqlBuilder = new StringBuilder(200); - sqlBuilder.append("select SQL_CALC_FOUND_ROWS "); - sqlBuilder - .append(this.accountTransfersMapper.schema()) - .append(" join m_account_transfer_standing_instructions atsi on atsi.account_transfer_details_id = att.account_transfer_details_id "); - sqlBuilder.append(" where atsi.id = ?"); - - if (searchParameters != null) { - if (searchParameters.isOrderByRequested()) { - sqlBuilder.append(" order by ").append(searchParameters.getOrderBy()); - - if (searchParameters.isSortOrderProvided()) { - sqlBuilder.append(' ').append(searchParameters.getSortOrder()); - } - } - - if (searchParameters.isLimited()) { - sqlBuilder.append(" limit ").append(searchParameters.getLimit()); - if (searchParameters.isOffset()) { - sqlBuilder.append(" offset ").append(searchParameters.getOffset()); - } - } - } - - final Object[] finalObjectArray = { id }; - final String sqlCountRows = "SELECT FOUND_ROWS()"; - return this.paginationHelper.fetchPage(this.jdbcTemplate, sqlCountRows, sqlBuilder.toString(), finalObjectArray, - this.accountTransfersMapper); - } - - @Override - public AccountTransferData retrieveRefundByTransferTemplate(final Long fromOfficeId, final Long fromClientId, final Long fromAccountId, - final Integer fromAccountType, final Long toOfficeId, final Long toClientId, final Long toAccountId, final Integer toAccountType) { - // TODO Auto-generated method stub - final EnumOptionData loanAccountType = AccountTransferEnumerations.accountType(PortfolioAccountType.LOAN); - final EnumOptionData savingsAccountType = AccountTransferEnumerations.accountType(PortfolioAccountType.SAVINGS); - - final Integer mostRelevantFromAccountType = fromAccountType; - final Collection<EnumOptionData> fromAccountTypeOptions = Arrays.asList(savingsAccountType, loanAccountType); - final Collection<EnumOptionData> toAccountTypeOptions; - if (mostRelevantFromAccountType == 1) { - // overpaid loan amt transfer to savings account - toAccountTypeOptions = Arrays.asList(savingsAccountType); - } else { - toAccountTypeOptions = Arrays.asList(loanAccountType, savingsAccountType); - } - final Integer mostRelevantToAccountType = toAccountType; - - final EnumOptionData fromAccountTypeData = AccountTransferEnumerations.accountType(mostRelevantFromAccountType); - final EnumOptionData toAccountTypeData = AccountTransferEnumerations.accountType(mostRelevantToAccountType); - - // from settings - OfficeData fromOffice = null; - ClientData fromClient = null; - PortfolioAccountData fromAccount = null; - - OfficeData toOffice = null; - ClientData toClient = null; - PortfolioAccountData toAccount = null; - - // template - Collection<PortfolioAccountData> fromAccountOptions = null; - Collection<PortfolioAccountData> toAccountOptions = null; - - Long mostRelevantFromOfficeId = fromOfficeId; - Long mostRelevantFromClientId = fromClientId; - - Long mostRelevantToOfficeId = toOfficeId; - Long mostRelevantToClientId = toClientId; - - if (fromAccountId != null) { - Integer accountType; - if (mostRelevantFromAccountType == 1) { - accountType = PortfolioAccountType.LOAN.getValue(); - } else { - accountType = PortfolioAccountType.SAVINGS.getValue(); - } - fromAccount = this.portfolioAccountReadPlatformService.retrieveOneByPaidInAdvance(fromAccountId, accountType); - - // override provided fromClient with client of account - mostRelevantFromClientId = fromAccount.clientId(); - } - - if (mostRelevantFromClientId != null) { - fromClient = this.clientReadPlatformService.retrieveOne(mostRelevantFromClientId); - mostRelevantFromOfficeId = fromClient.officeId(); - long[] loanStatus = null; - if (mostRelevantFromAccountType == 1) { - loanStatus = new long[] { 300, 700 }; - } - PortfolioAccountDTO portfolioAccountDTO = new PortfolioAccountDTO(mostRelevantFromAccountType, mostRelevantFromClientId, - loanStatus); - fromAccountOptions = this.portfolioAccountReadPlatformService.retrieveAllForLookup(portfolioAccountDTO); - } - - Collection<OfficeData> fromOfficeOptions = null; - Collection<ClientData> fromClientOptions = null; - if (mostRelevantFromOfficeId != null) { - fromOffice = this.officeReadPlatformService.retrieveOffice(mostRelevantFromOfficeId); - fromOfficeOptions = this.officeReadPlatformService.retrieveAllOfficesForDropdown(); - fromClientOptions = this.clientReadPlatformService.retrieveAllForLookupByOfficeId(mostRelevantFromOfficeId); - } - - // defaults - final LocalDate transferDate = DateUtils.getLocalDateOfTenant(); - Collection<OfficeData> toOfficeOptions = fromOfficeOptions; - Collection<ClientData> toClientOptions = null; - - if (toAccountId != null && fromAccount != null) { - toAccount = this.portfolioAccountReadPlatformService.retrieveOne(toAccountId, mostRelevantToAccountType, - fromAccount.currencyCode()); - mostRelevantToClientId = toAccount.clientId(); - } - - if (mostRelevantToClientId != null) { - toClient = this.clientReadPlatformService.retrieveOne(mostRelevantToClientId); - mostRelevantToOfficeId = toClient.officeId(); - - toClientOptions = this.clientReadPlatformService.retrieveAllForLookupByOfficeId(mostRelevantToOfficeId); - - toAccountOptions = retrieveToAccounts(fromAccount, mostRelevantToAccountType, mostRelevantToClientId); - } - - if (mostRelevantToOfficeId != null) { - toOffice = this.officeReadPlatformService.retrieveOffice(mostRelevantToOfficeId); - toOfficeOptions = this.officeReadPlatformService.retrieveAllOfficesForDropdown(); - - toClientOptions = this.clientReadPlatformService.retrieveAllForLookupByOfficeId(mostRelevantToOfficeId); - if (toClientOptions != null && toClientOptions.size() == 1) { - toClient = new ArrayList<>(toClientOptions).get(0); - - toAccountOptions = retrieveToAccounts(fromAccount, mostRelevantToAccountType, mostRelevantToClientId); - } - } - - return AccountTransferData.template(fromOffice, fromClient, fromAccountTypeData, fromAccount, transferDate, toOffice, toClient, - toAccountTypeData, toAccount, fromOfficeOptions, fromClientOptions, fromAccountTypeOptions, fromAccountOptions, - toOfficeOptions, toClientOptions, toAccountTypeOptions, toAccountOptions); - } +public class AccountTransfersReadPlatformServiceImpl implements + AccountTransfersReadPlatformService { + + private final JdbcTemplate jdbcTemplate; + private final ClientReadPlatformService clientReadPlatformService; + private final OfficeReadPlatformService officeReadPlatformService; + private final PortfolioAccountReadPlatformService portfolioAccountReadPlatformService; + + // mapper + private final AccountTransfersMapper accountTransfersMapper; + + // pagination + private final PaginationHelper<AccountTransferData> paginationHelper = new PaginationHelper<>(); + private final DateTimeFormatter formatter = DateTimeFormat + .forPattern("yyyy-MM-dd"); + + @Autowired + public AccountTransfersReadPlatformServiceImpl( + final RoutingDataSource dataSource, + final ClientReadPlatformService clientReadPlatformService, + final OfficeReadPlatformService officeReadPlatformService, + final PortfolioAccountReadPlatformService portfolioAccountReadPlatformService) { + this.jdbcTemplate = new JdbcTemplate(dataSource); + this.clientReadPlatformService = clientReadPlatformService; + this.officeReadPlatformService = officeReadPlatformService; + this.portfolioAccountReadPlatformService = portfolioAccountReadPlatformService; + + this.accountTransfersMapper = new AccountTransfersMapper(); + } + + @Override + public AccountTransferData retrieveTemplate(final Long fromOfficeId, + final Long fromClientId, final Long fromAccountId, + final Integer fromAccountType, final Long toOfficeId, + final Long toClientId, final Long toAccountId, + final Integer toAccountType) { + + final EnumOptionData loanAccountType = AccountTransferEnumerations + .accountType(PortfolioAccountType.LOAN); + final EnumOptionData savingsAccountType = AccountTransferEnumerations + .accountType(PortfolioAccountType.SAVINGS); + + final Integer mostRelevantFromAccountType = fromAccountType; + final Collection<EnumOptionData> fromAccountTypeOptions = Arrays + .asList(savingsAccountType, loanAccountType); + final Collection<EnumOptionData> toAccountTypeOptions; + if (mostRelevantFromAccountType != null + && mostRelevantFromAccountType == 1) { + // overpaid loan amt transfer to savings account + toAccountTypeOptions = Arrays.asList(savingsAccountType); + } else { + toAccountTypeOptions = Arrays.asList(loanAccountType, + savingsAccountType); + } + final Integer mostRelevantToAccountType = toAccountType; + + final EnumOptionData fromAccountTypeData = AccountTransferEnumerations + .accountType(mostRelevantFromAccountType); + final EnumOptionData toAccountTypeData = AccountTransferEnumerations + .accountType(mostRelevantToAccountType); + + // from settings + OfficeData fromOffice = null; + ClientData fromClient = null; + PortfolioAccountData fromAccount = null; + + OfficeData toOffice = null; + ClientData toClient = null; + PortfolioAccountData toAccount = null; + + // template + Collection<PortfolioAccountData> fromAccountOptions = null; + Collection<PortfolioAccountData> toAccountOptions = null; + + Long mostRelevantFromOfficeId = fromOfficeId; + Long mostRelevantFromClientId = fromClientId; + + Long mostRelevantToOfficeId = toOfficeId; + Long mostRelevantToClientId = toClientId; + + if (fromAccountId != null) { + Integer accountType; + if (mostRelevantFromAccountType == 1) { + accountType = PortfolioAccountType.LOAN.getValue(); + } else { + accountType = PortfolioAccountType.SAVINGS.getValue(); + } + fromAccount = this.portfolioAccountReadPlatformService.retrieveOne( + fromAccountId, accountType); + + // override provided fromClient with client of account + mostRelevantFromClientId = fromAccount.clientId(); + } + + if (mostRelevantFromClientId != null) { + fromClient = this.clientReadPlatformService + .retrieveOne(mostRelevantFromClientId); + mostRelevantFromOfficeId = fromClient.officeId(); + long[] loanStatus = null; + if (mostRelevantFromAccountType == 1) { + loanStatus = new long[] { 300, 700 }; + } + PortfolioAccountDTO portfolioAccountDTO = new PortfolioAccountDTO( + mostRelevantFromAccountType, mostRelevantFromClientId, + loanStatus); + fromAccountOptions = this.portfolioAccountReadPlatformService + .retrieveAllForLookup(portfolioAccountDTO); + } + + Collection<OfficeData> fromOfficeOptions = null; + Collection<ClientData> fromClientOptions = null; + if (mostRelevantFromOfficeId != null) { + fromOffice = this.officeReadPlatformService + .retrieveOffice(mostRelevantFromOfficeId); + fromOfficeOptions = this.officeReadPlatformService + .retrieveAllOfficesForDropdown(); + fromClientOptions = this.clientReadPlatformService + .retrieveAllForLookupByOfficeId(mostRelevantFromOfficeId); + } + + // defaults + final LocalDate transferDate = DateUtils.getLocalDateOfTenant(); + Collection<OfficeData> toOfficeOptions = fromOfficeOptions; + Collection<ClientData> toClientOptions = null; + + if (toAccountId != null && fromAccount != null) { + toAccount = this.portfolioAccountReadPlatformService.retrieveOne( + toAccountId, mostRelevantToAccountType, + fromAccount.currencyCode()); + mostRelevantToClientId = toAccount.clientId(); + } + + if (mostRelevantToClientId != null) { + toClient = this.clientReadPlatformService + .retrieveOne(mostRelevantToClientId); + mostRelevantToOfficeId = toClient.officeId(); + + toClientOptions = this.clientReadPlatformService + .retrieveAllForLookupByOfficeId(mostRelevantToOfficeId); + + toAccountOptions = retrieveToAccounts(fromAccount, + mostRelevantToAccountType, mostRelevantToClientId); + } + + if (mostRelevantToOfficeId != null) { + toOffice = this.officeReadPlatformService + .retrieveOffice(mostRelevantToOfficeId); + toOfficeOptions = this.officeReadPlatformService + .retrieveAllOfficesForDropdown(); + + toClientOptions = this.clientReadPlatformService + .retrieveAllForLookupByOfficeId(mostRelevantToOfficeId); + if (toClientOptions != null && toClientOptions.size() == 1) { + toClient = new ArrayList<>(toClientOptions).get(0); + + toAccountOptions = retrieveToAccounts(fromAccount, + mostRelevantToAccountType, mostRelevantToClientId); + } + } + + return AccountTransferData.template(fromOffice, fromClient, + fromAccountTypeData, fromAccount, transferDate, toOffice, + toClient, toAccountTypeData, toAccount, fromOfficeOptions, + fromClientOptions, fromAccountTypeOptions, fromAccountOptions, + toOfficeOptions, toClientOptions, toAccountTypeOptions, + toAccountOptions); + } + + private Collection<PortfolioAccountData> retrieveToAccounts( + final PortfolioAccountData excludeThisAccountFromOptions, + final Integer toAccountType, final Long toClientId) { + + final String currencyCode = excludeThisAccountFromOptions != null ? excludeThisAccountFromOptions + .currencyCode() : null; + + PortfolioAccountDTO portfolioAccountDTO = new PortfolioAccountDTO( + toAccountType, toClientId, currencyCode, null, null); + Collection<PortfolioAccountData> accountOptions = this.portfolioAccountReadPlatformService + .retrieveAllForLookup(portfolioAccountDTO); + if (!CollectionUtils.isEmpty(accountOptions)) { + accountOptions.remove(excludeThisAccountFromOptions); + } else { + accountOptions = null; + } + + return accountOptions; + } + + @Override + public Page<AccountTransferData> retrieveAll( + final SearchParameters searchParameters, final Long accountDetailId) { + + final StringBuilder sqlBuilder = new StringBuilder(200); + sqlBuilder.append("select SQL_CALC_FOUND_ROWS "); + sqlBuilder.append(this.accountTransfersMapper.schema()); + Object[] finalObjectArray = {}; + if (accountDetailId != null) { + sqlBuilder.append(" where att.account_transfer_details_id=?"); + finalObjectArray = new Object[] { accountDetailId }; + } + + if (searchParameters.isOrderByRequested()) { + sqlBuilder.append(" order by ").append( + searchParameters.getOrderBy()); + + if (searchParameters.isSortOrderProvided()) { + sqlBuilder.append(' ').append(searchParameters.getSortOrder()); + } + } + + if (searchParameters.isLimited()) { + sqlBuilder.append(" limit ").append(searchParameters.getLimit()); + if (searchParameters.isOffset()) { + sqlBuilder.append(" offset ").append( + searchParameters.getOffset()); + } + } + + final String sqlCountRows = "SELECT FOUND_ROWS()"; + return this.paginationHelper.fetchPage(this.jdbcTemplate, sqlCountRows, + sqlBuilder.toString(), finalObjectArray, + this.accountTransfersMapper); + } + + @Override + public AccountTransferData retrieveOne(final Long transferId) { + + try { + final String sql = "select " + this.accountTransfersMapper.schema() + + " where att.id = ?"; + + return this.jdbcTemplate.queryForObject(sql, + this.accountTransfersMapper, new Object[] { transferId }); + } catch (final EmptyResultDataAccessException e) { + throw new AccountTransferNotFoundException(transferId); + } + } + + @Override + public Collection<Long> fetchPostInterestTransactionIds(final Long accountId) { + final String sql = "select att.from_savings_transaction_id from m_account_transfer_transaction att inner join m_account_transfer_details atd on atd.id = att.account_transfer_details_id where atd.from_savings_account_id=? and att.is_reversed =0 and atd.transfer_type = ?"; + + final List<Long> transactionId = this.jdbcTemplate.queryForList(sql, + Long.class, accountId, + AccountTransferType.INTEREST_TRANSFER.getValue()); + + return transactionId; + } + + private static final class AccountTransfersMapper implements + RowMapper<AccountTransferData> { + + private final String schemaSql; + + public AccountTransfersMapper() { + final StringBuilder sqlBuilder = new StringBuilder(400); + sqlBuilder.append("att.id as id, att.is_reversed as isReversed,"); + sqlBuilder + .append("att.transaction_date as transferDate, att.amount as transferAmount,"); + sqlBuilder.append("att.description as transferDescription,"); + sqlBuilder + .append("att.currency_code as currencyCode, att.currency_digits as currencyDigits,"); + sqlBuilder.append("att.currency_multiplesof as inMultiplesOf, "); + sqlBuilder + .append("curr.name as currencyName, curr.internationalized_name_code as currencyNameCode, "); + sqlBuilder.append("curr.display_symbol as currencyDisplaySymbol, "); + sqlBuilder + .append("fromoff.id as fromOfficeId, fromoff.name as fromOfficeName,"); + sqlBuilder + .append("tooff.id as toOfficeId, tooff.name as toOfficeName,"); + sqlBuilder + .append("fromclient.id as fromClientId, fromclient.display_name as fromClientName,"); + sqlBuilder + .append("toclient.id as toClientId, toclient.display_name as toClientName,"); + sqlBuilder + .append("fromsavacc.id as fromSavingsAccountId, fromsavacc.account_no as fromSavingsAccountNo,"); + sqlBuilder + .append("fromloanacc.id as fromLoanAccountId, fromloanacc.account_no as fromLoanAccountNo,"); + sqlBuilder + .append("tosavacc.id as toSavingsAccountId, tosavacc.account_no as toSavingsAccountNo,"); + sqlBuilder + .append("toloanacc.id as toLoanAccountId, toloanacc.account_no as toLoanAccountNo,"); + sqlBuilder + .append("fromsavtran.id as fromSavingsAccountTransactionId,"); + sqlBuilder + .append("fromsavtran.transaction_type_enum as fromSavingsAccountTransactionType,"); + sqlBuilder.append("tosavtran.id as toSavingsAccountTransactionId,"); + sqlBuilder + .append("tosavtran.transaction_type_enum as toSavingsAccountTransactionType"); + sqlBuilder.append(" FROM m_account_transfer_transaction att "); + sqlBuilder + .append("left join m_account_transfer_details atd on atd.id = att.account_transfer_details_id "); + sqlBuilder + .append("join m_currency curr on curr.code = att.currency_code "); + sqlBuilder + .append("join m_office fromoff on fromoff.id = atd.from_office_id "); + sqlBuilder + .append("join m_office tooff on tooff.id = atd.to_office_id "); + sqlBuilder + .append("join m_client fromclient on fromclient.id = atd.from_client_id "); + sqlBuilder + .append("join m_client toclient on toclient.id = atd.to_client_id "); + sqlBuilder + .append("left join m_savings_account fromsavacc on fromsavacc.id = atd.from_savings_account_id "); + sqlBuilder + .append("left join m_loan fromloanacc on fromloanacc.id = atd.from_loan_account_id "); + sqlBuilder + .append("left join m_savings_account tosavacc on tosavacc.id = atd.to_savings_account_id "); + sqlBuilder + .append("left join m_loan toloanacc on toloanacc.id = atd.to_loan_account_id "); + sqlBuilder + .append("left join m_savings_account_transaction fromsavtran on fromsavtran.id = att.from_savings_transaction_id "); + sqlBuilder + .append("left join m_savings_account_transaction tosavtran on tosavtran.id = att.to_savings_transaction_id "); + sqlBuilder + .append("left join m_loan_transaction fromloantran on fromloantran.id = att.from_savings_transaction_id "); + sqlBuilder + .append("left join m_loan_transaction toloantran on toloantran.id = att.to_savings_transaction_id "); + + this.schemaSql = sqlBuilder.toString(); + } + + public String schema() { + return this.schemaSql; + } + + @Override + public AccountTransferData mapRow(final ResultSet rs, + @SuppressWarnings("unused") final int rowNum) + throws SQLException { + + final Long id = rs.getLong("id"); + final boolean reversed = rs.getBoolean("isReversed"); + + final LocalDate transferDate = JdbcSupport.getLocalDate(rs, + "transferDate"); + final BigDecimal transferAmount = JdbcSupport + .getBigDecimalDefaultToZeroIfNull(rs, "transferAmount"); + final String transferDescription = rs + .getString("transferDescription"); + + 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 Integer inMultiplesOf = JdbcSupport.getInteger(rs, + "inMultiplesOf"); + final CurrencyData currency = new CurrencyData(currencyCode, + currencyName, currencyDigits, inMultiplesOf, + currencyDisplaySymbol, currencyNameCode); + + final Long fromOfficeId = JdbcSupport.getLong(rs, "fromOfficeId"); + final String fromOfficeName = rs.getString("fromOfficeName"); + final OfficeData fromOffice = OfficeData.dropdown(fromOfficeId, + fromOfficeName, null); + + final Long toOfficeId = JdbcSupport.getLong(rs, "toOfficeId"); + final String toOfficeName = rs.getString("toOfficeName"); + final OfficeData toOffice = OfficeData.dropdown(toOfficeId, + toOfficeName, null); + + final Long fromClientId = JdbcSupport.getLong(rs, "fromClientId"); + final String fromClientName = rs.getString("fromClientName"); + final ClientData fromClient = ClientData.lookup(fromClientId, + fromClientName, fromOfficeId, fromOfficeName); + + final Long toClientId = JdbcSupport.getLong(rs, "toClientId"); + final String toClientName = rs.getString("toClientName"); + final ClientData toClient = ClientData.lookup(toClientId, + toClientName, toOfficeId, toOfficeName); + + final Long fromSavingsAccountId = JdbcSupport.getLong(rs, + "fromSavingsAccountId"); + final String fromSavingsAccountNo = rs + .getString("fromSavingsAccountNo"); + final Long fromLoanAccountId = JdbcSupport.getLong(rs, + "fromLoanAccountId"); + final String fromLoanAccountNo = rs.getString("fromLoanAccountNo"); + PortfolioAccountData fromAccount = null; + EnumOptionData fromAccountType = null; + if (fromSavingsAccountId != null) { + fromAccount = PortfolioAccountData.lookup(fromSavingsAccountId, + fromSavingsAccountNo); + fromAccountType = AccountTransferEnumerations + .accountType(PortfolioAccountType.SAVINGS); + } else if (fromLoanAccountId != null) { + fromAccount = PortfolioAccountData.lookup(fromLoanAccountId, + fromLoanAccountNo); + fromAccountType = AccountTransferEnumerations + .accountType(PortfolioAccountType.LOAN); + } + + PortfolioAccountData toAccount = null; + EnumOptionData toAccountType = null; + final Long toSavingsAccountId = JdbcSupport.getLong(rs, + "toSavingsAccountId"); + final String toSavingsAccountNo = rs + .getString("toSavingsAccountNo"); + final Long toLoanAccountId = JdbcSupport.getLong(rs, + "toLoanAccountId"); + final String toLoanAccountNo = rs.getString("toLoanAccountNo"); + + if (toSavingsAccountId != null) { + toAccount = PortfolioAccountData.lookup(toSavingsAccountId, + toSavingsAccountNo); + toAccountType = AccountTransferEnumerations + .accountType(PortfolioAccountType.SAVINGS); + } else if (toLoanAccountId != null) { + toAccount = PortfolioAccountData.lookup(toLoanAccountId, + toLoanAccountNo); + toAccountType = AccountTransferEnumerations + .accountType(PortfolioAccountType.LOAN); + } + + return AccountTransferData.instance(id, reversed, transferDate, + currency, transferAmount, transferDescription, fromOffice, + toOffice, fromClient, toClient, fromAccountType, + fromAccount, toAccountType, toAccount); + } + } + + @Override + public boolean isAccountTransfer(final Long transactionId, + final PortfolioAccountType accountType) { + final StringBuilder sql = new StringBuilder( + "select count(*) from m_account_transfer_transaction at where "); + if (accountType.isLoanAccount()) { + sql.append("at.from_loan_transaction_id=").append(transactionId) + .append(" or at.to_loan_transaction_id=") + .append(transactionId); + } else { + sql.append("at.from_savings_transaction_id=").append(transactionId) + .append(" or at.to_savings_transaction_id=") + .append(transactionId); + } + + @SuppressWarnings("deprecation") + final int count = this.jdbcTemplate.queryForInt(sql.toString()); + return count > 0; + } + + @Override + public Page<AccountTransferData> retrieveByStandingInstruction( + final Long id, final SearchParameters searchParameters) { + + final StringBuilder sqlBuilder = new StringBuilder(200); + sqlBuilder.append("select SQL_CALC_FOUND_ROWS "); + sqlBuilder + .append(this.accountTransfersMapper.schema()) + .append(" join m_account_transfer_standing_instructions atsi on atsi.account_transfer_details_id = att.account_transfer_details_id "); + sqlBuilder.append(" where atsi.id = ?"); + + if (searchParameters != null) { + if (searchParameters.isOrderByRequested()) { + sqlBuilder.append(" order by ").append( + searchParameters.getOrderBy()); + + if (searchParameters.isSortOrderProvided()) { + sqlBuilder.append(' ').append( + searchParameters.getSortOrder()); + } + } + + if (searchParameters.isLimited()) { + sqlBuilder.append(" limit ") + .append(searchParameters.getLimit()); + if (searchParameters.isOffset()) { + sqlBuilder.append(" offset ").append( + searchParameters.getOffset()); + } + } + } + + final Object[] finalObjectArray = { id }; + final String sqlCountRows = "SELECT FOUND_ROWS()"; + return this.paginationHelper.fetchPage(this.jdbcTemplate, sqlCountRows, + sqlBuilder.toString(), finalObjectArray, + this.accountTransfersMapper); + } + + @Override + public AccountTransferData retrieveRefundByTransferTemplate( + final Long fromOfficeId, final Long fromClientId, + final Long fromAccountId, final Integer fromAccountType, + final Long toOfficeId, final Long toClientId, + final Long toAccountId, final Integer toAccountType) { + // TODO Auto-generated method stub + final EnumOptionData loanAccountType = AccountTransferEnumerations + .accountType(PortfolioAccountType.LOAN); + final EnumOptionData savingsAccountType = AccountTransferEnumerations + .accountType(PortfolioAccountType.SAVINGS); + + final Integer mostRelevantFromAccountType = fromAccountType; + final Collection<EnumOptionData> fromAccountTypeOptions = Arrays + .asList(savingsAccountType, loanAccountType); + final Collection<EnumOptionData> toAccountTypeOptions; + if (mostRelevantFromAccountType == 1) { + // overpaid loan amt transfer to savings account + toAccountTypeOptions = Arrays.asList(savingsAccountType); + } else { + toAccountTypeOptions = Arrays.asList(loanAccountType, + savingsAccountType); + } + final Integer mostRelevantToAccountType = toAccountType; + + final EnumOptionData fromAccountTypeData = AccountTransferEnumerations + .accountType(mostRelevantFromAccountType); + final EnumOptionData toAccountTypeData = AccountTransferEnumerations + .accountType(mostRelevantToAccountType); + + // from settings + OfficeData fromOffice = null; + ClientData fromClient = null; + PortfolioAccountData fromAccount = null; + + OfficeData toOffice = null; + ClientData toClient = null; + PortfolioAccountData toAccount = null; + + // template + Collection<PortfolioAccountData> fromAccountOptions = null; + Collection<PortfolioAccountData> toAccountOptions = null; + + Long mostRelevantFromOfficeId = fromOfficeId; + Long mostRelevantFromClientId = fromClientId; + + Long mostRelevantToOfficeId = toOfficeId; + Long mostRelevantToClientId = toClientId; + + if (fromAccountId != null) { + Integer accountType; + if (mostRelevantFromAccountType == 1) { + accountType = PortfolioAccountType.LOAN.getValue(); + } else { + accountType = PortfolioAccountType.SAVINGS.getValue(); + } + fromAccount = this.portfolioAccountReadPlatformService + .retrieveOneByPaidInAdvance(fromAccountId, accountType); + + // override provided fromClient with client of account + mostRelevantFromClientId = fromAccount.clientId(); + } + + if (mostRelevantFromClientId != null) { + fromClient = this.clientReadPlatformService + .retrieveOne(mostRelevantFromClientId); + mostRelevantFromOfficeId = fromClient.officeId(); + long[] loanStatus = null; + if (mostRelevantFromAccountType == 1) { + loanStatus = new long[] { 300, 700 }; + } + PortfolioAccountDTO portfolioAccountDTO = new PortfolioAccountDTO( + mostRelevantFromAccountType, mostRelevantFromClientId, + loanStatus); + fromAccountOptions = this.portfolioAccountReadPlatformService + .retrieveAllForLookup(portfolioAccountDTO); + } + + Collection<OfficeData> fromOfficeOptions = null; + Collection<ClientData> fromClientOptions = null; + if (mostRelevantFromOfficeId != null) { + fromOffice = this.officeReadPlatformService + .retrieveOffice(mostRelevantFromOfficeId); + fromOfficeOptions = this.officeReadPlatformService + .retrieveAllOfficesForDropdown(); + fromClientOptions = this.clientReadPlatformService + .retrieveAllForLookupByOfficeId(mostRelevantFromOfficeId); + } + + // defaults + final LocalDate transferDate = DateUtils.getLocalDateOfTenant(); + Collection<OfficeData> toOfficeOptions = fromOfficeOptions; + Collection<ClientData> toClientOptions = null; + + if (toAccountId != null && fromAccount != null) { + toAccount = this.portfolioAccountReadPlatformService.retrieveOne( + toAccountId, mostRelevantToAccountType, + fromAccount.currencyCode()); + mostRelevantToClientId = toAccount.clientId(); + } + + if (mostRelevantToClientId != null) { + toClient = this.clientReadPlatformService + .retrieveOne(mostRelevantToClientId); + mostRelevantToOfficeId = toClient.officeId(); + + toClientOptions = this.clientReadPlatformService + .retrieveAllForLookupByOfficeId(mostRelevantToOfficeId); + + toAccountOptions = retrieveToAccounts(fromAccount, + mostRelevantToAccountType, mostRelevantToClientId); + } + + if (mostRelevantToOfficeId != null) { + toOffice = this.officeReadPlatformService + .retrieveOffice(mostRelevantToOfficeId); + toOfficeOptions = this.officeReadPlatformService + .retrieveAllOfficesForDropdown(); + + toClientOptions = this.clientReadPlatformService + .retrieveAllForLookupByOfficeId(mostRelevantToOfficeId); + if (toClientOptions != null && toClientOptions.size() == 1) { + toClient = new ArrayList<>(toClientOptions).get(0); + + toAccountOptions = retrieveToAccounts(fromAccount, + mostRelevantToAccountType, mostRelevantToClientId); + } + } + + return AccountTransferData.template(fromOffice, fromClient, + fromAccountTypeData, fromAccount, transferDate, toOffice, + toClient, toAccountTypeData, toAccount, fromOfficeOptions, + fromClientOptions, fromAccountTypeOptions, fromAccountOptions, + toOfficeOptions, toClientOptions, toAccountTypeOptions, + toAccountOptions); + } + + @Override + public BigDecimal getTotalTransactionAmount(Long accountId, + Integer accountType, LocalDate transactionDate) { + StringBuilder sqlBuilder = new StringBuilder( + " select sum(trans.amount) as totalTransactionAmount "); + sqlBuilder.append(" from m_account_transfer_details as det "); + sqlBuilder + .append(" inner join m_account_transfer_transaction as trans "); + sqlBuilder.append(" on det.id = trans.account_transfer_details_id "); + sqlBuilder.append(" where trans.is_reversed = 0 "); + sqlBuilder.append(" and trans.transaction_date = ? "); + sqlBuilder + .append(" and IF(1=?, det.from_loan_account_id = ?, det.from_savings_account_id = ?) "); + + return this.jdbcTemplate.queryForObject(sqlBuilder.toString(), + new Object[] { this.formatter.print(transactionDate), + accountType, accountId, accountId }, BigDecimal.class); + } } \ No newline at end of file http://git-wip-us.apache.org/repos/asf/incubator-fineract/blob/2bd3b062/fineract-provider/src/main/java/org/apache/fineract/portfolio/loanaccount/domain/LoanRepository.java ---------------------------------------------------------------------- diff --git a/fineract-provider/src/main/java/org/apache/fineract/portfolio/loanaccount/domain/LoanRepository.java b/fineract-provider/src/main/java/org/apache/fineract/portfolio/loanaccount/domain/LoanRepository.java index 845cc67..b306d70 100755 --- a/fineract-provider/src/main/java/org/apache/fineract/portfolio/loanaccount/domain/LoanRepository.java +++ b/fineract-provider/src/main/java/org/apache/fineract/portfolio/loanaccount/domain/LoanRepository.java @@ -69,6 +69,8 @@ public interface LoanRepository extends JpaRepository<Loan, Long>, JpaSpecificat public static final String DOES_PRODUCT_HAVE_NON_CLOSED_LOANS = "select case when (count (loan) > 0) then true else false end from Loan loan where loan.loanProduct.id = :productId and loan.loanStatus in (100,200,300,303,304,700)"; + public static final String FIND_BY_ACCOUNT_NUMBER = "from Loan loan where loan.accountNumber = :accountNumber and loan.loanStatus in (100,200,300,303,304)"; + @Query(FIND_GROUP_LOANS_DISBURSED_AFTER) List<Loan> getGroupLoansDisbursedAfter(@Param("disbursementDate") Date disbursementDate, @Param("groupId") Long groupId, @Param("loanType") Integer loanType); @@ -144,5 +146,7 @@ public interface LoanRepository extends JpaRepository<Loan, Long>, JpaSpecificat @Query(DOES_PRODUCT_HAVE_NON_CLOSED_LOANS) boolean doNonClosedLoanAccountsExistForProduct(@Param("productId") Long productId); - + + @Query(FIND_BY_ACCOUNT_NUMBER) + Loan findNonClosedLoanByAccountNumber(@Param("accountNumber") String accountNumber); } \ No newline at end of file http://git-wip-us.apache.org/repos/asf/incubator-fineract/blob/2bd3b062/fineract-provider/src/main/java/org/apache/fineract/portfolio/savings/domain/SavingsAccountRepository.java ---------------------------------------------------------------------- diff --git a/fineract-provider/src/main/java/org/apache/fineract/portfolio/savings/domain/SavingsAccountRepository.java b/fineract-provider/src/main/java/org/apache/fineract/portfolio/savings/domain/SavingsAccountRepository.java index b34e897..b614b25 100644 --- a/fineract-provider/src/main/java/org/apache/fineract/portfolio/savings/domain/SavingsAccountRepository.java +++ b/fineract-provider/src/main/java/org/apache/fineract/portfolio/savings/domain/SavingsAccountRepository.java @@ -45,4 +45,7 @@ public interface SavingsAccountRepository extends JpaRepository<SavingsAccount, @Query("from SavingsAccount sa where sa.id = :accountId and sa.depositType = :depositAccountTypeId") SavingsAccount findByIdAndDepositAccountType(@Param("accountId") Long accountId, @Param("depositAccountTypeId") Integer depositAccountTypeId); + + @Query("from SavingsAccount sa where sa.accountNumber = :accountNumber and sa.status in (100, 200, 300, 303, 304) ") + SavingsAccount findNonClosedAccountByAccountNumber(@Param("accountNumber") String accountNumber); } \ No newline at end of file
