commit for FINERACT-55 (Standing instruction not disabled at loan/savings account closure)

This commit is contained in:
Emmanuel Nnaa
2016-07-21 15:46:50 +02:00
parent 5ac0da03d3
commit 0e2da60065
5 changed files with 101 additions and 5 deletions
@@ -18,8 +18,32 @@
*/ */
package org.apache.fineract.portfolio.account.domain; package org.apache.fineract.portfolio.account.domain;
import java.util.Collection;
import org.apache.fineract.portfolio.loanaccount.domain.Loan;
import org.apache.fineract.portfolio.savings.domain.SavingsAccount;
import org.springframework.data.jpa.repository.JpaRepository; import org.springframework.data.jpa.repository.JpaRepository;
import org.springframework.data.jpa.repository.JpaSpecificationExecutor; import org.springframework.data.jpa.repository.JpaSpecificationExecutor;
import org.springframework.data.jpa.repository.Query;
import org.springframework.data.repository.query.Param;
public interface StandingInstructionRepository extends JpaRepository<AccountTransferStandingInstruction, Long>, public interface StandingInstructionRepository extends JpaRepository<AccountTransferStandingInstruction, Long>,
JpaSpecificationExecutor<AccountTransferStandingInstruction> {} JpaSpecificationExecutor<AccountTransferStandingInstruction> {
public final static String FIND_BY_LOAN_AND_STATUS_QUERY = "select accountTransferStandingInstruction "
+ "from AccountTransferStandingInstruction accountTransferStandingInstruction "
+ "where accountTransferStandingInstruction.status = :status "
+ "and (accountTransferStandingInstruction.accountTransferDetails.toLoanAccount = :loan "
+ "or accountTransferStandingInstruction.accountTransferDetails.fromLoanAccount = :loan)";
public final static String FIND_BY_SAVINGS_AND_STATUS_QUERY = "select accountTransferStandingInstruction "
+ "from AccountTransferStandingInstruction accountTransferStandingInstruction "
+ "where accountTransferStandingInstruction.status = :status "
+ "and (accountTransferStandingInstruction.accountTransferDetails.toSavingsAccount = :savingsAccount "
+ "or accountTransferStandingInstruction.accountTransferDetails.fromSavingsAccount = :savingsAccount)";
@Query(FIND_BY_LOAN_AND_STATUS_QUERY)
public Collection<AccountTransferStandingInstruction> findByLoanAccountAndStatus(@Param("loan") Loan loan, @Param("status") Integer status);
@Query(FIND_BY_SAVINGS_AND_STATUS_QUERY)
public Collection<AccountTransferStandingInstruction> findBySavingsAccountAndStatus(@Param("savingsAccount") SavingsAccount savingsAccount, @Param("status") Integer status);
}
@@ -58,4 +58,11 @@ public interface LoanAccountDomainService {
void saveLoanWithDataIntegrityViolationChecks(Loan loan); void saveLoanWithDataIntegrityViolationChecks(Loan loan);
Map<String, Object> foreCloseLoan(final Loan loan, final LocalDate foreClourseDate, String noteText); Map<String, Object> foreCloseLoan(final Loan loan, final LocalDate foreClourseDate, String noteText);
/**
* Disables all standing instructions linked to a closed loan
*
* @param loan {@link Loan} object
*/
void disableStandingInstructionsLinkedToClosedLoan(Loan loan);
} }
@@ -50,7 +50,10 @@ import org.apache.fineract.organisation.monetary.domain.Money;
import org.apache.fineract.organisation.workingdays.domain.WorkingDays; import org.apache.fineract.organisation.workingdays.domain.WorkingDays;
import org.apache.fineract.organisation.workingdays.domain.WorkingDaysRepositoryWrapper; import org.apache.fineract.organisation.workingdays.domain.WorkingDaysRepositoryWrapper;
import org.apache.fineract.portfolio.account.domain.AccountTransferRepository; 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.AccountTransferTransaction;
import org.apache.fineract.portfolio.account.domain.StandingInstructionRepository;
import org.apache.fineract.portfolio.account.domain.StandingInstructionStatus;
import org.apache.fineract.portfolio.client.domain.Client; import org.apache.fineract.portfolio.client.domain.Client;
import org.apache.fineract.portfolio.client.exception.ClientNotActiveException; import org.apache.fineract.portfolio.client.exception.ClientNotActiveException;
import org.apache.fineract.portfolio.common.BusinessEventNotificationConstants.BUSINESS_ENTITY; import org.apache.fineract.portfolio.common.BusinessEventNotificationConstants.BUSINESS_ENTITY;
@@ -96,6 +99,7 @@ public class LoanAccountDomainServiceJpa implements LoanAccountDomainService {
private final PlatformSecurityContext context; private final PlatformSecurityContext context;
private final BusinessEventNotifierService businessEventNotifierService; private final BusinessEventNotifierService businessEventNotifierService;
private final LoanUtilService loanUtilService; private final LoanUtilService loanUtilService;
private final StandingInstructionRepository standingInstructionRepository;
@Autowired @Autowired
public LoanAccountDomainServiceJpa(final LoanAssembler loanAccountAssembler, final LoanRepository loanRepository, public LoanAccountDomainServiceJpa(final LoanAssembler loanAccountAssembler, final LoanRepository loanRepository,
@@ -108,7 +112,8 @@ public class LoanAccountDomainServiceJpa implements LoanAccountDomainService {
final ApplicationCurrencyRepositoryWrapper applicationCurrencyRepository, final ApplicationCurrencyRepositoryWrapper applicationCurrencyRepository,
final LoanRepaymentScheduleInstallmentRepository repaymentScheduleInstallmentRepository, final LoanRepaymentScheduleInstallmentRepository repaymentScheduleInstallmentRepository,
final LoanAccrualPlatformService loanAccrualPlatformService, final PlatformSecurityContext context, final LoanAccrualPlatformService loanAccrualPlatformService, final PlatformSecurityContext context,
final BusinessEventNotifierService businessEventNotifierService, final LoanUtilService loanUtilService) { final BusinessEventNotifierService businessEventNotifierService, final LoanUtilService loanUtilService,
final StandingInstructionRepository standingInstructionRepository) {
this.loanAccountAssembler = loanAccountAssembler; this.loanAccountAssembler = loanAccountAssembler;
this.loanRepository = loanRepository; this.loanRepository = loanRepository;
this.loanTransactionRepository = loanTransactionRepository; this.loanTransactionRepository = loanTransactionRepository;
@@ -125,6 +130,7 @@ public class LoanAccountDomainServiceJpa implements LoanAccountDomainService {
this.context = context; this.context = context;
this.businessEventNotifierService = businessEventNotifierService; this.businessEventNotifierService = businessEventNotifierService;
this.loanUtilService = loanUtilService; this.loanUtilService = loanUtilService;
this.standingInstructionRepository = standingInstructionRepository;
} }
@Transactional @Transactional
@@ -208,6 +214,9 @@ public class LoanAccountDomainServiceJpa implements LoanAccountDomainService {
this.businessEventNotifierService.notifyBusinessEventWasExecuted(BUSINESS_EVENTS.LOAN_MAKE_REPAYMENT, this.businessEventNotifierService.notifyBusinessEventWasExecuted(BUSINESS_EVENTS.LOAN_MAKE_REPAYMENT,
constructEntityMap(BUSINESS_ENTITY.LOAN_TRANSACTION, newRepaymentTransaction)); constructEntityMap(BUSINESS_ENTITY.LOAN_TRANSACTION, newRepaymentTransaction));
// disable all active standing orders linked to this loan if status changes to closed
disableStandingInstructionsLinkedToClosedLoan(loan);
builderResult.withEntityId(newRepaymentTransaction.getId()) // builderResult.withEntityId(newRepaymentTransaction.getId()) //
.withOfficeId(loan.getOfficeId()) // .withOfficeId(loan.getOfficeId()) //
@@ -705,4 +714,20 @@ public class LoanAccountDomainServiceJpa implements LoanAccountDomainService {
return map; return map;
} }
} @Override
@Transactional
public void disableStandingInstructionsLinkedToClosedLoan(Loan loan) {
if ((loan != null) && (loan.status() != null) && loan.status().isClosed()) {
final Integer standingInstructionStatus = StandingInstructionStatus.ACTIVE.getValue();
final Collection<AccountTransferStandingInstruction> accountTransferStandingInstructions = this.standingInstructionRepository
.findByLoanAccountAndStatus(loan, standingInstructionStatus);
if (!accountTransferStandingInstructions.isEmpty()) {
for (AccountTransferStandingInstruction accountTransferStandingInstruction : accountTransferStandingInstructions) {
accountTransferStandingInstruction.updateStatus(StandingInstructionStatus.DISABLED.getValue());
this.standingInstructionRepository.save(accountTransferStandingInstruction);
}
}
}
}
}
@@ -1165,6 +1165,10 @@ public class LoanWritePlatformServiceJpaRepositoryImpl implements LoanWritePlatf
this.loanAccountDomainService.recalculateAccruals(loan); this.loanAccountDomainService.recalculateAccruals(loan);
this.businessEventNotifierService.notifyBusinessEventWasExecuted(BUSINESS_EVENTS.LOAN_CLOSE, this.businessEventNotifierService.notifyBusinessEventWasExecuted(BUSINESS_EVENTS.LOAN_CLOSE,
constructEntityMap(BUSINESS_ENTITY.LOAN, loan)); constructEntityMap(BUSINESS_ENTITY.LOAN, loan));
// disable all active standing instructions linked to the loan
this.loanAccountDomainService.disableStandingInstructionsLinkedToClosedLoan(loan);
CommandProcessingResult result = null; CommandProcessingResult result = null;
if (possibleClosingTransaction != null) { if (possibleClosingTransaction != null) {
@@ -1221,6 +1225,10 @@ public class LoanWritePlatformServiceJpaRepositoryImpl implements LoanWritePlatf
} }
this.businessEventNotifierService.notifyBusinessEventWasExecuted(BUSINESS_EVENTS.LOAN_CLOSE_AS_RESCHEDULE, this.businessEventNotifierService.notifyBusinessEventWasExecuted(BUSINESS_EVENTS.LOAN_CLOSE_AS_RESCHEDULE,
constructEntityMap(BUSINESS_ENTITY.LOAN, loan)); constructEntityMap(BUSINESS_ENTITY.LOAN, loan));
// disable all active standing instructions linked to the loan
this.loanAccountDomainService.disableStandingInstructionsLinkedToClosedLoan(loan);
return new CommandProcessingResultBuilder() // return new CommandProcessingResultBuilder() //
.withCommandId(command.commandId()) // .withCommandId(command.commandId()) //
.withEntityId(loanId) // .withEntityId(loanId) //
@@ -29,6 +29,7 @@ import static org.apache.fineract.portfolio.savings.SavingsApiConstants.withdraw
import java.math.BigDecimal; import java.math.BigDecimal;
import java.math.MathContext; import java.math.MathContext;
import java.util.ArrayList; import java.util.ArrayList;
import java.util.Collection;
import java.util.HashMap; import java.util.HashMap;
import java.util.HashSet; import java.util.HashSet;
import java.util.LinkedHashMap; import java.util.LinkedHashMap;
@@ -60,6 +61,9 @@ import org.apache.fineract.organisation.staff.domain.Staff;
import org.apache.fineract.organisation.staff.domain.StaffRepositoryWrapper; import org.apache.fineract.organisation.staff.domain.StaffRepositoryWrapper;
import org.apache.fineract.organisation.workingdays.domain.WorkingDaysRepositoryWrapper; import org.apache.fineract.organisation.workingdays.domain.WorkingDaysRepositoryWrapper;
import org.apache.fineract.portfolio.account.PortfolioAccountType; import org.apache.fineract.portfolio.account.PortfolioAccountType;
import org.apache.fineract.portfolio.account.domain.AccountTransferStandingInstruction;
import org.apache.fineract.portfolio.account.domain.StandingInstructionRepository;
import org.apache.fineract.portfolio.account.domain.StandingInstructionStatus;
import org.apache.fineract.portfolio.account.service.AccountAssociationsReadPlatformService; import org.apache.fineract.portfolio.account.service.AccountAssociationsReadPlatformService;
import org.apache.fineract.portfolio.account.service.AccountTransfersReadPlatformService; import org.apache.fineract.portfolio.account.service.AccountTransfersReadPlatformService;
import org.apache.fineract.portfolio.charge.domain.Charge; import org.apache.fineract.portfolio.charge.domain.Charge;
@@ -133,6 +137,7 @@ public class SavingsAccountWritePlatformServiceJpaRepositoryImpl implements Savi
private final ConfigurationDomainService configurationDomainService; private final ConfigurationDomainService configurationDomainService;
private final DepositAccountOnHoldTransactionRepository depositAccountOnHoldTransactionRepository; private final DepositAccountOnHoldTransactionRepository depositAccountOnHoldTransactionRepository;
private final AppUserRepositoryWrapper appuserRepository; private final AppUserRepositoryWrapper appuserRepository;
private final StandingInstructionRepository standingInstructionRepository;
@Autowired @Autowired
public SavingsAccountWritePlatformServiceJpaRepositoryImpl(final PlatformSecurityContext context, public SavingsAccountWritePlatformServiceJpaRepositoryImpl(final PlatformSecurityContext context,
@@ -152,7 +157,8 @@ public class SavingsAccountWritePlatformServiceJpaRepositoryImpl implements Savi
final SavingsAccountDataValidator fromApiJsonDeserializer, final SavingsAccountRepositoryWrapper savingsRepository, final SavingsAccountDataValidator fromApiJsonDeserializer, final SavingsAccountRepositoryWrapper savingsRepository,
final StaffRepositoryWrapper staffRepository, final ConfigurationDomainService configurationDomainService, final StaffRepositoryWrapper staffRepository, final ConfigurationDomainService configurationDomainService,
final DepositAccountOnHoldTransactionRepository depositAccountOnHoldTransactionRepository, final DepositAccountOnHoldTransactionRepository depositAccountOnHoldTransactionRepository,
final AppUserRepositoryWrapper appuserRepository) { final AppUserRepositoryWrapper appuserRepository,
final StandingInstructionRepository standingInstructionRepository) {
this.context = context; this.context = context;
this.savingAccountRepository = savingAccountRepository; this.savingAccountRepository = savingAccountRepository;
this.savingsAccountTransactionRepository = savingsAccountTransactionRepository; this.savingsAccountTransactionRepository = savingsAccountTransactionRepository;
@@ -176,6 +182,7 @@ public class SavingsAccountWritePlatformServiceJpaRepositoryImpl implements Savi
this.configurationDomainService = configurationDomainService; this.configurationDomainService = configurationDomainService;
this.depositAccountOnHoldTransactionRepository = depositAccountOnHoldTransactionRepository; this.depositAccountOnHoldTransactionRepository = depositAccountOnHoldTransactionRepository;
this.appuserRepository = appuserRepository; this.appuserRepository = appuserRepository;
this.standingInstructionRepository = standingInstructionRepository;
} }
@Transactional @Transactional
@@ -646,6 +653,10 @@ public class SavingsAccountWritePlatformServiceJpaRepositoryImpl implements Savi
} }
} }
// disable all standing orders linked to the savings account
this.disableStandingInstructionsLinkedToClosedSavings(account);
return new CommandProcessingResultBuilder() // return new CommandProcessingResultBuilder() //
.withEntityId(savingsId) // .withEntityId(savingsId) //
.withOfficeId(account.officeId()) // .withOfficeId(account.officeId()) //
@@ -1275,4 +1286,25 @@ public class SavingsAccountWritePlatformServiceJpaRepositoryImpl implements Savi
return user; return user;
} }
} /**
* Disable all standing instructions linked to the savings account if the status is "closed"
*
* @param savingsAccount -- the savings account object
* @return None
**/
@Transactional
private void disableStandingInstructionsLinkedToClosedSavings(final SavingsAccount savingsAccount) {
if (savingsAccount != null && savingsAccount.isClosed()) {
final Integer standingInstructionStatus = StandingInstructionStatus.ACTIVE.getValue();
final Collection<AccountTransferStandingInstruction> accountTransferStandingInstructions = this.standingInstructionRepository
.findBySavingsAccountAndStatus(savingsAccount, standingInstructionStatus);
if (!accountTransferStandingInstructions.isEmpty()) {
for (AccountTransferStandingInstruction accountTransferStandingInstruction : accountTransferStandingInstructions) {
accountTransferStandingInstruction.updateStatus(StandingInstructionStatus.DISABLED.getValue());
this.standingInstructionRepository.save(accountTransferStandingInstruction);
}
}
}
}
}