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());
}
}
}