diff --git a/api-docs/apiLive.htm b/api-docs/apiLive.htm index c182e6588..00751bc2c 100644 --- a/api-docs/apiLive.htm +++ b/api-docs/apiLive.htm @@ -5761,7 +5761,7 @@ Request Body:

Propose a Client Transfer

-

Allows you to propose the transfer of a Client to a different Office.

+

Allows you to propose the transfer of a Client to a different Office on a specific date, if loan or savings transaction not present from proposed transfer date to current date.

POST https://Domain Name/api/v1/clients/{clientId}?command=proposeTransfer @@ -5769,6 +5769,7 @@ Request Body: Content-Type: application/json Request Body: { + "transferDate":"28 August 2018", "destinationOfficeId":"2", "note":"Client Relocating to Bangalore" } diff --git a/fineract-provider/src/main/java/org/apache/fineract/portfolio/client/api/ClientsApiResource.java b/fineract-provider/src/main/java/org/apache/fineract/portfolio/client/api/ClientsApiResource.java index fc8904907..f4f14b206 100644 --- a/fineract-provider/src/main/java/org/apache/fineract/portfolio/client/api/ClientsApiResource.java +++ b/fineract-provider/src/main/java/org/apache/fineract/portfolio/client/api/ClientsApiResource.java @@ -21,6 +21,7 @@ package org.apache.fineract.portfolio.client.api; import java.io.InputStream; import java.util.Arrays; import java.util.Collection; +import java.util.Date; import java.util.HashSet; import java.util.List; import java.util.Set; @@ -62,6 +63,7 @@ import org.apache.fineract.portfolio.loanaccount.guarantor.data.ObligeeData; import org.apache.fineract.portfolio.loanaccount.guarantor.service.GuarantorReadPlatformService; import org.apache.fineract.portfolio.savings.data.SavingsAccountData; import org.apache.fineract.portfolio.savings.service.SavingsAccountReadPlatformService; +import org.joda.time.LocalDate; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.context.annotation.Scope; import org.springframework.stereotype.Component; @@ -95,10 +97,11 @@ public class ClientsApiResource { final AccountDetailsReadPlatformService accountDetailsReadPlatformService, final SavingsAccountReadPlatformService savingsAccountReadPlatformService, final BulkImportWorkbookPopulatorService bulkImportWorkbookPopulatorService, - final BulkImportWorkbookService bulkImportWorkbookService, final GuarantorReadPlatformService guarantorReadPlatformService) { - this.context = context; - this.clientReadPlatformService = readPlatformService; - this.toApiJsonSerializer = toApiJsonSerializer; + final BulkImportWorkbookService bulkImportWorkbookService, + final GuarantorReadPlatformService guarantorReadPlatformService) { + this.context = context; + this.clientReadPlatformService = readPlatformService; + this.toApiJsonSerializer = toApiJsonSerializer; this.clientAccountSummaryToApiJsonSerializer = clientAccountSummaryToApiJsonSerializer; this.apiRequestParameterHelper = apiRequestParameterHelper; this.commandsSourceWritePlatformService = commandsSourceWritePlatformService; @@ -361,4 +364,16 @@ public class ClientsApiResource { return this.toApiJsonSerializer.serialize(ObligeeList); } + @Path("{clientId}/transferproposaldate") + @Consumes({ MediaType.APPLICATION_JSON }) + @Produces({ MediaType.APPLICATION_JSON }) + public String retrieveTransferTemplate(@PathParam("clientId") final Long clientId, @Context final UriInfo uriInfo) { + + this.context.authenticatedUser().validateHasReadPermission(ClientApiConstants.CLIENT_RESOURCE_NAME); + final Date transferDate = this.clientReadPlatformService.retrieveClientTransferProposalDate(clientId); + if (transferDate != null) { + return this.toApiJsonSerializer.serialize(new LocalDate(transferDate)); + } + return this.toApiJsonSerializer.serialize(transferDate); + } } \ No newline at end of file diff --git a/fineract-provider/src/main/java/org/apache/fineract/portfolio/client/service/ClientReadPlatformService.java b/fineract-provider/src/main/java/org/apache/fineract/portfolio/client/service/ClientReadPlatformService.java index fc9f72f8c..b9461deaa 100644 --- a/fineract-provider/src/main/java/org/apache/fineract/portfolio/client/service/ClientReadPlatformService.java +++ b/fineract-provider/src/main/java/org/apache/fineract/portfolio/client/service/ClientReadPlatformService.java @@ -19,6 +19,7 @@ package org.apache.fineract.portfolio.client.service; import java.util.Collection; +import java.util.Date; import org.apache.fineract.infrastructure.core.service.Page; import org.apache.fineract.infrastructure.core.service.SearchParameters; @@ -45,4 +46,12 @@ public interface ClientReadPlatformService { Collection retrieveActiveClientMembersOfCenter(final Long centerId); ClientData retrieveAllNarrations(String clientNarrations); + + Date retrieveClientTransferProposalDate(Long clientId); + + Date retrieveClientTransferProposalDateByLoan(Long clientId); + + Date retrieveClientTransferProposalDateBySavings(Long clientId); + + void validateClient(Long clientId); } \ No newline at end of file diff --git a/fineract-provider/src/main/java/org/apache/fineract/portfolio/client/service/ClientReadPlatformServiceImpl.java b/fineract-provider/src/main/java/org/apache/fineract/portfolio/client/service/ClientReadPlatformServiceImpl.java index 9d1babd8a..43968d8d3 100644 --- a/fineract-provider/src/main/java/org/apache/fineract/portfolio/client/service/ClientReadPlatformServiceImpl.java +++ b/fineract-provider/src/main/java/org/apache/fineract/portfolio/client/service/ClientReadPlatformServiceImpl.java @@ -9,6 +9,7 @@ * * http://www.apache.org/licenses/LICENSE-2.0 * + * * Unless required by applicable law or agreed to in writing, * software distributed under the License is distributed on an * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY @@ -23,6 +24,7 @@ import java.sql.SQLException; import java.util.ArrayList; import java.util.Arrays; import java.util.Collection; +import java.util.Date; import java.util.List; import org.apache.commons.lang.StringUtils; @@ -59,7 +61,11 @@ import org.apache.fineract.portfolio.client.domain.ClientStatus; import org.apache.fineract.portfolio.client.domain.LegalForm; import org.apache.fineract.portfolio.client.exception.ClientNotFoundException; import org.apache.fineract.portfolio.group.data.GroupGeneralData; +import org.apache.fineract.portfolio.loanaccount.domain.LoanStatus; +import org.apache.fineract.portfolio.loanaccount.domain.LoanTransactionType; +import org.apache.fineract.portfolio.savings.SavingsAccountTransactionType; import org.apache.fineract.portfolio.savings.data.SavingsProductData; +import org.apache.fineract.portfolio.savings.domain.SavingsAccountStatusType; import org.apache.fineract.portfolio.savings.service.SavingsProductReadPlatformService; import org.apache.fineract.useradministration.domain.AppUser; import org.joda.time.LocalDate; @@ -100,8 +106,8 @@ public class ClientReadPlatformServiceImpl implements ClientReadPlatformService final AddressReadPlatformService addressReadPlatformService,final ClientFamilyMembersReadPlatformService clientFamilyMembersReadPlatformService, final ConfigurationReadPlatformService configurationReadPlatformService, final EntityDatatableChecksReadService entityDatatableChecksReadService, - final ColumnValidator columnValidator) { - this.context = context; + final ColumnValidator columnValidator) { + this.context = context; this.officeReadPlatformService = officeReadPlatformService; this.jdbcTemplate = new JdbcTemplate(dataSource); this.staffReadPlatformService = staffReadPlatformService; @@ -112,7 +118,7 @@ public class ClientReadPlatformServiceImpl implements ClientReadPlatformService this.configurationReadPlatformService=configurationReadPlatformService; this.entityDatatableChecksReadService = entityDatatableChecksReadService; this.columnValidator = columnValidator; - } + } @Override public ClientData retrieveTemplate(final Long officeId, final boolean staffInSelectedOfficeOnly) { @@ -816,5 +822,50 @@ public class ClientReadPlatformServiceImpl implements ClientReadPlatformService return ClientData.template(null, null, null, null, narrations, null, null, clientTypeOptions, clientClassificationOptions, clientNonPersonConstitutionOptions, clientNonPersonMainBusinessLineOptions, clientLegalFormOptions,null,null,null, null); } + + @Override + public Date retrieveClientTransferProposalDateByLoan(Long clientId) { + try { + String sql = "SELECT t.transaction_date FROM m_client c LEFT JOIN m_loan loan ON c.id = loan.client_id AND c.id = ? AND loan.loan_status_id = ? LEFT JOIN m_loan_transaction t ON loan.id = t.loan_id AND t.transaction_type_enum = ? ORDER BY t.id DESC LIMIT 1"; + return this.jdbcTemplate.queryForObject(sql, Date.class, clientId, + LoanStatus.TRANSFER_IN_PROGRESS.getValue(), LoanTransactionType.INITIATE_TRANSFER.getValue()); + } catch (final EmptyResultDataAccessException e) { + return null; + + } + } + + @Override + public Date retrieveClientTransferProposalDateBySavings(Long clientId) { + try { + String sql = "SELECT t.transaction_date FROM m_client c LEFT JOIN m_savings_account savings ON c.id = savings.client_id AND c.id = ? AND savings.status_enum = ? LEFT JOIN m_savings_account_transaction t ON savings.id = t.savings_account_id AND t.transaction_type_enum = ? ORDER BY t.id DESC LIMIT 1"; + return this.jdbcTemplate.queryForObject(sql, Date.class, clientId, + SavingsAccountStatusType.TRANSFER_IN_PROGRESS.getValue(), + SavingsAccountTransactionType.INITIATE_TRANSFER.getValue()); + } catch (final EmptyResultDataAccessException e) { + return null; + + } + } + + @Override + public Date retrieveClientTransferProposalDate(Long clientId) { + validateClient(clientId); + Date transferDateForLoan = retrieveClientTransferProposalDateByLoan(clientId); + if (transferDateForLoan == null) { + transferDateForLoan = retrieveClientTransferProposalDateBySavings(clientId); + } + return transferDateForLoan; + } + + @Override + public void validateClient(Long clientId) { + try { + final String sql = "SELECT cl.id FROM m_client cl WHERE cl.id =? "; + this.jdbcTemplate.queryForObject(sql, Long.class, clientId); + } catch (final EmptyResultDataAccessException e) { + throw new ClientNotFoundException(clientId); + } + } } \ No newline at end of file diff --git a/fineract-provider/src/main/java/org/apache/fineract/portfolio/loanaccount/service/LoanWritePlatformServiceJpaRepositoryImpl.java b/fineract-provider/src/main/java/org/apache/fineract/portfolio/loanaccount/service/LoanWritePlatformServiceJpaRepositoryImpl.java index b6eed1918..411974ee5 100755 --- a/fineract-provider/src/main/java/org/apache/fineract/portfolio/loanaccount/service/LoanWritePlatformServiceJpaRepositoryImpl.java +++ b/fineract-provider/src/main/java/org/apache/fineract/portfolio/loanaccount/service/LoanWritePlatformServiceJpaRepositoryImpl.java @@ -19,7 +19,17 @@ package org.apache.fineract.portfolio.loanaccount.service; import java.math.BigDecimal; -import java.util.*; +import java.util.ArrayList; +import java.util.Arrays; +import java.util.Collection; +import java.util.Date; +import java.util.HashMap; +import java.util.HashSet; +import java.util.LinkedHashMap; +import java.util.List; +import java.util.Locale; +import java.util.Map; +import java.util.Set; import org.apache.commons.lang.StringUtils; import org.apache.fineract.accounting.journalentry.service.JournalEntryWritePlatformService; @@ -57,22 +67,44 @@ import org.apache.fineract.organisation.workingdays.domain.WorkingDaysRepository import org.apache.fineract.portfolio.account.PortfolioAccountType; import org.apache.fineract.portfolio.account.data.AccountTransferDTO; import org.apache.fineract.portfolio.account.data.PortfolioAccountData; -import org.apache.fineract.portfolio.account.domain.*; +import org.apache.fineract.portfolio.account.domain.AccountAssociationType; +import org.apache.fineract.portfolio.account.domain.AccountAssociations; +import org.apache.fineract.portfolio.account.domain.AccountAssociationsRepository; +import org.apache.fineract.portfolio.account.domain.AccountTransferDetailRepository; +import org.apache.fineract.portfolio.account.domain.AccountTransferDetails; +import org.apache.fineract.portfolio.account.domain.AccountTransferRecurrenceType; +import org.apache.fineract.portfolio.account.domain.AccountTransferRepository; +import org.apache.fineract.portfolio.account.domain.AccountTransferStandingInstruction; +import org.apache.fineract.portfolio.account.domain.AccountTransferTransaction; +import org.apache.fineract.portfolio.account.domain.AccountTransferType; +import org.apache.fineract.portfolio.account.domain.StandingInstructionPriority; +import org.apache.fineract.portfolio.account.domain.StandingInstructionStatus; +import org.apache.fineract.portfolio.account.domain.StandingInstructionType; import org.apache.fineract.portfolio.account.service.AccountAssociationsReadPlatformService; import org.apache.fineract.portfolio.account.service.AccountTransfersReadPlatformService; import org.apache.fineract.portfolio.account.service.AccountTransfersWritePlatformService; import org.apache.fineract.portfolio.accountdetails.domain.AccountType; -import org.apache.fineract.portfolio.calendar.domain.*; import org.apache.fineract.portfolio.calendar.domain.Calendar; +import org.apache.fineract.portfolio.calendar.domain.CalendarEntityType; +import org.apache.fineract.portfolio.calendar.domain.CalendarInstance; +import org.apache.fineract.portfolio.calendar.domain.CalendarInstanceRepository; +import org.apache.fineract.portfolio.calendar.domain.CalendarRepository; +import org.apache.fineract.portfolio.calendar.domain.CalendarType; import org.apache.fineract.portfolio.calendar.exception.CalendarParameterUpdateNotSupportedException; import org.apache.fineract.portfolio.charge.domain.Charge; import org.apache.fineract.portfolio.charge.domain.ChargePaymentMode; import org.apache.fineract.portfolio.charge.domain.ChargeRepositoryWrapper; -import org.apache.fineract.portfolio.charge.exception.*; +import org.apache.fineract.portfolio.charge.exception.ChargeCannotBeUpdatedException; +import org.apache.fineract.portfolio.charge.exception.LoanChargeCannotBeAddedException; +import org.apache.fineract.portfolio.charge.exception.LoanChargeCannotBeDeletedException; import org.apache.fineract.portfolio.charge.exception.LoanChargeCannotBeDeletedException.LOAN_CHARGE_CANNOT_BE_DELETED_REASON; +import org.apache.fineract.portfolio.charge.exception.LoanChargeCannotBePayedException; import org.apache.fineract.portfolio.charge.exception.LoanChargeCannotBePayedException.LOAN_CHARGE_CANNOT_BE_PAYED_REASON; +import org.apache.fineract.portfolio.charge.exception.LoanChargeCannotBeUpdatedException; import org.apache.fineract.portfolio.charge.exception.LoanChargeCannotBeUpdatedException.LOAN_CHARGE_CANNOT_BE_UPDATED_REASON; +import org.apache.fineract.portfolio.charge.exception.LoanChargeCannotBeWaivedException; import org.apache.fineract.portfolio.charge.exception.LoanChargeCannotBeWaivedException.LOAN_CHARGE_CANNOT_BE_WAIVED_REASON; +import org.apache.fineract.portfolio.charge.exception.LoanChargeNotFoundException; import org.apache.fineract.portfolio.client.domain.Client; import org.apache.fineract.portfolio.client.exception.ClientNotActiveException; import org.apache.fineract.portfolio.collectionsheet.command.CollectionSheetBulkDisbursalCommand; @@ -87,9 +119,44 @@ import org.apache.fineract.portfolio.group.domain.Group; import org.apache.fineract.portfolio.group.exception.GroupNotActiveException; import org.apache.fineract.portfolio.loanaccount.api.LoanApiConstants; import org.apache.fineract.portfolio.loanaccount.command.LoanUpdateCommand; -import org.apache.fineract.portfolio.loanaccount.data.*; -import org.apache.fineract.portfolio.loanaccount.domain.*; -import org.apache.fineract.portfolio.loanaccount.exception.*; +import org.apache.fineract.portfolio.loanaccount.data.HolidayDetailDTO; +import org.apache.fineract.portfolio.loanaccount.data.LoanChargeData; +import org.apache.fineract.portfolio.loanaccount.data.LoanChargePaidByData; +import org.apache.fineract.portfolio.loanaccount.data.LoanInstallmentChargeData; +import org.apache.fineract.portfolio.loanaccount.data.ScheduleGeneratorDTO; +import org.apache.fineract.portfolio.loanaccount.domain.ChangedTransactionDetail; +import org.apache.fineract.portfolio.loanaccount.domain.DefaultLoanLifecycleStateMachine; +import org.apache.fineract.portfolio.loanaccount.domain.Loan; +import org.apache.fineract.portfolio.loanaccount.domain.LoanAccountDomainService; +import org.apache.fineract.portfolio.loanaccount.domain.LoanCharge; +import org.apache.fineract.portfolio.loanaccount.domain.LoanChargeRepository; +import org.apache.fineract.portfolio.loanaccount.domain.LoanDisbursementDetails; +import org.apache.fineract.portfolio.loanaccount.domain.LoanEvent; +import org.apache.fineract.portfolio.loanaccount.domain.LoanInstallmentCharge; +import org.apache.fineract.portfolio.loanaccount.domain.LoanInterestRecalcualtionAdditionalDetails; +import org.apache.fineract.portfolio.loanaccount.domain.LoanLifecycleStateMachine; +import org.apache.fineract.portfolio.loanaccount.domain.LoanOverdueInstallmentCharge; +import org.apache.fineract.portfolio.loanaccount.domain.LoanRepaymentScheduleInstallment; +import org.apache.fineract.portfolio.loanaccount.domain.LoanRepaymentScheduleInstallmentRepository; +import org.apache.fineract.portfolio.loanaccount.domain.LoanRepaymentScheduleTransactionProcessorFactory; +import org.apache.fineract.portfolio.loanaccount.domain.LoanRepositoryWrapper; +import org.apache.fineract.portfolio.loanaccount.domain.LoanStatus; +import org.apache.fineract.portfolio.loanaccount.domain.LoanSubStatus; +import org.apache.fineract.portfolio.loanaccount.domain.LoanSummaryWrapper; +import org.apache.fineract.portfolio.loanaccount.domain.LoanTrancheDisbursementCharge; +import org.apache.fineract.portfolio.loanaccount.domain.LoanTransaction; +import org.apache.fineract.portfolio.loanaccount.domain.LoanTransactionRepository; +import org.apache.fineract.portfolio.loanaccount.domain.LoanTransactionType; +import org.apache.fineract.portfolio.loanaccount.exception.DateMismatchException; +import org.apache.fineract.portfolio.loanaccount.exception.ExceedingTrancheCountException; +import org.apache.fineract.portfolio.loanaccount.exception.InvalidPaidInAdvanceAmountException; +import org.apache.fineract.portfolio.loanaccount.exception.LoanDisbursalException; +import org.apache.fineract.portfolio.loanaccount.exception.LoanForeclosureException; +import org.apache.fineract.portfolio.loanaccount.exception.LoanMultiDisbursementException; +import org.apache.fineract.portfolio.loanaccount.exception.LoanOfficerAssignmentException; +import org.apache.fineract.portfolio.loanaccount.exception.LoanOfficerUnassignmentException; +import org.apache.fineract.portfolio.loanaccount.exception.LoanTransactionNotFoundException; +import org.apache.fineract.portfolio.loanaccount.exception.MultiDisbursementDataRequiredException; import org.apache.fineract.portfolio.loanaccount.guarantor.service.GuarantorDomainService; import org.apache.fineract.portfolio.loanaccount.loanschedule.data.OverdueLoanScheduleData; import org.apache.fineract.portfolio.loanaccount.loanschedule.domain.DefaultScheduledDateGenerator; @@ -111,6 +178,7 @@ import org.apache.fineract.portfolio.paymentdetail.domain.PaymentDetail; import org.apache.fineract.portfolio.paymentdetail.service.PaymentDetailWritePlatformService; import org.apache.fineract.portfolio.savings.domain.SavingsAccount; import org.apache.fineract.portfolio.savings.exception.InsufficientAccountBalanceException; +import org.apache.fineract.portfolio.transfer.api.TransferApiConstants; import org.apache.fineract.useradministration.domain.AppUser; import org.joda.time.LocalDate; import org.joda.time.format.DateTimeFormat; @@ -1792,12 +1860,14 @@ public class LoanWritePlatformServiceJpaRepositoryImpl implements LoanWritePlatf AppUser currentUser = getAppUserIfPresent(); this.loanAssembler.setHelpers(loan); checkClientOrGroupActive(loan); + validateTransactionsForTransfer(loan, transferDate); + this.businessEventNotifierService.notifyBusinessEventToBeExecuted(BUSINESS_EVENTS.LOAN_INITIATE_TRANSFER, constructEntityMap(BUSINESS_ENTITY.LOAN, loan)); final List existingTransactionIds = new ArrayList<>(loan.findExistingTransactionIds()); final List existingReversedTransactionIds = new ArrayList<>(loan.findExistingReversedTransactionIds()); - + final LoanTransaction newTransferTransaction = LoanTransaction.initiateTransfer(loan.getOffice(), loan, transferDate, DateUtils.getLocalDateTimeOfTenant(), currentUser); loan.addLoanTransaction(newTransferTransaction); @@ -2942,4 +3012,19 @@ public class LoanWritePlatformServiceJpaRepositoryImpl implements LoanWritePlatf } } + + private void validateTransactionsForTransfer(final Loan loan, final LocalDate transferDate) { + + for (LoanTransaction transaction : loan.getLoanTransactions()) { + if ((transaction.getTransactionDate().isEqual(transferDate) + && transaction.getCreatedDateTime().isEqual(transferDate.toDateTimeAtStartOfDay().toLocalDateTime())) + || transaction.getTransactionDate().isAfter(transferDate)) { + throw new GeneralPlatformDomainRuleException(TransferApiConstants.transferClientLoanException, + TransferApiConstants.transferClientLoanExceptionMessage, transaction.getCreatedDateTime().toLocalDate(), + transferDate); + } + + } + + } } diff --git a/fineract-provider/src/main/java/org/apache/fineract/portfolio/savings/domain/SavingsAccountTransaction.java b/fineract-provider/src/main/java/org/apache/fineract/portfolio/savings/domain/SavingsAccountTransaction.java index cf5ae0354..2f25e602a 100644 --- a/fineract-provider/src/main/java/org/apache/fineract/portfolio/savings/domain/SavingsAccountTransaction.java +++ b/fineract-provider/src/main/java/org/apache/fineract/portfolio/savings/domain/SavingsAccountTransaction.java @@ -111,7 +111,7 @@ public final class SavingsAccountTransaction extends AbstractPersistableCustom existingTransactionIds = new HashSet<>(); @@ -1497,4 +1537,19 @@ public class SavingsAccountWritePlatformServiceJpaRepositoryImpl implements Savi return new CommandProcessingResultBuilder().withEntityId(savingsId).withOfficeId(account.officeId()) .withClientId(account.clientId()).withGroupId(account.groupId()).withSavingsId(savingsId).with(changes).build(); } + + private void validateTransactionsForTransfer(final SavingsAccount savingsAccount, final LocalDate transferDate) { + + for (SavingsAccountTransaction transaction : savingsAccount.getTransactions()) { + if ((transaction.getTransactionLocalDate().isEqual(transferDate) + && transaction.getTransactionLocalDate().isAfter(new LocalDate(transferDate))) + || transaction.getTransactionLocalDate().isAfter(transferDate)) { + throw new GeneralPlatformDomainRuleException(TransferApiConstants.transferClientSavingsException, + TransferApiConstants.transferClientSavingsException, new LocalDate(transaction.getCreatedDate()), + transferDate); + } + + } + + } } diff --git a/fineract-provider/src/main/java/org/apache/fineract/portfolio/transfer/api/TransferApiConstants.java b/fineract-provider/src/main/java/org/apache/fineract/portfolio/transfer/api/TransferApiConstants.java index 0135f0055..37519e92e 100644 --- a/fineract-provider/src/main/java/org/apache/fineract/portfolio/transfer/api/TransferApiConstants.java +++ b/fineract-provider/src/main/java/org/apache/fineract/portfolio/transfer/api/TransferApiConstants.java @@ -18,24 +18,26 @@ */ package org.apache.fineract.portfolio.transfer.api; -import java.util.Arrays; -import java.util.HashSet; -import java.util.Set; - public class TransferApiConstants { - // general - public static final String localeParamName = "locale"; - public static final String dateFormatParamName = "dateFormat"; - - // request parameters - public static final String idParamName = "id"; - public static final String destinationGroupIdParamName = "destinationGroupId"; - public static final String clients = "clients"; - public static final String inheritDestinationGroupLoanOfficer = "inheritDestinationGroupLoanOfficer"; - public static final String newStaffIdParamName = "staffId"; - public static final String transferActiveLoans = "transferActiveLoans"; - public static final String destinationOfficeIdParamName = "destinationOfficeId"; - public static final String note = "note"; + // general + public static final String localeParamName = "locale"; + public static final String dateFormatParamName = "dateFormat"; + // request parameters + public static final String idParamName = "id"; + public static final String destinationGroupIdParamName = "destinationGroupId"; + public static final String clients = "clients"; + public static final String inheritDestinationGroupLoanOfficer = "inheritDestinationGroupLoanOfficer"; + public static final String newStaffIdParamName = "staffId"; + public static final String transferActiveLoans = "transferActiveLoans"; + public static final String destinationOfficeIdParamName = "destinationOfficeId"; + public static final String note = "note"; + public static final String transferDate = "transferDate"; + public static final String transferClientLoanException = "error.msg.caanot.transfer.client.as.loan.transaction.present.on.or.after.transfer.date"; + public static final String transferClientLoanExceptionMessage = "error msg caanot transfer client as loan transaction present on or after transfer date"; + public static final String transferClientSavingsException = "error.msg.caanot.transfer.client.as.savings.transaction.present.on.or.after.transfer.date"; + public static final String transferClientSavingsExceptionMessage = "error msg caanot transfer client as savings transaction present on or after transfer date"; + public static final String transferClientToSameOfficeException = "error.msg.cannot.transfer.clinet.as.selected.office.and.current.office.are.same"; + public static final String transferClientToSameOfficeExceptionMessage = "error.msg.cannot.transfer.clinet.as.selected.office.and.current.office.are.same"; } \ No newline at end of file diff --git a/fineract-provider/src/main/java/org/apache/fineract/portfolio/transfer/data/TransfersDataValidator.java b/fineract-provider/src/main/java/org/apache/fineract/portfolio/transfer/data/TransfersDataValidator.java index 273e87a08..b769212a3 100644 --- a/fineract-provider/src/main/java/org/apache/fineract/portfolio/transfer/data/TransfersDataValidator.java +++ b/fineract-provider/src/main/java/org/apache/fineract/portfolio/transfer/data/TransfersDataValidator.java @@ -35,6 +35,7 @@ import org.apache.fineract.infrastructure.core.serialization.FromJsonHelper; import org.apache.fineract.portfolio.client.api.ClientApiConstants; import org.apache.fineract.portfolio.group.api.GroupingTypesApiConstants; import org.apache.fineract.portfolio.transfer.api.TransferApiConstants; +import org.joda.time.LocalDate; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.stereotype.Component; @@ -54,7 +55,7 @@ public final class TransfersDataValidator { private static final Set PROPOSE_CLIENT_TRANSFER_DATA_PARAMETERS = new HashSet<>( Arrays.asList(TransferApiConstants.localeParamName, TransferApiConstants.dateFormatParamName, TransferApiConstants.destinationOfficeIdParamName, TransferApiConstants.transferActiveLoans, - TransferApiConstants.note)); + TransferApiConstants.note, TransferApiConstants.transferDate)); private static final Set ACCEPT_CLIENT_TRANSFER_DATA_PARAMETERS = new HashSet<>( Arrays.asList(TransferApiConstants.newStaffIdParamName, TransferApiConstants.destinationGroupIdParamName, @@ -132,7 +133,7 @@ public final class TransfersDataValidator { .extractLongNamed(TransferApiConstants.destinationOfficeIdParamName, element); baseDataValidator.reset().parameter(TransferApiConstants.destinationOfficeIdParamName).value(destinationOfficeId).notNull() .integerGreaterThanZero(); - + validateNote(baseDataValidator, element); throwExceptionIfValidationWarningsExist(dataValidationErrors); diff --git a/fineract-provider/src/main/java/org/apache/fineract/portfolio/transfer/service/TransferWritePlatformServiceJpaRepositoryImpl.java b/fineract-provider/src/main/java/org/apache/fineract/portfolio/transfer/service/TransferWritePlatformServiceJpaRepositoryImpl.java index d037c1612..b464dba9b 100755 --- a/fineract-provider/src/main/java/org/apache/fineract/portfolio/transfer/service/TransferWritePlatformServiceJpaRepositoryImpl.java +++ b/fineract-provider/src/main/java/org/apache/fineract/portfolio/transfer/service/TransferWritePlatformServiceJpaRepositoryImpl.java @@ -20,13 +20,12 @@ package org.apache.fineract.portfolio.transfer.service; import java.util.ArrayList; import java.util.Date; -import java.util.HashMap; import java.util.List; -import java.util.Map; import org.apache.fineract.infrastructure.core.api.JsonCommand; import org.apache.fineract.infrastructure.core.data.CommandProcessingResult; import org.apache.fineract.infrastructure.core.data.CommandProcessingResultBuilder; +import org.apache.fineract.infrastructure.core.exception.GeneralPlatformDomainRuleException; import org.apache.fineract.infrastructure.core.service.DateUtils; import org.apache.fineract.organisation.office.domain.Office; import org.apache.fineract.organisation.office.domain.OfficeRepositoryWrapper; @@ -42,7 +41,6 @@ import org.apache.fineract.portfolio.client.domain.Client; import org.apache.fineract.portfolio.client.domain.ClientRepositoryWrapper; import org.apache.fineract.portfolio.client.domain.ClientStatus; import org.apache.fineract.portfolio.client.exception.ClientHasBeenClosedException; -import org.apache.fineract.portfolio.common.BusinessEventNotificationConstants.BUSINESS_ENTITY; import org.apache.fineract.portfolio.group.domain.Group; import org.apache.fineract.portfolio.group.domain.GroupRepositoryWrapper; import org.apache.fineract.portfolio.group.exception.ClientNotInGroupException; @@ -60,6 +58,7 @@ import org.apache.fineract.portfolio.transfer.exception.ClientNotAwaitingTransfe import org.apache.fineract.portfolio.transfer.exception.ClientNotAwaitingTransferApprovalOrOnHoldException; import org.apache.fineract.portfolio.transfer.exception.TransferNotSupportedException; import org.apache.fineract.portfolio.transfer.exception.TransferNotSupportedException.TRANSFER_NOT_SUPPORTED_REASON; +import org.joda.time.LocalDate; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.stereotype.Service; import org.springframework.transaction.annotation.Transactional; @@ -295,8 +294,13 @@ public class TransferWritePlatformServiceJpaRepositoryImpl implements TransferWr final Long destinationOfficeId = jsonCommand.longValueOfParameterNamed(TransferApiConstants.destinationOfficeIdParamName); final Office office = this.officeRepository.findOneWithNotFoundDetection(destinationOfficeId); final Client client = this.clientRepositoryWrapper.findOneWithNotFoundDetection(clientId); - handleClientTransferLifecycleEvent(client, office, TransferEventType.PROPOSAL, jsonCommand); - this.clientRepositoryWrapper.save(client); + if (client.getOffice().getId().equals(destinationOfficeId)) { + throw new GeneralPlatformDomainRuleException(TransferApiConstants.transferClientToSameOfficeException, + TransferApiConstants.transferClientToSameOfficeExceptionMessage, office.getName()); + + } + handleClientTransferLifecycleEvent(client, office, TransferEventType.PROPOSAL, jsonCommand); + this.clientRepositoryWrapper.save(client); return new CommandProcessingResultBuilder() // .withClientId(clientId) // .withEntityId(clientId) // @@ -369,6 +373,7 @@ public class TransferWritePlatformServiceJpaRepositoryImpl implements TransferWr Group destinationGroup = null; final Long staffId = jsonCommand.longValueOfParameterNamed(TransferApiConstants.newStaffIdParamName); final Long destinationGroupId = jsonCommand.longValueOfParameterNamed(TransferApiConstants.destinationGroupIdParamName); + final LocalDate transferDate = jsonCommand.localDateValueOfParameterNamed(TransferApiConstants.transferDate); if (staffId != null) { staff = this.staffRepositoryWrapper.findByOfficeHierarchyWithNotFoundDetection(staffId, destinationOffice.getHierarchy()); } @@ -387,17 +392,17 @@ public class TransferWritePlatformServiceJpaRepositoryImpl implements TransferWr if (loan.isDisbursed() && !loan.isClosed()) { switch (transferEventType) { case ACCEPTANCE: - this.loanWritePlatformService.acceptLoanTransfer(loan, DateUtils.getLocalDateOfTenant(), + this.loanWritePlatformService.acceptLoanTransfer(loan, loan.getLastUserTransactionDate(), destinationOffice, staff); break; case PROPOSAL: - this.loanWritePlatformService.initiateLoanTransfer(loan, DateUtils.getLocalDateOfTenant()); + this.loanWritePlatformService.initiateLoanTransfer(loan, transferDate); break; case REJECTION: this.loanWritePlatformService.rejectLoanTransfer(loan); break; case WITHDRAWAL: - this.loanWritePlatformService.withdrawLoanTransfer(loan, DateUtils.getLocalDateOfTenant()); + this.loanWritePlatformService.withdrawLoanTransfer(loan, loan.getLastUserTransactionDate()); } } } @@ -411,18 +416,18 @@ public class TransferWritePlatformServiceJpaRepositoryImpl implements TransferWr switch (transferEventType) { case ACCEPTANCE: this.savingsAccountWritePlatformService.acceptSavingsTransfer(savingsAccount, - DateUtils.getLocalDateOfTenant(), destinationOffice, staff); + savingsAccount.retrieveLastTransactionDate(), destinationOffice, staff); break; case PROPOSAL: this.savingsAccountWritePlatformService.initiateSavingsTransfer(savingsAccount, - DateUtils.getLocalDateOfTenant()); + transferDate); break; case REJECTION: this.savingsAccountWritePlatformService.rejectSavingsTransfer(savingsAccount); break; case WITHDRAWAL: this.savingsAccountWritePlatformService.withdrawSavingsTransfer(savingsAccount, - DateUtils.getLocalDateOfTenant()); + savingsAccount.retrieveLastTransactionDate()); } } }