From 39da68820b8758c8f488f262198593dbae9a0287 Mon Sep 17 00:00:00 2001 From: Adam Saghy Date: Mon, 11 Nov 2024 10:28:12 +0100 Subject: [PATCH] FINERACT-2081: Fix inconsistent transaction processing order --- ...bstractAuditableWithUTCDateTimeCustom.java | 11 ---------- .../core/service/DateUtils.java | 20 +++++++++++++++++ .../data/CalendarHistoryDataWrapper.java | 2 +- .../resources/features/EMICalculation.feature | 16 +++++++------- .../resources/features/LoanRepayment.feature | 2 -- .../validator/LoanDelinquencyActionData.java | 5 +++-- .../loanaccount/data/DisbursementData.java | 5 +---- .../loanaccount/domain/LoanTransaction.java | 17 +------------- .../domain/LoanTransactionComparator.java | 22 ++++++++++++------- ...edPaymentScheduleTransactionProcessor.java | 16 ++------------ .../impl/ChangeOperation.java | 8 +++---- .../impl/ChangeOperationTest.java | 2 +- .../service/SmsCampaignDomainServiceImpl.java | 7 ++++-- .../InternalClientInformationApiResource.java | 4 ++-- ...eralManagementReadPlatformServiceImpl.java | 2 +- .../InternalLoanInformationApiResource.java | 8 +++---- ...WritePlatformServiceJpaRepositoryImpl.java | 3 +-- ...WritePlatformServiceJpaRepositoryImpl.java | 2 +- .../reaging/LoanReAgingValidatorTest.java | 3 ++- .../LoanReAmortizationValidatorTest.java | 3 ++- .../SavingsAccountTransactionComparator.java | 2 +- 21 files changed, 74 insertions(+), 86 deletions(-) diff --git a/fineract-core/src/main/java/org/apache/fineract/infrastructure/core/domain/AbstractAuditableWithUTCDateTimeCustom.java b/fineract-core/src/main/java/org/apache/fineract/infrastructure/core/domain/AbstractAuditableWithUTCDateTimeCustom.java index 802608512c8..9798cbf8eae 100644 --- a/fineract-core/src/main/java/org/apache/fineract/infrastructure/core/domain/AbstractAuditableWithUTCDateTimeCustom.java +++ b/fineract-core/src/main/java/org/apache/fineract/infrastructure/core/domain/AbstractAuditableWithUTCDateTimeCustom.java @@ -33,7 +33,6 @@ import lombok.Getter; import lombok.NoArgsConstructor; import lombok.Setter; -import org.apache.fineract.infrastructure.core.service.DateUtils; import org.springframework.data.domain.Auditable; import org.springframework.data.jpa.domain.AbstractAuditable; @@ -81,11 +80,6 @@ public Optional getCreatedDate() { return Optional.ofNullable(createdDate); } - @NotNull - public OffsetDateTime getCreatedDateTime() { - return getCreatedDate().orElseGet(DateUtils::getAuditOffsetDateTime); - } - @Override @NotNull public Optional getLastModifiedBy() { @@ -97,9 +91,4 @@ public Optional getLastModifiedBy() { public Optional getLastModifiedDate() { return Optional.ofNullable(lastModifiedDate); } - - @NotNull - public OffsetDateTime getLastModifiedDateTime() { - return getLastModifiedDate().orElseGet(DateUtils::getAuditOffsetDateTime); - } } diff --git a/fineract-core/src/main/java/org/apache/fineract/infrastructure/core/service/DateUtils.java b/fineract-core/src/main/java/org/apache/fineract/infrastructure/core/service/DateUtils.java index 10e596954c4..c7cc68239f0 100644 --- a/fineract-core/src/main/java/org/apache/fineract/infrastructure/core/service/DateUtils.java +++ b/fineract-core/src/main/java/org/apache/fineract/infrastructure/core/service/DateUtils.java @@ -31,6 +31,7 @@ import java.time.temporal.ChronoUnit; import java.util.List; import java.util.Locale; +import java.util.Optional; import org.apache.fineract.infrastructure.core.data.ApiParameterError; import org.apache.fineract.infrastructure.core.domain.FineractPlatformTenant; import org.apache.fineract.infrastructure.core.exception.PlatformApiDataValidationException; @@ -425,4 +426,23 @@ private static DateTimeFormatter getDateTimeFormatter(String format, Locale loca } return formatter; } + + /** + * Comparing dates. Null will be considered as last elements + * + * @param first + * @param second + * @return + */ + public static int compareWithNullsLast(LocalDate first, LocalDate second) { + return first == null ? (second == null ? 0 : 1) : (second == null ? -1 : first.compareTo(second)); + } + + public static int compareWithNullsLast(@NotNull Optional first, @NotNull Optional second) { + return DateUtils.compareWithNullsLast(first.orElse(null), second.orElse(null)); + } + + public static int compareWithNullsLast(OffsetDateTime first, OffsetDateTime second) { + return first == null ? (second == null ? 0 : 1) : (second == null ? -1 : first.compareTo(second)); + } } diff --git a/fineract-core/src/main/java/org/apache/fineract/portfolio/calendar/data/CalendarHistoryDataWrapper.java b/fineract-core/src/main/java/org/apache/fineract/portfolio/calendar/data/CalendarHistoryDataWrapper.java index a932ceaeb46..b0964232732 100644 --- a/fineract-core/src/main/java/org/apache/fineract/portfolio/calendar/data/CalendarHistoryDataWrapper.java +++ b/fineract-core/src/main/java/org/apache/fineract/portfolio/calendar/data/CalendarHistoryDataWrapper.java @@ -37,7 +37,7 @@ public CalendarHistoryDataWrapper(final Set calendarHistoryList @Override public int compare(CalendarHistory calendarHistory1, CalendarHistory calendarHistory2) { - return DateUtils.compare(calendarHistory1.getEndDate(), calendarHistory2.getEndDate()); + return DateUtils.compareWithNullsLast(calendarHistory1.getEndDate(), calendarHistory2.getEndDate()); } }; this.calendarHistoryList.sort(orderByDate); diff --git a/fineract-e2e-tests-runner/src/test/resources/features/EMICalculation.feature b/fineract-e2e-tests-runner/src/test/resources/features/EMICalculation.feature index 6be8314097c..66b8ac83032 100644 --- a/fineract-e2e-tests-runner/src/test/resources/features/EMICalculation.feature +++ b/fineract-e2e-tests-runner/src/test/resources/features/EMICalculation.feature @@ -3824,8 +3824,8 @@ Feature: EMI calculation and repayment schedule checks for interest bearing loan | Transaction date | Transaction Type | Amount | Principal | Interest | Fees | Penalties | Loan Balance | Reverted | Replayed | | 01 January 2024 | Disbursement | 1000.0 | 0.0 | 0.0 | 0.0 | 0.0 | 1000.0 | false | false | | 01 February 2024 | Repayment | 255.14 | 246.75 | 8.39 | 0.0 | 0.0 | 753.25 | false | false | - | 09 February 2024 | Payout Refund | 1000.0 | 743.23 | 1.63 | 0.0 | 0.0 | 10.02 | false | false | - | 09 February 2024 | Interest Refund | 10.02 | 10.02 | 0.0 | 0.0 | 0.0 | 0.0 | false | false | + | 09 February 2024 | Payout Refund | 1000.0 | 753.25 | 1.63 | 0.0 | 0.0 | 0.0 | false | false | + | 09 February 2024 | Interest Refund | 10.02 | 0.0 | 0.0 | 0.0 | 0.0 | 0.0 | false | false | When Admin sets the business date to "10 February 2024" When Admin makes Credit Balance Refund transaction on "10 February 2024" with 255.14 EUR transaction amount Then Loan Repayment schedule has 4 periods, with the following data for periods: @@ -3842,8 +3842,8 @@ Feature: EMI calculation and repayment schedule checks for interest bearing loan | Transaction date | Transaction Type | Amount | Principal | Interest | Fees | Penalties | Loan Balance | Reverted | Replayed | | 01 January 2024 | Disbursement | 1000.0 | 0.0 | 0.0 | 0.0 | 0.0 | 1000.0 | false | false | | 01 February 2024 | Repayment | 255.14 | 246.75 | 8.39 | 0.0 | 0.0 | 753.25 | false | false | - | 09 February 2024 | Payout Refund | 1000.0 | 743.23 | 1.63 | 0.0 | 0.0 | 10.02 | false | false | - | 09 February 2024 | Interest Refund | 10.02 | 10.02 | 0.0 | 0.0 | 0.0 | 0.0 | false | false | + | 09 February 2024 | Payout Refund | 1000.0 | 753.25 | 1.63 | 0.0 | 0.0 | 0.0 | false | false | + | 09 February 2024 | Interest Refund | 10.02 | 0.0 | 0.0 | 0.0 | 0.0 | 0.0 | false | false | | 10 February 2024 | Credit Balance Refund | 255.14 | 0.0 | 0.0 | 0.0 | 0.0 | 0.0 | false | false | | 10 February 2024 | Accrual | 10.02 | 0.0 | 10.02 | 0.0 | 0.0 | 0.0 | false | false | Then Loan status will be "CLOSED_OBLIGATIONS_MET" @@ -3960,8 +3960,8 @@ Feature: EMI calculation and repayment schedule checks for interest bearing loan | 01 January 2024 | Disbursement | 500.0 | 0.0 | 0.0 | 0.0 | 0.0 | 500.0 | false | false | | 07 January 2024 | Disbursement | 500.0 | 0.0 | 0.0 | 0.0 | 0.0 | 1000.0 | false | false | | 01 February 2024 | Repayment | 255.14 | 247.57 | 7.57 | 0.0 | 0.0 | 752.43 | false | false | - | 09 February 2024 | Merchant Issued Refund | 1000.0 | 743.23 | 1.63 | 0.0 | 0.0 | 9.2 | false | false | - | 09 February 2024 | Interest Refund | 9.2 | 9.2 | 0.0 | 0.0 | 0.0 | 0.0 | false | false | + | 09 February 2024 | Merchant Issued Refund | 1000.0 | 752.43 | 1.63 | 0.0 | 0.0 | 0.0 | false | false | + | 09 February 2024 | Interest Refund | 9.2 | 0.0 | 0.0 | 0.0 | 0.0 | 0.0 | false | false | When Admin sets the business date to "10 February 2024" When Admin makes Credit Balance Refund transaction on "10 February 2024" with 255.14 EUR transaction amount Then Loan Repayment schedule has 4 periods, with the following data for periods: @@ -3980,8 +3980,8 @@ Feature: EMI calculation and repayment schedule checks for interest bearing loan | 01 January 2024 | Disbursement | 500.0 | 0.0 | 0.0 | 0.0 | 0.0 | 500.0 | false | false | | 07 January 2024 | Disbursement | 500.0 | 0.0 | 0.0 | 0.0 | 0.0 | 1000.0 | false | false | | 01 February 2024 | Repayment | 255.14 | 247.57 | 7.57 | 0.0 | 0.0 | 752.43 | false | false | - | 09 February 2024 | Merchant Issued Refund | 1000.0 | 743.23 | 1.63 | 0.0 | 0.0 | 9.2 | false | false | - | 09 February 2024 | Interest Refund | 9.2 | 9.2 | 0.0 | 0.0 | 0.0 | 0.0 | false | false | + | 09 February 2024 | Merchant Issued Refund | 1000.0 | 752.43 | 1.63 | 0.0 | 0.0 | 0.0 | false | false | + | 09 February 2024 | Interest Refund | 9.2 | 0.0 | 0.0 | 0.0 | 0.0 | 0.0 | false | false | | 10 February 2024 | Credit Balance Refund | 255.14 | 0.0 | 0.0 | 0.0 | 0.0 | 0.0 | false | false | | 10 February 2024 | Accrual | 9.2 | 0.0 | 9.2 | 0.0 | 0.0 | 0.0 | false | false | Then Loan status will be "CLOSED_OBLIGATIONS_MET" diff --git a/fineract-e2e-tests-runner/src/test/resources/features/LoanRepayment.feature b/fineract-e2e-tests-runner/src/test/resources/features/LoanRepayment.feature index 3b70bc6f9d9..81fe59167a8 100644 --- a/fineract-e2e-tests-runner/src/test/resources/features/LoanRepayment.feature +++ b/fineract-e2e-tests-runner/src/test/resources/features/LoanRepayment.feature @@ -3942,8 +3942,6 @@ Feature: LoanRepayment | 24 June 2024 | Disbursement | 100.0 | 0.0 | 0.0 | 0.0 | 0.0 | 500.0 | | 10 September 2024 | Merchant Issued Refund | 200.0 | 200.0 | 0.0 | 0.0 | 0.0 | 300.0 | - # Needs to fix Merchant issued Refund - Interest refund order - @Skip Scenario: Verify the relationship for Interest Refund transaction after repayment by reverting related transaction When Admin sets the business date to "30 January 2024" When Admin creates a client with random data diff --git a/fineract-loan/src/main/java/org/apache/fineract/portfolio/delinquency/validator/LoanDelinquencyActionData.java b/fineract-loan/src/main/java/org/apache/fineract/portfolio/delinquency/validator/LoanDelinquencyActionData.java index 945a1b56a07..728beb1f3d0 100644 --- a/fineract-loan/src/main/java/org/apache/fineract/portfolio/delinquency/validator/LoanDelinquencyActionData.java +++ b/fineract-loan/src/main/java/org/apache/fineract/portfolio/delinquency/validator/LoanDelinquencyActionData.java @@ -21,6 +21,7 @@ import java.time.LocalDate; import java.time.OffsetDateTime; import lombok.Data; +import org.apache.fineract.infrastructure.core.service.DateUtils; import org.apache.fineract.portfolio.delinquency.domain.DelinquencyAction; import org.apache.fineract.portfolio.delinquency.domain.LoanDelinquencyAction; @@ -44,8 +45,8 @@ public LoanDelinquencyActionData(LoanDelinquencyAction loanDelinquencyAction) { loanDelinquencyAction.getCreatedBy().ifPresent(this::setCreatedById); loanDelinquencyAction.getLastModifiedBy().ifPresent(this::setUpdatedById); - this.createdOn = loanDelinquencyAction.getCreatedDateTime(); - this.lastModifiedOn = loanDelinquencyAction.getLastModifiedDateTime(); + this.createdOn = loanDelinquencyAction.getCreatedDate().orElse(DateUtils.getAuditOffsetDateTime()); + this.lastModifiedOn = loanDelinquencyAction.getLastModifiedDate().orElse(DateUtils.getAuditOffsetDateTime()); } } diff --git a/fineract-loan/src/main/java/org/apache/fineract/portfolio/loanaccount/data/DisbursementData.java b/fineract-loan/src/main/java/org/apache/fineract/portfolio/loanaccount/data/DisbursementData.java index 53e318fffa7..fdcd5b02df3 100644 --- a/fineract-loan/src/main/java/org/apache/fineract/portfolio/loanaccount/data/DisbursementData.java +++ b/fineract-loan/src/main/java/org/apache/fineract/portfolio/loanaccount/data/DisbursementData.java @@ -84,10 +84,7 @@ public boolean isDisbursed() { @Override public int compareTo(final DisbursementData obj) { - if (obj == null) { - return -1; - } - return DateUtils.compare(obj.expectedDisbursementDate, this.expectedDisbursementDate); + return DateUtils.compareWithNullsLast(obj.expectedDisbursementDate, this.expectedDisbursementDate); } public boolean isDueForDisbursement(LoanScheduleType loanScheduleType, final LocalDate fromDate, final LocalDate toDate) { diff --git a/fineract-loan/src/main/java/org/apache/fineract/portfolio/loanaccount/domain/LoanTransaction.java b/fineract-loan/src/main/java/org/apache/fineract/portfolio/loanaccount/domain/LoanTransaction.java index 54ca17930bb..9f14dd04529 100644 --- a/fineract-loan/src/main/java/org/apache/fineract/portfolio/loanaccount/domain/LoanTransaction.java +++ b/fineract-loan/src/main/java/org/apache/fineract/portfolio/loanaccount/domain/LoanTransaction.java @@ -1041,22 +1041,7 @@ public void setLoanReAgeParameter(LoanReAgeParameter loanReAgeParameter) { } public boolean happenedBefore(LoanTransaction loanTransaction) { - // compare transaction date, creation date and then transaction id - if (DateUtils.isBefore(getTransactionDate(), loanTransaction.getTransactionDate())) { - return true; - } - if (DateUtils.isEqual(getTransactionDate(), loanTransaction.getTransactionDate())) { - if (DateUtils.isBefore(getCreatedDateTime(), loanTransaction.getCreatedDateTime())) { - return true; - } - if (DateUtils.isEqual(getCreatedDateTime(), loanTransaction.getCreatedDateTime())) { - if (getId().compareTo(loanTransaction.getId()) < 0) { - return true; - } - } - } - - return false; + return LoanTransactionComparator.INSTANCE.compare(this, loanTransaction) < 0; } public boolean isOverPaid() { diff --git a/fineract-loan/src/main/java/org/apache/fineract/portfolio/loanaccount/domain/LoanTransactionComparator.java b/fineract-loan/src/main/java/org/apache/fineract/portfolio/loanaccount/domain/LoanTransactionComparator.java index ead9e19a6cf..a16a1f685ce 100644 --- a/fineract-loan/src/main/java/org/apache/fineract/portfolio/loanaccount/domain/LoanTransactionComparator.java +++ b/fineract-loan/src/main/java/org/apache/fineract/portfolio/loanaccount/domain/LoanTransactionComparator.java @@ -22,7 +22,8 @@ import org.apache.fineract.infrastructure.core.service.DateUtils; /** - * Sort loan transactions by transaction date, created date and transaction type placing + * Sort loan transactions by transaction date, submitted date, created date, transaction type placing, lastly compare + * ids */ public class LoanTransactionComparator implements Comparator { @@ -30,22 +31,27 @@ public class LoanTransactionComparator implements Comparator { @Override public int compare(final LoanTransaction o1, final LoanTransaction o2) { - int result = DateUtils.compare(o1.getTransactionDate(), o2.getTransactionDate()); + int result = DateUtils.compareWithNullsLast(o1.getTransactionDate(), o2.getTransactionDate()); if (result != 0) { return result; } - // For transactions bearing the same transaction date, we sort transactions based on created date (when - // available) after which sorting for waivers takes place - result = o1.getCreatedDate().isPresent() - ? (o2.getCreatedDate().isPresent() ? DateUtils.compare(o1.getCreatedDateTime(), o2.getCreatedDateTime()) : -1) - : (o2.getCreatedDate().isPresent() ? 1 : 0); + // Accrual activity as last + if (o1.isAccrualActivity() != o2.isAccrualActivity()) { + return o1.isAccrualActivity() ? 1 : -1; + } + result = DateUtils.compareWithNullsLast(o1.getSubmittedOnDate(), o2.getSubmittedOnDate()); + if (result != 0) { + return result; + } + result = DateUtils.compareWithNullsLast(o1.getCreatedDate(), o2.getCreatedDate()); if (result != 0) { return result; } - // equal transaction dates + // income posting takes priority if (o1.isIncomePosting() != o2.isIncomePosting()) { return o1.isIncomePosting() ? -1 : 1; } + // waive takes priority if (o1.isWaiver() != o2.isWaiver()) { return o1.isWaiver() ? -1 : 1; } diff --git a/fineract-progressive-loan/src/main/java/org/apache/fineract/portfolio/loanaccount/domain/transactionprocessor/impl/AdvancedPaymentScheduleTransactionProcessor.java b/fineract-progressive-loan/src/main/java/org/apache/fineract/portfolio/loanaccount/domain/transactionprocessor/impl/AdvancedPaymentScheduleTransactionProcessor.java index d2d97484c2f..ab321b70cad 100644 --- a/fineract-progressive-loan/src/main/java/org/apache/fineract/portfolio/loanaccount/domain/transactionprocessor/impl/AdvancedPaymentScheduleTransactionProcessor.java +++ b/fineract-progressive-loan/src/main/java/org/apache/fineract/portfolio/loanaccount/domain/transactionprocessor/impl/AdvancedPaymentScheduleTransactionProcessor.java @@ -74,6 +74,7 @@ import org.apache.fineract.portfolio.loanaccount.domain.LoanRepaymentScheduleProcessingWrapper; import org.apache.fineract.portfolio.loanaccount.domain.LoanTermVariations; import org.apache.fineract.portfolio.loanaccount.domain.LoanTransaction; +import org.apache.fineract.portfolio.loanaccount.domain.LoanTransactionComparator; import org.apache.fineract.portfolio.loanaccount.domain.LoanTransactionRelation; import org.apache.fineract.portfolio.loanaccount.domain.LoanTransactionRelationTypeEnum; import org.apache.fineract.portfolio.loanaccount.domain.LoanTransactionToRepaymentScheduleMapping; @@ -471,7 +472,7 @@ private Map adjustOriginalAllocationWithFormerChargebacks List chargebacks = allTransactions.stream().filter(LoanTransaction::isChargeback).toList(); // let's figure out the original transaction for these chargebacks, and order them by ascending order - Comparator comparator = loanTransactionDateComparator(); + Comparator comparator = LoanTransactionComparator.INSTANCE; List chargebacksForTheSameOriginal = chargebacks.stream() .filter(tr -> findChargebackOriginalTransaction(tr, ctx) == originalTransaction && comparator.compare(tr, chargeBackTransaction) < 0) @@ -486,19 +487,6 @@ private Map adjustOriginalAllocationWithFormerChargebacks return allocation; } - @NotNull - private Comparator loanTransactionDateComparator() { - return (tr1, tr2) -> { - if (tr1.getTransactionDate().compareTo(tr2.getTransactionDate()) != 0) { - return tr1.getTransactionDate().compareTo(tr2.getTransactionDate()); - } else if (tr1.getSubmittedOnDate().compareTo(tr2.getSubmittedOnDate()) != 0) { - return tr1.getSubmittedOnDate().compareTo(tr2.getSubmittedOnDate()); - } else { - return tr1.getCreatedDateTime().compareTo(tr2.getCreatedDateTime()); - } - }; - } - private void recognizeAmountsAfterChargeback(MonetaryCurrency currency, LocalDate localDate, LoanRepaymentScheduleInstallment installment, Map chargebackAllocation) { Money principal = chargebackAllocation.get(PRINCIPAL); diff --git a/fineract-progressive-loan/src/main/java/org/apache/fineract/portfolio/loanaccount/domain/transactionprocessor/impl/ChangeOperation.java b/fineract-progressive-loan/src/main/java/org/apache/fineract/portfolio/loanaccount/domain/transactionprocessor/impl/ChangeOperation.java index 16469f8a0d6..a5335388c48 100644 --- a/fineract-progressive-loan/src/main/java/org/apache/fineract/portfolio/loanaccount/domain/transactionprocessor/impl/ChangeOperation.java +++ b/fineract-progressive-loan/src/main/java/org/apache/fineract/portfolio/loanaccount/domain/transactionprocessor/impl/ChangeOperation.java @@ -108,7 +108,7 @@ private OffsetDateTime getCreatedDateTime() { } else if (loanCharge.isPresent() && loanCharge.get().getCreatedDate().isPresent()) { return loanCharge.get().getCreatedDate().get(); } else if (loanTransaction.isPresent()) { - return loanTransaction.get().getCreatedDateTime(); + return loanTransaction.get().getCreatedDate().orElse(null); } else { throw new RuntimeException("Either charge with createdDate or transaction created datetime should be present"); } @@ -117,15 +117,15 @@ private OffsetDateTime getCreatedDateTime() { @Override @SuppressFBWarnings(value = "EQ_COMPARETO_USE_OBJECT_EQUALS", justification = "TODO: fix this! See: https://stackoverflow.com/questions/2609037/findbugs-how-to-solve-eq-compareto-use-object-equals") public int compareTo(@NotNull ChangeOperation o) { - int datePortion = DateUtils.compare(this.getEffectiveDate(), o.getEffectiveDate()); + int datePortion = DateUtils.compareWithNullsLast(this.getEffectiveDate(), o.getEffectiveDate()); if (datePortion == 0) { final boolean isAccrual = isAccrualActivity(); if (isAccrual != o.isAccrualActivity()) { return isAccrual ? 1 : -1; } - int submittedDate = DateUtils.compare(getSubmittedOnDate(), o.getSubmittedOnDate()); + int submittedDate = DateUtils.compareWithNullsLast(getSubmittedOnDate(), o.getSubmittedOnDate()); if (submittedDate == 0) { - return DateUtils.compare(getCreatedDateTime(), o.getCreatedDateTime(), null); + return DateUtils.compareWithNullsLast(getCreatedDateTime(), o.getCreatedDateTime()); } return submittedDate; } diff --git a/fineract-progressive-loan/src/test/java/org/apache/fineract/portfolio/loanaccount/domain/transactionprocessor/impl/ChangeOperationTest.java b/fineract-progressive-loan/src/test/java/org/apache/fineract/portfolio/loanaccount/domain/transactionprocessor/impl/ChangeOperationTest.java index 4269573884f..236d7888a6e 100644 --- a/fineract-progressive-loan/src/test/java/org/apache/fineract/portfolio/loanaccount/domain/transactionprocessor/impl/ChangeOperationTest.java +++ b/fineract-progressive-loan/src/test/java/org/apache/fineract/portfolio/loanaccount/domain/transactionprocessor/impl/ChangeOperationTest.java @@ -152,7 +152,7 @@ private ChangeOperation createTransaction(String transactionDate, String submitt LoanTransaction transaction = Mockito.mock(LoanTransaction.class); Mockito.when(transaction.getSubmittedOnDate()).thenReturn(LocalDate.parse(submittedDate)); Mockito.when(transaction.getTransactionDate()).thenReturn(LocalDate.parse(transactionDate)); - Mockito.when(transaction.getCreatedDateTime()).thenReturn(OffsetDateTime.parse(creationDateTime)); + Mockito.when(transaction.getCreatedDate()).thenReturn(Optional.of(OffsetDateTime.parse(creationDateTime))); return new ChangeOperation(transaction); } diff --git a/fineract-provider/src/main/java/org/apache/fineract/infrastructure/campaigns/sms/service/SmsCampaignDomainServiceImpl.java b/fineract-provider/src/main/java/org/apache/fineract/infrastructure/campaigns/sms/service/SmsCampaignDomainServiceImpl.java index 2cdf3d2652e..b5fac551f45 100644 --- a/fineract-provider/src/main/java/org/apache/fineract/infrastructure/campaigns/sms/service/SmsCampaignDomainServiceImpl.java +++ b/fineract-provider/src/main/java/org/apache/fineract/infrastructure/campaigns/sms/service/SmsCampaignDomainServiceImpl.java @@ -24,6 +24,7 @@ import jakarta.annotation.PostConstruct; import java.io.IOException; import java.security.InvalidParameterException; +import java.time.OffsetDateTime; import java.time.format.DateTimeFormatter; import java.util.ArrayList; import java.util.Collection; @@ -40,6 +41,7 @@ import org.apache.fineract.infrastructure.campaigns.sms.domain.SmsCampaignRepository; import org.apache.fineract.infrastructure.campaigns.sms.exception.SmsRuntimeException; import org.apache.fineract.infrastructure.campaigns.sms.serialization.SmsCampaignValidator; +import org.apache.fineract.infrastructure.core.service.DateUtils; import org.apache.fineract.infrastructure.event.business.BusinessEventListener; import org.apache.fineract.infrastructure.event.business.domain.client.ClientActivateBusinessEvent; import org.apache.fineract.infrastructure.event.business.domain.client.ClientRejectBusinessEvent; @@ -330,9 +332,10 @@ private HashMap processRepaymentDataForSms(final LoanTransaction smsParams.put("loanOfficerId", -1); } + OffsetDateTime creationDate = loanTransaction.getCreatedDate().orElse(DateUtils.getAuditOffsetDateTime()); smsParams.put("repaymentAmount", loanTransaction.getAmount(loan.getCurrency())); - smsParams.put("RepaymentDate", loanTransaction.getCreatedDateTime().toLocalDate().format(dateFormatter)); - smsParams.put("RepaymentTime", loanTransaction.getCreatedDateTime().toLocalTime().format(timeFormatter)); + smsParams.put("RepaymentDate", creationDate.toLocalDate().format(dateFormatter)); + smsParams.put("RepaymentTime", creationDate.toLocalTime().format(timeFormatter)); if (loanTransaction.getPaymentDetail() != null) { smsParams.put("receiptNumber", loanTransaction.getPaymentDetail().getReceiptNumber()); diff --git a/fineract-provider/src/main/java/org/apache/fineract/portfolio/client/api/InternalClientInformationApiResource.java b/fineract-provider/src/main/java/org/apache/fineract/portfolio/client/api/InternalClientInformationApiResource.java index ae454ca0843..e0e3430f203 100644 --- a/fineract-provider/src/main/java/org/apache/fineract/portfolio/client/api/InternalClientInformationApiResource.java +++ b/fineract-provider/src/main/java/org/apache/fineract/portfolio/client/api/InternalClientInformationApiResource.java @@ -84,8 +84,8 @@ public String getClientAuditFields(@Context final UriInfo uriInfo, @PathParam("c final Client client = clientRepositoryWrapper.findOneWithNotFoundDetection(clientId); Map auditFields = new HashMap<>( - Map.of(CREATED_BY, client.getCreatedBy().orElse(null), CREATED_DATE, client.getCreatedDateTime(), LAST_MODIFIED_BY, - client.getLastModifiedBy().orElse(null), LAST_MODIFIED_DATE, client.getLastModifiedDateTime())); + Map.of(CREATED_BY, client.getCreatedBy().orElse(null), CREATED_DATE, client.getCreatedDate().orElse(null), LAST_MODIFIED_BY, + client.getLastModifiedBy().orElse(null), LAST_MODIFIED_DATE, client.getLastModifiedDate().orElse(null))); final ApiRequestJsonSerializationSettings settings = this.apiRequestParameterHelper.process(uriInfo.getQueryParameters()); return this.toApiJsonSerializer.serialize(settings, auditFields); } diff --git a/fineract-provider/src/main/java/org/apache/fineract/portfolio/collateralmanagement/service/ClientCollateralManagementReadPlatformServiceImpl.java b/fineract-provider/src/main/java/org/apache/fineract/portfolio/collateralmanagement/service/ClientCollateralManagementReadPlatformServiceImpl.java index 27d3fbfff05..cd370fd6432 100644 --- a/fineract-provider/src/main/java/org/apache/fineract/portfolio/collateralmanagement/service/ClientCollateralManagementReadPlatformServiceImpl.java +++ b/fineract-provider/src/main/java/org/apache/fineract/portfolio/collateralmanagement/service/ClientCollateralManagementReadPlatformServiceImpl.java @@ -81,7 +81,7 @@ public ClientCollateralManagementData getClientCollateralManagementData(final Lo LoanTransaction loanTransaction = this.loanTransactionRepository.findById(transactionId) .orElseThrow(() -> new LoanTransactionNotFoundException(transactionId)); LoanTransactionData loanTransactionData = LoanTransactionData.instance(loanTransaction.getLoan().getId(), - loanTransaction.getCreatedDateTime(), loanTransaction.getOutstandingLoanBalance(), + loanTransaction.getCreatedDate().orElse(null), loanTransaction.getOutstandingLoanBalance(), loanTransaction.getPrincipalPortion()); loanTransactionDataList.add(loanTransactionData); } diff --git a/fineract-provider/src/main/java/org/apache/fineract/portfolio/loanaccount/api/InternalLoanInformationApiResource.java b/fineract-provider/src/main/java/org/apache/fineract/portfolio/loanaccount/api/InternalLoanInformationApiResource.java index bef3ac73b59..84785072dc6 100644 --- a/fineract-provider/src/main/java/org/apache/fineract/portfolio/loanaccount/api/InternalLoanInformationApiResource.java +++ b/fineract-provider/src/main/java/org/apache/fineract/portfolio/loanaccount/api/InternalLoanInformationApiResource.java @@ -98,8 +98,8 @@ public String getLoanAuditFields(@Context final UriInfo uriInfo, @PathParam("loa final Loan loan = loanRepositoryWrapper.findOneWithNotFoundDetection(loanId); Map auditFields = new HashMap<>( - Map.of(CREATED_BY, loan.getCreatedBy().orElse(null), CREATED_DATE, loan.getCreatedDateTime(), LAST_MODIFIED_BY, - loan.getLastModifiedBy().orElse(null), LAST_MODIFIED_DATE, loan.getLastModifiedDateTime())); + Map.of(CREATED_BY, loan.getCreatedBy().orElse(null), CREATED_DATE, loan.getCreatedDate().orElse(null), LAST_MODIFIED_BY, + loan.getLastModifiedBy().orElse(null), LAST_MODIFIED_DATE, loan.getLastModifiedDate().orElse(null))); final ApiRequestJsonSerializationSettings settings = this.apiRequestParameterHelper.process(uriInfo.getQueryParameters()); return this.toApiJsonSerializerForMap.serialize(settings, auditFields); } @@ -119,8 +119,8 @@ public String getLoanTransactionAuditFields(@Context final UriInfo uriInfo, @Pat final LoanTransaction transaction = loanTransactionRepository.findById(transactionId).orElseThrow(); Map auditFields = new HashMap<>(Map.of(CREATED_BY, transaction.getCreatedBy().orElse(null), CREATED_DATE, - transaction.getCreatedDateTime(), LAST_MODIFIED_BY, transaction.getLastModifiedBy().orElse(null), LAST_MODIFIED_DATE, - transaction.getLastModifiedDateTime())); + transaction.getCreatedDate().orElse(null), LAST_MODIFIED_BY, transaction.getLastModifiedBy().orElse(null), + LAST_MODIFIED_DATE, transaction.getLastModifiedDate().orElse(null))); final ApiRequestJsonSerializationSettings settings = this.apiRequestParameterHelper.process(uriInfo.getQueryParameters()); return this.toApiJsonSerializerForMap.serialize(settings, auditFields); } 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 3b6e1aa3a40..faeb302a677 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 @@ -3355,8 +3355,7 @@ private void validateTransactionsForTransfer(final Loan loan, final LocalDate tr && DateUtils.isEqual(transferDate, transaction.getSubmittedOnDate())) || DateUtils.isBefore(transferDate, transaction.getTransactionDate())) { throw new GeneralPlatformDomainRuleException(TransferApiConstants.transferClientLoanException, - TransferApiConstants.transferClientLoanExceptionMessage, transaction.getCreatedDateTime().toLocalDate(), - transferDate); + TransferApiConstants.transferClientLoanExceptionMessage, transaction.getTransactionDate(), transferDate); } } } diff --git a/fineract-provider/src/main/java/org/apache/fineract/portfolio/savings/service/SavingsAccountWritePlatformServiceJpaRepositoryImpl.java b/fineract-provider/src/main/java/org/apache/fineract/portfolio/savings/service/SavingsAccountWritePlatformServiceJpaRepositoryImpl.java index 76b34916bbf..b6705759cb4 100644 --- a/fineract-provider/src/main/java/org/apache/fineract/portfolio/savings/service/SavingsAccountWritePlatformServiceJpaRepositoryImpl.java +++ b/fineract-provider/src/main/java/org/apache/fineract/portfolio/savings/service/SavingsAccountWritePlatformServiceJpaRepositoryImpl.java @@ -1898,7 +1898,7 @@ private void validateTransactionsForTransfer(final SavingsAccount savingsAccount && DateUtils.isEqual(transferDate, transaction.getSubmittedOnDate())) || DateUtils.isBefore(transferDate, transaction.getTransactionDate())) { throw new GeneralPlatformDomainRuleException(TransferApiConstants.transferClientSavingsException, - TransferApiConstants.transferClientSavingsException, transaction.getCreatedDateTime(), transferDate); + TransferApiConstants.transferClientSavingsException, transaction.getTransactionDate(), transferDate); } } } diff --git a/fineract-provider/src/test/java/org/apache/fineract/portfolio/loanaccount/service/reaging/LoanReAgingValidatorTest.java b/fineract-provider/src/test/java/org/apache/fineract/portfolio/loanaccount/service/reaging/LoanReAgingValidatorTest.java index 8f340845a5f..57d92c78d16 100644 --- a/fineract-provider/src/test/java/org/apache/fineract/portfolio/loanaccount/service/reaging/LoanReAgingValidatorTest.java +++ b/fineract-provider/src/test/java/org/apache/fineract/portfolio/loanaccount/service/reaging/LoanReAgingValidatorTest.java @@ -33,6 +33,7 @@ import java.util.HashMap; import java.util.List; import java.util.Map; +import java.util.Optional; import org.apache.commons.lang3.RandomStringUtils; import org.apache.fineract.infrastructure.businessdate.domain.BusinessDateType; import org.apache.fineract.infrastructure.core.api.JsonCommand; @@ -480,7 +481,7 @@ private JsonCommand makeJsonCommand(String json) { private LoanTransaction loanTransaction(LoanTransactionType type, LocalDate txDate, OffsetDateTime creationTime) { LoanTransaction loanTransaction = loanTransaction(type, txDate); - given(loanTransaction.getCreatedDateTime()).willReturn(creationTime); + given(loanTransaction.getCreatedDate()).willReturn(Optional.of(creationTime)); return loanTransaction; } diff --git a/fineract-provider/src/test/java/org/apache/fineract/portfolio/loanaccount/service/reamortization/LoanReAmortizationValidatorTest.java b/fineract-provider/src/test/java/org/apache/fineract/portfolio/loanaccount/service/reamortization/LoanReAmortizationValidatorTest.java index 6f4127a1d34..baa24ee4ae3 100644 --- a/fineract-provider/src/test/java/org/apache/fineract/portfolio/loanaccount/service/reamortization/LoanReAmortizationValidatorTest.java +++ b/fineract-provider/src/test/java/org/apache/fineract/portfolio/loanaccount/service/reamortization/LoanReAmortizationValidatorTest.java @@ -32,6 +32,7 @@ import java.util.HashMap; import java.util.List; import java.util.Map; +import java.util.Optional; import org.apache.commons.lang3.RandomStringUtils; import org.apache.fineract.infrastructure.businessdate.domain.BusinessDateType; import org.apache.fineract.infrastructure.core.api.JsonCommand; @@ -267,7 +268,7 @@ private JsonCommand jsonCommand(String externalId) { private LoanTransaction loanTransaction(LoanTransactionType type, LocalDate txDate, OffsetDateTime creationTime) { LoanTransaction loanTransaction = loanTransaction(type, txDate); - given(loanTransaction.getCreatedDateTime()).willReturn(creationTime); + given(loanTransaction.getCreatedDate()).willReturn(Optional.of(creationTime)); return loanTransaction; } diff --git a/fineract-savings/src/main/java/org/apache/fineract/portfolio/savings/domain/SavingsAccountTransactionComparator.java b/fineract-savings/src/main/java/org/apache/fineract/portfolio/savings/domain/SavingsAccountTransactionComparator.java index d526246c573..5d29fa6f68f 100644 --- a/fineract-savings/src/main/java/org/apache/fineract/portfolio/savings/domain/SavingsAccountTransactionComparator.java +++ b/fineract-savings/src/main/java/org/apache/fineract/portfolio/savings/domain/SavingsAccountTransactionComparator.java @@ -32,7 +32,7 @@ public int compare(final SavingsAccountTransaction o1, final SavingsAccountTrans if (result != 0) { return result; } - result = DateUtils.compare(o1.getCreatedDateTime(), o2.getCreatedDateTime()); + result = DateUtils.compareWithNullsLast(o1.getCreatedDate(), o2.getCreatedDate()); if (result != 0) { return result; }