From 073ad2a43101ccc8831ebca0283f2c82c52ed233 Mon Sep 17 00:00:00 2001 From: Adam Saghy Date: Tue, 31 Jan 2023 10:31:53 +0100 Subject: [PATCH] FINERACT-1865: Fix transaction persistence issues during reverse-replay --- .../portfolio/loanaccount/domain/Loan.java | 6 - .../domain/LoanAccountDomainServiceJpa.java | 7 - ...heduleRequestWritePlatformServiceImpl.java | 4 - .../LoanChargeWritePlatformServiceImpl.java | 12 -- ...WritePlatformServiceJpaRepositoryImpl.java | 10 -- .../ClientLoanIntegrationTest.java | 137 ++++++++++++++++++ 6 files changed, 137 insertions(+), 39 deletions(-) diff --git a/fineract-provider/src/main/java/org/apache/fineract/portfolio/loanaccount/domain/Loan.java b/fineract-provider/src/main/java/org/apache/fineract/portfolio/loanaccount/domain/Loan.java index 8997c8b78..bfe7e7bf4 100644 --- a/fineract-provider/src/main/java/org/apache/fineract/portfolio/loanaccount/domain/Loan.java +++ b/fineract-provider/src/main/java/org/apache/fineract/portfolio/loanaccount/domain/Loan.java @@ -704,7 +704,6 @@ public class Loan extends AbstractAuditableWithUTCDateTimeCustom { } this.loanTransactions.addAll(changedTransactionDetail.getNewTransactionMappings().values()); updateLoanSummaryDerivedFields(); - this.loanTransactions.removeAll(changedTransactionDetail.getNewTransactionMappings().values()); return changedTransactionDetail; } @@ -3326,9 +3325,6 @@ public class Loan extends AbstractAuditableWithUTCDateTimeCustom { } } - if (changedTransactionDetail != null) { - this.loanTransactions.removeAll(changedTransactionDetail.getNewTransactionMappings().values()); - } return changedTransactionDetail; } @@ -5391,8 +5387,6 @@ public class Loan extends AbstractAuditableWithUTCDateTimeCustom { this.loanTransactions.addAll(changedTransactionDetail.getNewTransactionMappings().values()); updateLoanSummaryDerivedFields(); - this.loanTransactions.removeAll(changedTransactionDetail.getNewTransactionMappings().values()); - return changedTransactionDetail; } diff --git a/fineract-provider/src/main/java/org/apache/fineract/portfolio/loanaccount/domain/LoanAccountDomainServiceJpa.java b/fineract-provider/src/main/java/org/apache/fineract/portfolio/loanaccount/domain/LoanAccountDomainServiceJpa.java index a66cdfc83..114040a0c 100644 --- a/fineract-provider/src/main/java/org/apache/fineract/portfolio/loanaccount/domain/LoanAccountDomainServiceJpa.java +++ b/fineract-provider/src/main/java/org/apache/fineract/portfolio/loanaccount/domain/LoanAccountDomainServiceJpa.java @@ -207,10 +207,6 @@ public class LoanAccountDomainServiceJpa implements LoanAccountDomainService { ***/ if (changedTransactionDetail != null) { for (Map.Entry mapEntry : changedTransactionDetail.getNewTransactionMappings().entrySet()) { - - loanTransactionRepository.save(mapEntry.getValue()); - // update loan with references to the newly created transactions - loan.addLoanTransaction(mapEntry.getValue()); updateLoanTransaction(mapEntry.getKey(), mapEntry.getValue()); } // Trigger transaction replayed event @@ -783,9 +779,6 @@ public class LoanAccountDomainServiceJpa implements LoanAccountDomainService { if (changedTransactionDetail != null) { for (Map.Entry mapEntry : changedTransactionDetail.getNewTransactionMappings().entrySet()) { - loanTransactionRepository.save(mapEntry.getValue()); - // update loan with references to the newly created transactions - loan.getLoanTransactions().add(mapEntry.getValue()); updateLoanTransaction(mapEntry.getKey(), mapEntry.getValue()); } // Trigger transaction replayed event diff --git a/fineract-provider/src/main/java/org/apache/fineract/portfolio/loanaccount/rescheduleloan/service/LoanRescheduleRequestWritePlatformServiceImpl.java b/fineract-provider/src/main/java/org/apache/fineract/portfolio/loanaccount/rescheduleloan/service/LoanRescheduleRequestWritePlatformServiceImpl.java index 3c3a62e7e..4da3fd478 100644 --- a/fineract-provider/src/main/java/org/apache/fineract/portfolio/loanaccount/rescheduleloan/service/LoanRescheduleRequestWritePlatformServiceImpl.java +++ b/fineract-provider/src/main/java/org/apache/fineract/portfolio/loanaccount/rescheduleloan/service/LoanRescheduleRequestWritePlatformServiceImpl.java @@ -445,10 +445,6 @@ public class LoanRescheduleRequestWritePlatformServiceImpl implements LoanResche if (changedTransactionDetail != null) { for (final Map.Entry mapEntry : changedTransactionDetail.getNewTransactionMappings().entrySet()) { - this.loanTransactionRepository.save(mapEntry.getValue()); - // update loan with references to the newly created - // transactions - loan.addLoanTransaction(mapEntry.getValue()); this.accountTransfersWritePlatformService.updateLoanTransaction(mapEntry.getKey(), mapEntry.getValue()); } // Trigger transaction replayed event diff --git a/fineract-provider/src/main/java/org/apache/fineract/portfolio/loanaccount/service/LoanChargeWritePlatformServiceImpl.java b/fineract-provider/src/main/java/org/apache/fineract/portfolio/loanaccount/service/LoanChargeWritePlatformServiceImpl.java index 541d7d37f..493ec971d 100644 --- a/fineract-provider/src/main/java/org/apache/fineract/portfolio/loanaccount/service/LoanChargeWritePlatformServiceImpl.java +++ b/fineract-provider/src/main/java/org/apache/fineract/portfolio/loanaccount/service/LoanChargeWritePlatformServiceImpl.java @@ -239,10 +239,6 @@ public class LoanChargeWritePlatformServiceImpl implements LoanChargeWritePlatfo ChangedTransactionDetail changedTransactionDetail = loan.reprocessTransactions(); if (changedTransactionDetail != null) { for (final Map.Entry mapEntry : changedTransactionDetail.getNewTransactionMappings().entrySet()) { - this.loanTransactionRepository.save(mapEntry.getValue()); - // update loan with references to the newly created - // transactions - loan.addLoanTransaction(mapEntry.getValue()); this.accountTransfersWritePlatformService.updateLoanTransaction(mapEntry.getKey(), mapEntry.getValue()); } // Trigger transaction replayed event @@ -739,10 +735,6 @@ public class LoanChargeWritePlatformServiceImpl implements LoanChargeWritePlatfo if (changedTransactionDetail != null) { for (final Map.Entry mapEntry : changedTransactionDetail.getNewTransactionMappings() .entrySet()) { - this.loanTransactionRepository.save(mapEntry.getValue()); - // update loan with references to the newly created - // transactions - loan.addLoanTransaction(mapEntry.getValue()); this.accountTransfersWritePlatformService.updateLoanTransaction(mapEntry.getKey(), mapEntry.getValue()); } // Trigger transaction replayed event @@ -1085,10 +1077,6 @@ public class LoanChargeWritePlatformServiceImpl implements LoanChargeWritePlatfo this.loanRepositoryWrapper.save(loan); if (changedTransactionDetail != null) { for (final Map.Entry mapEntry : changedTransactionDetail.getNewTransactionMappings().entrySet()) { - this.loanTransactionRepository.save(mapEntry.getValue()); - // update loan with references to the newly created - // transactions - loan.addLoanTransaction(mapEntry.getValue()); this.accountTransfersWritePlatformService.updateLoanTransaction(mapEntry.getKey(), mapEntry.getValue()); } // Trigger transaction replayed event 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 199a24b67..afac84139 100644 --- 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 @@ -1135,9 +1135,6 @@ public class LoanWritePlatformServiceJpaRepositoryImpl implements LoanWritePlatf ***/ if (changedTransactionDetail != null) { for (final Map.Entry mapEntry : changedTransactionDetail.getNewTransactionMappings().entrySet()) { - this.loanTransactionRepository.save(mapEntry.getValue()); - // update loan with references to the newly created transactions - loan.addLoanTransaction(mapEntry.getValue()); this.accountTransfersWritePlatformService.updateLoanTransaction(mapEntry.getKey(), mapEntry.getValue()); } // Trigger transaction replayed event @@ -1370,9 +1367,6 @@ public class LoanWritePlatformServiceJpaRepositoryImpl implements LoanWritePlatf if (changedTransactionDetail != null) { for (final Map.Entry mapEntry : changedTransactionDetail.getNewTransactionMappings().entrySet()) { - this.loanTransactionRepository.save(mapEntry.getValue()); - // update loan with references to the newly created transactions - loan.addLoanTransaction(mapEntry.getValue()); this.accountTransfersWritePlatformService.updateLoanTransaction(mapEntry.getKey(), mapEntry.getValue()); } // Trigger transaction replayed event @@ -2344,10 +2338,6 @@ public class LoanWritePlatformServiceJpaRepositoryImpl implements LoanWritePlatf if (changedTransactionDetail != null) { for (final Map.Entry mapEntry : changedTransactionDetail.getNewTransactionMappings().entrySet()) { - this.loanTransactionRepository.save(mapEntry.getValue()); - // update loan with references to the newly created - // transactions - loan.addLoanTransaction(mapEntry.getValue()); this.accountTransfersWritePlatformService.updateLoanTransaction(mapEntry.getKey(), mapEntry.getValue()); } // Trigger transaction replayed event diff --git a/integration-tests/src/test/java/org/apache/fineract/integrationtests/ClientLoanIntegrationTest.java b/integration-tests/src/test/java/org/apache/fineract/integrationtests/ClientLoanIntegrationTest.java index 2d1a6ee25..c69acfd3f 100644 --- a/integration-tests/src/test/java/org/apache/fineract/integrationtests/ClientLoanIntegrationTest.java +++ b/integration-tests/src/test/java/org/apache/fineract/integrationtests/ClientLoanIntegrationTest.java @@ -7000,6 +7000,143 @@ public class ClientLoanIntegrationTest { assertEquals("Administrator", loanDetails.getTimeline().getChargedOffByLastname()); } + @Test + public void testReverseReplay() { + try { + GlobalConfigurationHelper.updateIsAutomaticExternalIdGenerationEnabled(this.requestSpec, this.responseSpec, true); + final Account assetAccount = this.accountHelper.createAssetAccount(); + final Account incomeAccount = this.accountHelper.createIncomeAccount(); + final Account expenseAccount = this.accountHelper.createExpenseAccount(); + final Account overpaymentAccount = this.accountHelper.createLiabilityAccount(); + + final Integer loanProductID = createLoanProductWithPeriodicAccrualAccountingNoInterest(assetAccount, incomeAccount, + expenseAccount, overpaymentAccount); + + final Integer clientID = ClientHelper.createClient(requestSpec, responseSpec, "01 January 2011"); + + final Integer loanID = applyForLoanApplication(clientID, loanProductID); + + HashMap loanStatusHashMap = LoanStatusChecker.getStatusOfLoan(requestSpec, responseSpec, loanID); + LoanStatusChecker.verifyLoanIsPending(loanStatusHashMap); + + loanStatusHashMap = this.loanTransactionHelper.approveLoan("02 September 2022", loanID); + LoanStatusChecker.verifyLoanIsApproved(loanStatusHashMap); + LoanStatusChecker.verifyLoanIsWaitingForDisbursal(loanStatusHashMap); + + loanStatusHashMap = this.loanTransactionHelper.disburseLoanWithNetDisbursalAmount("03 September 2022", loanID, "1000"); + LoanStatusChecker.verifyLoanIsActive(loanStatusHashMap); + + this.loanTransactionHelper.makeRepayment("04 September 2022", Float.parseFloat("500"), loanID); + this.loanTransactionHelper.makeRepayment("05 September 2022", Float.parseFloat("10"), loanID); + this.loanTransactionHelper.makeRepayment("06 September 2022", Float.parseFloat("400"), loanID); + this.loanTransactionHelper.makeRepayment("07 September 2022", Float.parseFloat("390"), loanID); + + GetLoansLoanIdResponse loanDetails = this.loanTransactionHelper.getLoanDetails((long) loanID); + + assertEquals(300.0, loanDetails.getTotalOverpaid()); + + assertEquals(500.0, loanDetails.getTransactions().get(1).getAmount()); + assertEquals(500.0, loanDetails.getTransactions().get(1).getPrincipalPortion()); + assertEquals(LocalDate.of(2022, 9, 4), loanDetails.getTransactions().get(1).getDate()); + + assertEquals(10.0, loanDetails.getTransactions().get(2).getAmount()); + assertEquals(10.0, loanDetails.getTransactions().get(2).getPrincipalPortion()); + assertEquals(LocalDate.of(2022, 9, 5), loanDetails.getTransactions().get(2).getDate()); + + assertEquals(400.0, loanDetails.getTransactions().get(3).getAmount()); + assertEquals(400.0, loanDetails.getTransactions().get(3).getPrincipalPortion()); + assertEquals(LocalDate.of(2022, 9, 6), loanDetails.getTransactions().get(3).getDate()); + + assertEquals(390.0, loanDetails.getTransactions().get(4).getAmount()); + assertEquals(90.0, loanDetails.getTransactions().get(4).getPrincipalPortion()); + assertEquals(300.0, loanDetails.getTransactions().get(4).getOverpaymentPortion()); + assertEquals(LocalDate.of(2022, 9, 7), loanDetails.getTransactions().get(4).getDate()); + + this.loanTransactionHelper.reverseLoanTransaction((long) loanID, loanDetails.getTransactions().get(2).getId(), + new PostLoansLoanIdTransactionsTransactionIdRequest().dateFormat("dd MMMM yyyy").transactionDate("05 September 2022") + .transactionAmount(0.0).locale("en")); + + loanDetails = this.loanTransactionHelper.getLoanDetails((long) loanID); + + assertEquals(290.0, loanDetails.getTotalOverpaid()); + + assertEquals(500.0, loanDetails.getTransactions().get(1).getAmount()); + assertEquals(500.0, loanDetails.getTransactions().get(1).getPrincipalPortion()); + assertEquals(LocalDate.of(2022, 9, 4), loanDetails.getTransactions().get(1).getDate()); + + assertEquals(10.0, loanDetails.getTransactions().get(2).getAmount()); + assertEquals(10.0, loanDetails.getTransactions().get(2).getPrincipalPortion()); + assertEquals(LocalDate.of(2022, 9, 5), loanDetails.getTransactions().get(2).getDate()); + assertTrue(loanDetails.getTransactions().get(2).getManuallyReversed()); + + assertEquals(400.0, loanDetails.getTransactions().get(3).getAmount()); + assertEquals(400.0, loanDetails.getTransactions().get(3).getPrincipalPortion()); + assertEquals(LocalDate.of(2022, 9, 6), loanDetails.getTransactions().get(3).getDate()); + + assertEquals(390.0, loanDetails.getTransactions().get(4).getAmount()); + assertEquals(100.0, loanDetails.getTransactions().get(4).getPrincipalPortion()); + assertEquals(290.0, loanDetails.getTransactions().get(4).getOverpaymentPortion()); + assertEquals(LocalDate.of(2022, 9, 7), loanDetails.getTransactions().get(4).getDate()); + + this.loanTransactionHelper.reverseLoanTransaction((long) loanID, loanDetails.getTransactions().get(1).getId(), + new PostLoansLoanIdTransactionsTransactionIdRequest().dateFormat("dd MMMM yyyy").transactionDate("05 September 2022") + .transactionAmount(0.0).locale("en")); + + loanDetails = this.loanTransactionHelper.getLoanDetails((long) loanID); + + assertEquals(210.0, loanDetails.getSummary().getTotalOutstanding()); + + assertEquals(500.0, loanDetails.getTransactions().get(1).getAmount()); + assertEquals(500.0, loanDetails.getTransactions().get(1).getPrincipalPortion()); + assertEquals(LocalDate.of(2022, 9, 4), loanDetails.getTransactions().get(1).getDate()); + assertTrue(loanDetails.getTransactions().get(2).getManuallyReversed()); + + assertEquals(10.0, loanDetails.getTransactions().get(2).getAmount()); + assertEquals(10.0, loanDetails.getTransactions().get(2).getPrincipalPortion()); + assertEquals(LocalDate.of(2022, 9, 5), loanDetails.getTransactions().get(2).getDate()); + assertTrue(loanDetails.getTransactions().get(2).getManuallyReversed()); + + assertEquals(400.0, loanDetails.getTransactions().get(3).getAmount()); + assertEquals(400.0, loanDetails.getTransactions().get(3).getPrincipalPortion()); + assertEquals(LocalDate.of(2022, 9, 6), loanDetails.getTransactions().get(3).getDate()); + + assertEquals(390.0, loanDetails.getTransactions().get(4).getAmount()); + assertEquals(390.0, loanDetails.getTransactions().get(4).getPrincipalPortion()); + assertEquals(LocalDate.of(2022, 9, 7), loanDetails.getTransactions().get(4).getDate()); + + this.loanTransactionHelper.makeRepayment("04 September 2022", Float.parseFloat("500"), loanID); + + loanDetails = this.loanTransactionHelper.getLoanDetails((long) loanID); + + assertEquals(290.0, loanDetails.getTotalOverpaid()); + + assertEquals(500.0, loanDetails.getTransactions().get(1).getAmount()); + assertEquals(500.0, loanDetails.getTransactions().get(1).getPrincipalPortion()); + assertEquals(LocalDate.of(2022, 9, 4), loanDetails.getTransactions().get(1).getDate()); + assertTrue(loanDetails.getTransactions().get(1).getManuallyReversed()); + + assertEquals(500.0, loanDetails.getTransactions().get(2).getAmount()); + assertEquals(500.0, loanDetails.getTransactions().get(2).getPrincipalPortion()); + assertEquals(LocalDate.of(2022, 9, 4), loanDetails.getTransactions().get(2).getDate()); + + assertEquals(10.0, loanDetails.getTransactions().get(3).getAmount()); + assertEquals(10.0, loanDetails.getTransactions().get(3).getPrincipalPortion()); + assertEquals(LocalDate.of(2022, 9, 5), loanDetails.getTransactions().get(3).getDate()); + assertTrue(loanDetails.getTransactions().get(3).getManuallyReversed()); + + assertEquals(400.0, loanDetails.getTransactions().get(4).getAmount()); + assertEquals(400.0, loanDetails.getTransactions().get(4).getPrincipalPortion()); + assertEquals(LocalDate.of(2022, 9, 6), loanDetails.getTransactions().get(4).getDate()); + + assertEquals(390.0, loanDetails.getTransactions().get(5).getAmount()); + assertEquals(100.0, loanDetails.getTransactions().get(5).getPrincipalPortion()); + assertEquals(290.0, loanDetails.getTransactions().get(5).getOverpaymentPortion()); + assertEquals(LocalDate.of(2022, 9, 7), loanDetails.getTransactions().get(5).getDate()); + } finally { + GlobalConfigurationHelper.updateIsAutomaticExternalIdGenerationEnabled(this.requestSpec, this.responseSpec, false); + } + } + private Integer applyForLoanApplication(final Integer clientID, final Integer loanProductID) { LOG.info("--------------------------------APPLYING FOR LOAN APPLICATION--------------------------------"); final String loanApplicationJSON = new LoanApplicationTestBuilder().withPrincipal("1000").withLoanTermFrequency("1")