FINERACT-627 Back dated client transfer

This commit is contained in:
ShruthiRajaram
2018-11-16 15:13:07 +05:30
parent b0fbc6e6bc
commit ec57197809
10 changed files with 281 additions and 53 deletions
+2 -1
View File
@@ -5761,7 +5761,7 @@ Request Body:
<div class="method-section">
<div class="method-description">
<h4>Propose a Client Transfer</h4>
<p>Allows you to propose the transfer of a <i>Client</i> to a different <i>Office</i>.</p>
<p>Allows you to propose the transfer of a <i>Client</i> to a different <i>Office</i> on a specific date, if loan or savings transaction not present from proposed transfer date to current date.</p>
</div>
<div class="method-example">
<code class="method-declaration">POST https://Domain Name/api/v1/clients/{clientId}?command=proposeTransfer</code>
@@ -5769,6 +5769,7 @@ Request Body:
Content-Type: application/json
Request Body:
{
"transferDate":"28 August 2018",
"destinationOfficeId":"2",
"note":"Client Relocating to Bangalore"
}
@@ -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);
}
}
@@ -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<ClientData> retrieveActiveClientMembersOfCenter(final Long centerId);
ClientData retrieveAllNarrations(String clientNarrations);
Date retrieveClientTransferProposalDate(Long clientId);
Date retrieveClientTransferProposalDateByLoan(Long clientId);
Date retrieveClientTransferProposalDateBySavings(Long clientId);
void validateClient(Long clientId);
}
@@ -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);
}
}
}
@@ -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<Long> existingTransactionIds = new ArrayList<>(loan.findExistingTransactionIds());
final List<Long> 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);
}
}
}
}
@@ -111,7 +111,7 @@ public final class SavingsAccountTransaction extends AbstractPersistableCustom<L
@Column(name = "created_date", nullable = false)
private Date createdDate;
@ManyToOne
@ManyToOne
@JoinColumn(name = "appuser_id", nullable = true)
private AppUser appUser;
@@ -790,5 +790,9 @@ public final class SavingsAccountTransaction extends AbstractPersistableCustom<L
public boolean isAmountOnHoldNotReleased() {
return (isAmountOnHold() && getReleaseIdOfHoldAmountTransaction() == null);
}
}
public Date getCreatedDate() {
return createdDate;
}
}
@@ -18,11 +18,25 @@
*/
package org.apache.fineract.portfolio.savings.service;
import static org.apache.fineract.portfolio.savings.SavingsApiConstants.*;
import static org.apache.fineract.portfolio.savings.SavingsApiConstants.SAVINGS_ACCOUNT_CHARGE_RESOURCE_NAME;
import static org.apache.fineract.portfolio.savings.SavingsApiConstants.SAVINGS_ACCOUNT_RESOURCE_NAME;
import static org.apache.fineract.portfolio.savings.SavingsApiConstants.amountParamName;
import static org.apache.fineract.portfolio.savings.SavingsApiConstants.chargeIdParamName;
import static org.apache.fineract.portfolio.savings.SavingsApiConstants.dueAsOfDateParamName;
import static org.apache.fineract.portfolio.savings.SavingsApiConstants.withHoldTaxParamName;
import static org.apache.fineract.portfolio.savings.SavingsApiConstants.withdrawBalanceParamName;
import java.math.BigDecimal;
import java.math.MathContext;
import java.util.*;
import java.util.ArrayList;
import java.util.Collection;
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;
@@ -32,6 +46,7 @@ import org.apache.fineract.infrastructure.core.data.ApiParameterError;
import org.apache.fineract.infrastructure.core.data.CommandProcessingResult;
import org.apache.fineract.infrastructure.core.data.CommandProcessingResultBuilder;
import org.apache.fineract.infrastructure.core.data.DataValidatorBuilder;
import org.apache.fineract.infrastructure.core.exception.GeneralPlatformDomainRuleException;
import org.apache.fineract.infrastructure.core.exception.PlatformApiDataValidationException;
import org.apache.fineract.infrastructure.core.exception.PlatformServiceUnavailableException;
import org.apache.fineract.infrastructure.core.service.DateUtils;
@@ -40,7 +55,11 @@ import org.apache.fineract.infrastructure.dataqueries.data.StatusEnum;
import org.apache.fineract.infrastructure.dataqueries.service.EntityDatatableChecksWritePlatformService;
import org.apache.fineract.infrastructure.security.service.PlatformSecurityContext;
import org.apache.fineract.organisation.holiday.domain.HolidayRepositoryWrapper;
import org.apache.fineract.organisation.monetary.domain.*;
import org.apache.fineract.organisation.monetary.domain.ApplicationCurrency;
import org.apache.fineract.organisation.monetary.domain.ApplicationCurrencyRepositoryWrapper;
import org.apache.fineract.organisation.monetary.domain.MonetaryCurrency;
import org.apache.fineract.organisation.monetary.domain.Money;
import org.apache.fineract.organisation.monetary.domain.MoneyHelper;
import org.apache.fineract.organisation.office.domain.Office;
import org.apache.fineract.organisation.staff.domain.Staff;
import org.apache.fineract.organisation.staff.domain.StaffRepositoryWrapper;
@@ -72,12 +91,30 @@ import org.apache.fineract.portfolio.savings.data.SavingsAccountChargeDataValida
import org.apache.fineract.portfolio.savings.data.SavingsAccountDataValidator;
import org.apache.fineract.portfolio.savings.data.SavingsAccountTransactionDTO;
import org.apache.fineract.portfolio.savings.data.SavingsAccountTransactionDataValidator;
import org.apache.fineract.portfolio.savings.domain.*;
import org.apache.fineract.portfolio.savings.exception.*;
import org.apache.fineract.portfolio.savings.domain.DepositAccountOnHoldTransaction;
import org.apache.fineract.portfolio.savings.domain.DepositAccountOnHoldTransactionRepository;
import org.apache.fineract.portfolio.savings.domain.SavingsAccount;
import org.apache.fineract.portfolio.savings.domain.SavingsAccountAssembler;
import org.apache.fineract.portfolio.savings.domain.SavingsAccountCharge;
import org.apache.fineract.portfolio.savings.domain.SavingsAccountChargeRepositoryWrapper;
import org.apache.fineract.portfolio.savings.domain.SavingsAccountDomainService;
import org.apache.fineract.portfolio.savings.domain.SavingsAccountRepositoryWrapper;
import org.apache.fineract.portfolio.savings.domain.SavingsAccountStatusType;
import org.apache.fineract.portfolio.savings.domain.SavingsAccountTransaction;
import org.apache.fineract.portfolio.savings.domain.SavingsAccountTransactionRepository;
import org.apache.fineract.portfolio.savings.exception.PostInterestAsOnDateException;
import org.apache.fineract.portfolio.savings.exception.PostInterestAsOnDateException.PostInterestAsOnException_TYPE;
import org.apache.fineract.portfolio.savings.exception.PostInterestClosingDateException;
import org.apache.fineract.portfolio.savings.exception.SavingsAccountClosingNotAllowedException;
import org.apache.fineract.portfolio.savings.exception.SavingsAccountTransactionNotFoundException;
import org.apache.fineract.portfolio.savings.exception.SavingsOfficerAssignmentException;
import org.apache.fineract.portfolio.savings.exception.SavingsOfficerUnassignmentException;
import org.apache.fineract.portfolio.savings.exception.TransactionUpdateNotAllowedException;
import org.apache.fineract.portfolio.transfer.api.TransferApiConstants;
import org.apache.fineract.useradministration.domain.AppUser;
import org.apache.fineract.useradministration.domain.AppUserRepositoryWrapper;
import org.joda.time.LocalDate;
import org.joda.time.LocalDateTime;
import org.joda.time.format.DateTimeFormat;
import org.joda.time.format.DateTimeFormatter;
import org.springframework.beans.factory.annotation.Autowired;
@@ -720,6 +757,9 @@ public class SavingsAccountWritePlatformServiceJpaRepositoryImpl implements Savi
final boolean isSavingsInterestPostingAtCurrentPeriodEnd = this.configurationDomainService
.isSavingsInterestPostingAtCurrentPeriodEnd();
validateTransactionsForTransfer(savingsAccount, transferDate);
final Integer financialYearBeginningMonth = this.configurationDomainService.retrieveFinancialYearBeginningMonth();
this.savingAccountAssembler.setHelpers(savingsAccount);
final Set<Long> 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);
}
}
}
}
@@ -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";
}
@@ -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<String> 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<String> 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);
@@ -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());
}
}
}