FINERACT-2107: Adjust event trigger on refund reversion
This commit is contained in:
+3
-57
@@ -2360,7 +2360,7 @@ public class Loan extends AbstractAuditableWithUTCDateTimeCustom<Long> {
|
||||
doPostLoanTransactionChecks(loanTransaction.getTransactionDate(), loanLifecycleStateMachine);
|
||||
}
|
||||
|
||||
private ChangedTransactionDetail handleRepaymentOrRecoveryOrWaiverTransaction(final LoanTransaction loanTransaction,
|
||||
public ChangedTransactionDetail handleRepaymentOrRecoveryOrWaiverTransaction(final LoanTransaction loanTransaction,
|
||||
final LoanLifecycleStateMachine loanLifecycleStateMachine, final LoanTransaction adjustedTransaction,
|
||||
final ScheduleGeneratorDTO scheduleGeneratorDTO) {
|
||||
ChangedTransactionDetail changedTransactionDetail = null;
|
||||
@@ -2681,60 +2681,6 @@ public class Loan extends AbstractAuditableWithUTCDateTimeCustom<Long> {
|
||||
possibleInterestToWaive.zero(), ExternalId.empty());
|
||||
}
|
||||
|
||||
public ChangedTransactionDetail adjustExistingTransaction(final LoanTransaction newTransactionDetail,
|
||||
final LoanLifecycleStateMachine loanLifecycleStateMachine, final LoanTransaction transactionForAdjustment,
|
||||
final List<Long> existingTransactionIds, final List<Long> existingReversedTransactionIds,
|
||||
final ScheduleGeneratorDTO scheduleGeneratorDTO, final ExternalId reversalExternalId) {
|
||||
|
||||
ChangedTransactionDetail changedTransactionDetail = null;
|
||||
|
||||
existingTransactionIds.addAll(findExistingTransactionIds());
|
||||
existingReversedTransactionIds.addAll(findExistingReversedTransactionIds());
|
||||
|
||||
validateActivityNotBeforeClientOrGroupTransferDate(LoanEvent.LOAN_REPAYMENT_OR_WAIVER,
|
||||
transactionForAdjustment.getTransactionDate());
|
||||
|
||||
if (transactionForAdjustment.isNotRepaymentLikeType() && transactionForAdjustment.isNotWaiver()
|
||||
&& transactionForAdjustment.isNotCreditBalanceRefund()) {
|
||||
final String errorMessage = "Only (non-reversed) transactions of type repayment, waiver or credit balance refund can be adjusted.";
|
||||
throw new InvalidLoanTransactionTypeException("transaction",
|
||||
"adjustment.is.only.allowed.to.repayment.or.waiver.or.creditbalancerefund.transactions", errorMessage);
|
||||
}
|
||||
|
||||
transactionForAdjustment.reverse(reversalExternalId);
|
||||
transactionForAdjustment.manuallyAdjustedOrReversed();
|
||||
|
||||
if (transactionForAdjustment.getTypeOf().equals(LoanTransactionType.MERCHANT_ISSUED_REFUND)
|
||||
|| transactionForAdjustment.getTypeOf().equals(LoanTransactionType.PAYOUT_REFUND)) {
|
||||
getLoanTransactions().stream() //
|
||||
.filter(LoanTransaction::isNotReversed)
|
||||
.filter(loanTransaction -> loanTransaction.getLoanTransactionRelations().stream()
|
||||
.anyMatch(relation -> relation.getRelationType().equals(LoanTransactionRelationTypeEnum.RELATED)
|
||||
&& relation.getToTransaction().getId().equals(transactionForAdjustment.getId())))
|
||||
.forEach(loanTransaction -> {
|
||||
loanTransaction.reverse();
|
||||
loanTransaction.manuallyAdjustedOrReversed();
|
||||
});
|
||||
}
|
||||
|
||||
if (isClosedWrittenOff()) {
|
||||
// find write off transaction and reverse it
|
||||
final LoanTransaction writeOffTransaction = findWriteOffTransaction();
|
||||
writeOffTransaction.reverse();
|
||||
}
|
||||
|
||||
if (isClosedObligationsMet() || isClosedWrittenOff() || isClosedWithOutstandingAmountMarkedForReschedule()) {
|
||||
loanLifecycleStateMachine.transition(LoanEvent.LOAN_ADJUST_TRANSACTION, this);
|
||||
}
|
||||
|
||||
if (newTransactionDetail.isRepaymentLikeType() || newTransactionDetail.isInterestWaiver()) {
|
||||
changedTransactionDetail = handleRepaymentOrRecoveryOrWaiverTransaction(newTransactionDetail, loanLifecycleStateMachine,
|
||||
transactionForAdjustment, scheduleGeneratorDTO);
|
||||
}
|
||||
|
||||
return changedTransactionDetail;
|
||||
}
|
||||
|
||||
public ChangedTransactionDetail undoWrittenOff(LoanLifecycleStateMachine loanLifecycleStateMachine,
|
||||
final List<Long> existingTransactionIds, final List<Long> existingReversedTransactionIds,
|
||||
final ScheduleGeneratorDTO scheduleGeneratorDTO) {
|
||||
@@ -3087,7 +3033,7 @@ public class Loan extends AbstractAuditableWithUTCDateTimeCustom<Long> {
|
||||
return getStatus().isClosedWrittenOff();
|
||||
}
|
||||
|
||||
private boolean isClosedWithOutstandingAmountMarkedForReschedule() {
|
||||
public boolean isClosedWithOutstandingAmountMarkedForReschedule() {
|
||||
return getStatus().isClosedWithOutsandingAmountMarkedForReschedule();
|
||||
}
|
||||
|
||||
@@ -3777,7 +3723,7 @@ public class Loan extends AbstractAuditableWithUTCDateTimeCustom<Long> {
|
||||
this.loanTransactions.remove(loanTransaction);
|
||||
}
|
||||
|
||||
private void validateActivityNotBeforeClientOrGroupTransferDate(final LoanEvent event, final LocalDate activityDate) {
|
||||
public void validateActivityNotBeforeClientOrGroupTransferDate(final LoanEvent event, final LocalDate activityDate) {
|
||||
if (this.client != null && this.client.getOfficeJoiningDate() != null) {
|
||||
final LocalDate clientOfficeJoiningDate = this.client.getOfficeJoiningDate();
|
||||
if (DateUtils.isBefore(activityDate, clientOfficeJoiningDate)) {
|
||||
|
||||
+57
-1
@@ -1489,7 +1489,7 @@ public class LoanWritePlatformServiceJpaRepositoryImpl implements LoanWritePlatf
|
||||
loanTransactionValidator.validateRepaymentDateIsOnNonWorkingDay(newTransactionDetail.getTransactionDate(),
|
||||
holidayDetailDTO.getWorkingDays(), holidayDetailDTO.isAllowTransactionsOnNonWorkingDay());
|
||||
|
||||
final ChangedTransactionDetail changedTransactionDetail = loan.adjustExistingTransaction(newTransactionDetail,
|
||||
final ChangedTransactionDetail changedTransactionDetail = adjustExistingTransaction(loan, newTransactionDetail,
|
||||
loanLifecycleStateMachine, transactionToAdjust, existingTransactionIds, existingReversedTransactionIds,
|
||||
scheduleGeneratorDTO, reversalTxnExternalId);
|
||||
|
||||
@@ -1583,6 +1583,62 @@ public class LoanWritePlatformServiceJpaRepositoryImpl implements LoanWritePlatf
|
||||
.with(changes).build();
|
||||
}
|
||||
|
||||
public ChangedTransactionDetail adjustExistingTransaction(final Loan loan, final LoanTransaction newTransactionDetail,
|
||||
final LoanLifecycleStateMachine loanLifecycleStateMachine, final LoanTransaction transactionForAdjustment,
|
||||
final List<Long> existingTransactionIds, final List<Long> existingReversedTransactionIds,
|
||||
final ScheduleGeneratorDTO scheduleGeneratorDTO, final ExternalId reversalExternalId) {
|
||||
|
||||
ChangedTransactionDetail changedTransactionDetail = null;
|
||||
|
||||
existingTransactionIds.addAll(loan.findExistingTransactionIds());
|
||||
existingReversedTransactionIds.addAll(loan.findExistingReversedTransactionIds());
|
||||
|
||||
loan.validateActivityNotBeforeClientOrGroupTransferDate(LoanEvent.LOAN_REPAYMENT_OR_WAIVER,
|
||||
transactionForAdjustment.getTransactionDate());
|
||||
|
||||
if (transactionForAdjustment.isNotRepaymentLikeType() && transactionForAdjustment.isNotWaiver()
|
||||
&& transactionForAdjustment.isNotCreditBalanceRefund()) {
|
||||
final String errorMessage = "Only (non-reversed) transactions of type repayment, waiver or credit balance refund can be adjusted.";
|
||||
throw new InvalidLoanTransactionTypeException("transaction",
|
||||
"adjustment.is.only.allowed.to.repayment.or.waiver.or.creditbalancerefund.transactions", errorMessage);
|
||||
}
|
||||
|
||||
transactionForAdjustment.reverse(reversalExternalId);
|
||||
transactionForAdjustment.manuallyAdjustedOrReversed();
|
||||
|
||||
if (transactionForAdjustment.getTypeOf().equals(LoanTransactionType.MERCHANT_ISSUED_REFUND)
|
||||
|| transactionForAdjustment.getTypeOf().equals(LoanTransactionType.PAYOUT_REFUND)) {
|
||||
loan.getLoanTransactions().stream() //
|
||||
.filter(LoanTransaction::isNotReversed)
|
||||
.filter(loanTransaction -> loanTransaction.getLoanTransactionRelations().stream()
|
||||
.anyMatch(relation -> relation.getRelationType().equals(LoanTransactionRelationTypeEnum.RELATED)
|
||||
&& relation.getToTransaction().getId().equals(transactionForAdjustment.getId())))
|
||||
.forEach(loanTransaction -> {
|
||||
loanTransaction.reverse();
|
||||
loanTransaction.manuallyAdjustedOrReversed();
|
||||
LoanAdjustTransactionBusinessEvent.Data eventData = new LoanAdjustTransactionBusinessEvent.Data(loanTransaction);
|
||||
businessEventNotifierService.notifyPostBusinessEvent(new LoanAdjustTransactionBusinessEvent(eventData));
|
||||
});
|
||||
}
|
||||
|
||||
if (loan.isClosedWrittenOff()) {
|
||||
// find write off transaction and reverse it
|
||||
final LoanTransaction writeOffTransaction = loan.findWriteOffTransaction();
|
||||
writeOffTransaction.reverse();
|
||||
}
|
||||
|
||||
if (loan.isClosedObligationsMet() || loan.isClosedWrittenOff() || loan.isClosedWithOutstandingAmountMarkedForReschedule()) {
|
||||
loanLifecycleStateMachine.transition(LoanEvent.LOAN_ADJUST_TRANSACTION, loan);
|
||||
}
|
||||
|
||||
if (newTransactionDetail.isRepaymentLikeType() || newTransactionDetail.isInterestWaiver()) {
|
||||
changedTransactionDetail = loan.handleRepaymentOrRecoveryOrWaiverTransaction(newTransactionDetail, loanLifecycleStateMachine,
|
||||
transactionForAdjustment, scheduleGeneratorDTO);
|
||||
}
|
||||
|
||||
return changedTransactionDetail;
|
||||
}
|
||||
|
||||
@Transactional
|
||||
@Override
|
||||
public CommandProcessingResult chargebackLoanTransaction(final Long loanId, final Long transactionId, final JsonCommand command) {
|
||||
|
||||
+302
@@ -0,0 +1,302 @@
|
||||
/**
|
||||
* Licensed to the Apache Software Foundation (ASF) under one
|
||||
* or more contributor license agreements. See the NOTICE file
|
||||
* distributed with this work for additional information
|
||||
* regarding copyright ownership. The ASF licenses this file
|
||||
* to you under the Apache License, Version 2.0 (the
|
||||
* "License"); you may not use this file except in compliance
|
||||
* with the License. You may obtain a copy of the License at
|
||||
*
|
||||
* 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
|
||||
* KIND, either express or implied. See the License for the
|
||||
* specific language governing permissions and limitations
|
||||
* under the License.
|
||||
*/
|
||||
package org.apache.fineract.portfolio.loanaccount.service;
|
||||
|
||||
import static org.junit.jupiter.api.Assertions.assertEquals;
|
||||
import static org.mockito.ArgumentMatchers.any;
|
||||
import static org.mockito.Mockito.doNothing;
|
||||
import static org.mockito.Mockito.mock;
|
||||
import static org.mockito.Mockito.never;
|
||||
import static org.mockito.Mockito.verify;
|
||||
import static org.mockito.Mockito.when;
|
||||
|
||||
import java.time.LocalDate;
|
||||
import java.time.ZoneId;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Arrays;
|
||||
import java.util.Collections;
|
||||
import java.util.HashSet;
|
||||
import java.util.List;
|
||||
import java.util.Set;
|
||||
import org.apache.fineract.accounting.journalentry.service.JournalEntryWritePlatformService;
|
||||
import org.apache.fineract.cob.service.LoanAccountLockService;
|
||||
import org.apache.fineract.infrastructure.codes.domain.CodeValueRepositoryWrapper;
|
||||
import org.apache.fineract.infrastructure.configuration.domain.ConfigurationDomainService;
|
||||
import org.apache.fineract.infrastructure.core.domain.ExternalId;
|
||||
import org.apache.fineract.infrastructure.core.exception.ErrorHandler;
|
||||
import org.apache.fineract.infrastructure.core.serialization.FromJsonHelper;
|
||||
import org.apache.fineract.infrastructure.core.service.ExternalIdFactory;
|
||||
import org.apache.fineract.infrastructure.dataqueries.service.EntityDatatableChecksWritePlatformService;
|
||||
import org.apache.fineract.infrastructure.event.business.domain.loan.LoanAdjustTransactionBusinessEvent;
|
||||
import org.apache.fineract.infrastructure.event.business.service.BusinessEventNotifierService;
|
||||
import org.apache.fineract.infrastructure.security.service.PlatformSecurityContext;
|
||||
import org.apache.fineract.organisation.holiday.domain.HolidayRepositoryWrapper;
|
||||
import org.apache.fineract.organisation.teller.data.CashierTransactionDataValidator;
|
||||
import org.apache.fineract.organisation.workingdays.domain.WorkingDaysRepositoryWrapper;
|
||||
import org.apache.fineract.portfolio.account.domain.AccountAssociationsRepository;
|
||||
import org.apache.fineract.portfolio.account.domain.AccountTransferDetailRepository;
|
||||
import org.apache.fineract.portfolio.account.domain.AccountTransferRepository;
|
||||
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.calendar.domain.CalendarInstanceRepository;
|
||||
import org.apache.fineract.portfolio.calendar.domain.CalendarRepository;
|
||||
import org.apache.fineract.portfolio.loanaccount.data.ScheduleGeneratorDTO;
|
||||
import org.apache.fineract.portfolio.loanaccount.domain.GLIMAccountInfoRepository;
|
||||
import org.apache.fineract.portfolio.loanaccount.domain.Loan;
|
||||
import org.apache.fineract.portfolio.loanaccount.domain.LoanAccountDomainService;
|
||||
import org.apache.fineract.portfolio.loanaccount.domain.LoanLifecycleStateMachine;
|
||||
import org.apache.fineract.portfolio.loanaccount.domain.LoanRepaymentScheduleInstallmentRepository;
|
||||
import org.apache.fineract.portfolio.loanaccount.domain.LoanRepaymentScheduleTransactionProcessorFactory;
|
||||
import org.apache.fineract.portfolio.loanaccount.domain.LoanRepository;
|
||||
import org.apache.fineract.portfolio.loanaccount.domain.LoanRepositoryWrapper;
|
||||
import org.apache.fineract.portfolio.loanaccount.domain.LoanSummaryWrapper;
|
||||
import org.apache.fineract.portfolio.loanaccount.domain.LoanTransaction;
|
||||
import org.apache.fineract.portfolio.loanaccount.domain.LoanTransactionRelation;
|
||||
import org.apache.fineract.portfolio.loanaccount.domain.LoanTransactionRelationRepository;
|
||||
import org.apache.fineract.portfolio.loanaccount.domain.LoanTransactionRelationTypeEnum;
|
||||
import org.apache.fineract.portfolio.loanaccount.domain.LoanTransactionRepository;
|
||||
import org.apache.fineract.portfolio.loanaccount.domain.LoanTransactionType;
|
||||
import org.apache.fineract.portfolio.loanaccount.guarantor.service.GuarantorDomainService;
|
||||
import org.apache.fineract.portfolio.loanaccount.loanschedule.service.LoanScheduleHistoryWritePlatformService;
|
||||
import org.apache.fineract.portfolio.loanaccount.serialization.LoanApplicationValidator;
|
||||
import org.apache.fineract.portfolio.loanaccount.serialization.LoanTransactionValidator;
|
||||
import org.apache.fineract.portfolio.loanaccount.serialization.LoanUpdateCommandFromApiJsonDeserializer;
|
||||
import org.apache.fineract.portfolio.note.domain.NoteRepository;
|
||||
import org.apache.fineract.portfolio.paymentdetail.service.PaymentDetailWritePlatformService;
|
||||
import org.apache.fineract.portfolio.repaymentwithpostdatedchecks.domain.PostDatedChecksRepository;
|
||||
import org.apache.fineract.portfolio.repaymentwithpostdatedchecks.service.RepaymentWithPostDatedChecksAssembler;
|
||||
import org.junit.jupiter.api.Test;
|
||||
import org.junit.jupiter.api.extension.ExtendWith;
|
||||
import org.mockito.ArgumentCaptor;
|
||||
import org.mockito.InjectMocks;
|
||||
import org.mockito.Mock;
|
||||
import org.mockito.junit.jupiter.MockitoExtension;
|
||||
|
||||
@ExtendWith(MockitoExtension.class)
|
||||
class LoanWritePlatformServiceJpaRepositoryImplTest {
|
||||
|
||||
@InjectMocks
|
||||
private LoanWritePlatformServiceJpaRepositoryImpl loanWritePlatformService;
|
||||
|
||||
@Mock
|
||||
private LoanRepaymentScheduleTransactionProcessorFactory transactionProcessorFactory;
|
||||
@Mock
|
||||
private PlatformSecurityContext context;
|
||||
@Mock
|
||||
private LoanTransactionValidator loanTransactionValidator;
|
||||
@Mock
|
||||
private LoanUpdateCommandFromApiJsonDeserializer loanUpdateCommandFromApiJsonDeserializer;
|
||||
@Mock
|
||||
private LoanRepositoryWrapper loanRepositoryWrapper;
|
||||
@Mock
|
||||
private LoanAccountDomainService loanAccountDomainService;
|
||||
@Mock
|
||||
private NoteRepository noteRepository;
|
||||
@Mock
|
||||
private LoanTransactionRepository loanTransactionRepository;
|
||||
@Mock
|
||||
private LoanTransactionRelationRepository loanTransactionRelationRepository;
|
||||
@Mock
|
||||
private LoanAssembler loanAssembler;
|
||||
@Mock
|
||||
private JournalEntryWritePlatformService journalEntryWritePlatformService;
|
||||
@Mock
|
||||
private CalendarInstanceRepository calendarInstanceRepository;
|
||||
@Mock
|
||||
private PaymentDetailWritePlatformService paymentDetailWritePlatformService;
|
||||
@Mock
|
||||
private HolidayRepositoryWrapper holidayRepository;
|
||||
@Mock
|
||||
private ConfigurationDomainService configurationDomainService;
|
||||
@Mock
|
||||
private WorkingDaysRepositoryWrapper workingDaysRepository;
|
||||
@Mock
|
||||
private AccountTransfersWritePlatformService accountTransfersWritePlatformService;
|
||||
@Mock
|
||||
private AccountTransfersReadPlatformService accountTransfersReadPlatformService;
|
||||
@Mock
|
||||
private AccountAssociationsReadPlatformService accountAssociationsReadPlatformService;
|
||||
@Mock
|
||||
private LoanReadPlatformService loanReadPlatformService;
|
||||
@Mock
|
||||
private FromJsonHelper fromApiJsonHelper;
|
||||
@Mock
|
||||
private CalendarRepository calendarRepository;
|
||||
@Mock
|
||||
private LoanScheduleHistoryWritePlatformService loanScheduleHistoryWritePlatformService;
|
||||
@Mock
|
||||
private LoanApplicationValidator loanApplicationCommandFromApiJsonHelper;
|
||||
@Mock
|
||||
private AccountAssociationsRepository accountAssociationRepository;
|
||||
@Mock
|
||||
private AccountTransferDetailRepository accountTransferDetailRepository;
|
||||
@Mock
|
||||
private BusinessEventNotifierService businessEventNotifierService;
|
||||
@Mock
|
||||
private GuarantorDomainService guarantorDomainService;
|
||||
@Mock
|
||||
private LoanUtilService loanUtilService;
|
||||
@Mock
|
||||
private LoanSummaryWrapper loanSummaryWrapper;
|
||||
@Mock
|
||||
private EntityDatatableChecksWritePlatformService entityDatatableChecksWritePlatformService;
|
||||
@Mock
|
||||
private LoanRepaymentScheduleTransactionProcessorFactory transactionProcessingStrategy;
|
||||
@Mock
|
||||
private CodeValueRepositoryWrapper codeValueRepository;
|
||||
@Mock
|
||||
private CashierTransactionDataValidator cashierTransactionDataValidator;
|
||||
@Mock
|
||||
private GLIMAccountInfoRepository glimRepository;
|
||||
@Mock
|
||||
private LoanRepository loanRepository;
|
||||
@Mock
|
||||
private RepaymentWithPostDatedChecksAssembler repaymentWithPostDatedChecksAssembler;
|
||||
@Mock
|
||||
private PostDatedChecksRepository postDatedChecksRepository;
|
||||
@Mock
|
||||
private LoanRepaymentScheduleInstallmentRepository loanRepaymentScheduleInstallmentRepository;
|
||||
@Mock
|
||||
private LoanLifecycleStateMachine loanLifecycleStateMachine;
|
||||
@Mock
|
||||
private LoanAccountLockService loanAccountLockService;
|
||||
@Mock
|
||||
private ExternalIdFactory externalIdFactory;
|
||||
@Mock
|
||||
private ReplayedTransactionBusinessEventService replayedTransactionBusinessEventService;
|
||||
@Mock
|
||||
private LoanAccrualTransactionBusinessEventService loanAccrualTransactionBusinessEventService;
|
||||
@Mock
|
||||
private ErrorHandler errorHandler;
|
||||
@Mock
|
||||
private LoanDownPaymentHandlerService loanDownPaymentHandlerService;
|
||||
@Mock
|
||||
private AccountTransferRepository accountTransferRepository;
|
||||
@Mock
|
||||
private LoanTransactionAssembler loanTransactionAssembler;
|
||||
@Mock
|
||||
private LoanAccrualsProcessingService loanAccrualsProcessingService;
|
||||
|
||||
@Test
|
||||
void givenMerchantIssuedRefundTransactionWithRelatedTransactions_whenAdjustExistingTransaction_thenRelatedTransactionsAreReversedAndEventsTriggered() {
|
||||
// Arrange
|
||||
Loan loan = mock(Loan.class);
|
||||
LoanTransaction transactionForAdjustment = mock(LoanTransaction.class);
|
||||
LoanTransaction newTransactionDetail = mock(LoanTransaction.class);
|
||||
ScheduleGeneratorDTO scheduleGeneratorDTO = mock(ScheduleGeneratorDTO.class);
|
||||
ExternalId reversalExternalId = ExternalId.generate();
|
||||
|
||||
List<Long> existingTransactionIds = new ArrayList<>();
|
||||
List<Long> existingReversedTransactionIds = new ArrayList<>();
|
||||
|
||||
// Mock transaction type
|
||||
when(transactionForAdjustment.getTypeOf()).thenReturn(LoanTransactionType.MERCHANT_ISSUED_REFUND);
|
||||
when(transactionForAdjustment.isNotRepaymentLikeType()).thenReturn(false);
|
||||
|
||||
// Mock transaction date
|
||||
when(transactionForAdjustment.getTransactionDate()).thenReturn(LocalDate.now(ZoneId.systemDefault()));
|
||||
|
||||
// Mock transaction ID to prevent NullPointerException
|
||||
when(transactionForAdjustment.getId()).thenReturn(1L);
|
||||
|
||||
// Mock loan transactions
|
||||
LoanTransaction relatedTransaction = mock(LoanTransaction.class);
|
||||
when(relatedTransaction.isNotReversed()).thenReturn(true);
|
||||
|
||||
LoanTransactionRelation transactionRelation = mock(LoanTransactionRelation.class);
|
||||
when(transactionRelation.getRelationType()).thenReturn(LoanTransactionRelationTypeEnum.RELATED);
|
||||
when(transactionRelation.getToTransaction()).thenReturn(transactionForAdjustment);
|
||||
|
||||
Set<LoanTransactionRelation> transactionRelations = new HashSet<>();
|
||||
transactionRelations.add(transactionRelation);
|
||||
|
||||
when(relatedTransaction.getLoanTransactionRelations()).thenReturn(transactionRelations);
|
||||
|
||||
List<LoanTransaction> loanTransactions = Arrays.asList(transactionForAdjustment, relatedTransaction);
|
||||
when(loan.getLoanTransactions()).thenReturn(loanTransactions);
|
||||
|
||||
// Mock methods called inside adjustExistingTransaction
|
||||
when(loan.findExistingTransactionIds()).thenReturn(Collections.emptyList());
|
||||
when(loan.findExistingReversedTransactionIds()).thenReturn(Collections.emptyList());
|
||||
doNothing().when(loan).validateActivityNotBeforeClientOrGroupTransferDate(any(), any());
|
||||
when(loan.isClosedWrittenOff()).thenReturn(false);
|
||||
when(loan.isClosedObligationsMet()).thenReturn(false);
|
||||
when(loan.isClosedWithOutstandingAmountMarkedForReschedule()).thenReturn(false);
|
||||
when(newTransactionDetail.isRepaymentLikeType()).thenReturn(true);
|
||||
|
||||
// Act
|
||||
loanWritePlatformService.adjustExistingTransaction(loan, newTransactionDetail, loanLifecycleStateMachine, transactionForAdjustment,
|
||||
existingTransactionIds, existingReversedTransactionIds, scheduleGeneratorDTO, reversalExternalId);
|
||||
|
||||
// Assert
|
||||
// Verify that related transaction is reversed and event is triggered
|
||||
verify(relatedTransaction).reverse();
|
||||
verify(relatedTransaction).manuallyAdjustedOrReversed();
|
||||
|
||||
ArgumentCaptor<LoanAdjustTransactionBusinessEvent> eventCaptor = ArgumentCaptor.forClass(LoanAdjustTransactionBusinessEvent.class);
|
||||
verify(businessEventNotifierService).notifyPostBusinessEvent(eventCaptor.capture());
|
||||
|
||||
LoanAdjustTransactionBusinessEvent event = eventCaptor.getValue();
|
||||
assertEquals(relatedTransaction, event.get().getTransactionToAdjust());
|
||||
}
|
||||
|
||||
@Test
|
||||
void givenNonMerchantIssuedRefundTransaction_whenAdjustExistingTransaction_thenNoRelatedTransactionsReversed() {
|
||||
// Arrange
|
||||
Loan loan = mock(Loan.class);
|
||||
LoanTransaction transactionForAdjustment = mock(LoanTransaction.class);
|
||||
LoanTransaction newTransactionDetail = mock(LoanTransaction.class);
|
||||
ScheduleGeneratorDTO scheduleGeneratorDTO = mock(ScheduleGeneratorDTO.class);
|
||||
ExternalId reversalExternalId = ExternalId.generate();
|
||||
|
||||
List<Long> existingTransactionIds = new ArrayList<>();
|
||||
List<Long> existingReversedTransactionIds = new ArrayList<>();
|
||||
|
||||
// Mock transaction type
|
||||
when(transactionForAdjustment.getTypeOf()).thenReturn(LoanTransactionType.REPAYMENT);
|
||||
when(transactionForAdjustment.isNotRepaymentLikeType()).thenReturn(false);
|
||||
|
||||
// Mock transaction date
|
||||
when(transactionForAdjustment.getTransactionDate()).thenReturn(LocalDate.now(ZoneId.systemDefault()));
|
||||
|
||||
// Mock loan transactions
|
||||
LoanTransaction unrelatedTransaction = mock(LoanTransaction.class);
|
||||
|
||||
// Mock methods called inside adjustExistingTransaction
|
||||
when(loan.findExistingTransactionIds()).thenReturn(Collections.emptyList());
|
||||
when(loan.findExistingReversedTransactionIds()).thenReturn(Collections.emptyList());
|
||||
doNothing().when(loan).validateActivityNotBeforeClientOrGroupTransferDate(any(), any());
|
||||
when(loan.isClosedWrittenOff()).thenReturn(false);
|
||||
when(loan.isClosedObligationsMet()).thenReturn(false);
|
||||
when(loan.isClosedWithOutstandingAmountMarkedForReschedule()).thenReturn(false);
|
||||
when(newTransactionDetail.isRepaymentLikeType()).thenReturn(true);
|
||||
|
||||
// Act
|
||||
loanWritePlatformService.adjustExistingTransaction(loan, newTransactionDetail, loanLifecycleStateMachine, transactionForAdjustment,
|
||||
existingTransactionIds, existingReversedTransactionIds, scheduleGeneratorDTO, reversalExternalId);
|
||||
|
||||
// Assert
|
||||
// Verify that no related transactions are reversed
|
||||
verify(unrelatedTransaction, never()).reverse();
|
||||
verify(unrelatedTransaction, never()).manuallyAdjustedOrReversed();
|
||||
verify(businessEventNotifierService, never()).notifyPostBusinessEvent(any(LoanAdjustTransactionBusinessEvent.class));
|
||||
}
|
||||
|
||||
}
|
||||
Reference in New Issue
Block a user