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 802608512..9798cbf8e 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.AccessLevel; 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 abstract class AbstractAuditableWithUTCDateTimeCustom getLastModifiedBy() { @@ -97,9 +91,4 @@ public abstract class AbstractAuditableWithUTCDateTimeCustom 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 10e596954..c7cc68239 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.format.DateTimeParseException; 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 @@ public final class DateUtils { } 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 a932ceaeb..b09642327 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 class CalendarHistoryDataWrapper { @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 6be831409..66b8ac830 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 3b70bc6f9..81fe59167 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 945a1b56a..728beb1f3 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 @@ package org.apache.fineract.portfolio.delinquency.validator; 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 class LoanDelinquencyActionData { 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 53e318fff..fdcd5b02d 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 final class DisbursementData implements Comparable { @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 54ca17930..9f14dd045 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 class LoanTransaction extends AbstractAuditableWithUTCDateTimeCustom { @@ -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; } - // equal transaction dates + result = DateUtils.compareWithNullsLast(o1.getCreatedDate(), o2.getCreatedDate()); + if (result != 0) { + return result; + } + // 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 d2d97484c..ab321b70c 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.LoanRepaymentScheduleIns 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 @@ public class AdvancedPaymentScheduleTransactionProcessor extends AbstractLoanRep 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 @@ public class AdvancedPaymentScheduleTransactionProcessor extends AbstractLoanRep 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 16469f8a0..a5335388c 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 @@ public class ChangeOperation implements Comparable { } 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 @@ public class ChangeOperation implements Comparable { @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 426957388..236d7888a 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 @@ public class ChangeOperationTest { 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 2cdf3d265..b5fac551f 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 com.fasterxml.jackson.databind.ObjectMapper; 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.SmsCampaign; 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 @@ public class SmsCampaignDomainServiceImpl implements SmsCampaignDomainService { 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 ae454ca08..e0e3430f2 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 class InternalClientInformationApiResource implements InitializingBean { 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 27d3fbfff..cd370fd64 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 class ClientCollateralManagementReadPlatformServiceImpl implements Client 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 bef3ac73b..84785072d 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 class InternalLoanInformationApiResource implements InitializingBean { 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 class InternalLoanInformationApiResource implements InitializingBean { 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 3b6e1aa3a..faeb302a6 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 @@ public class LoanWritePlatformServiceJpaRepositoryImpl implements LoanWritePlatf && 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 76b34916b..b6705759c 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 @@ public class SavingsAccountWritePlatformServiceJpaRepositoryImpl implements Savi && 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 8f340845a..57d92c78d 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.time.format.DateTimeFormatter; 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 @@ class LoanReAgingValidatorTest { 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 6f4127a1d..baa24ee4a 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.time.ZoneOffset; 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 @@ class LoanReAmortizationValidatorTest { 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 d526246c5..5d29fa6f6 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 class SavingsAccountTransactionComparator implements Comparator