FINERACT-2081: Fix inconsistent transaction processing order

This commit is contained in:
Adam Saghy
2024-11-11 12:32:21 +01:00
parent 832b84f574
commit 39da68820b
21 changed files with 74 additions and 86 deletions
@@ -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<T extends Serializa
return Optional.ofNullable(createdDate);
}
@NotNull
public OffsetDateTime getCreatedDateTime() {
return getCreatedDate().orElseGet(DateUtils::getAuditOffsetDateTime);
}
@Override
@NotNull
public Optional<Long> getLastModifiedBy() {
@@ -97,9 +91,4 @@ public abstract class AbstractAuditableWithUTCDateTimeCustom<T extends Serializa
public Optional<OffsetDateTime> getLastModifiedDate() {
return Optional.ofNullable(lastModifiedDate);
}
@NotNull
public OffsetDateTime getLastModifiedDateTime() {
return getLastModifiedDate().orElseGet(DateUtils::getAuditOffsetDateTime);
}
}
@@ -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<OffsetDateTime> first, @NotNull Optional<OffsetDateTime> 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));
}
}
@@ -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);
@@ -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"
@@ -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
@@ -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());
}
}
@@ -84,10 +84,7 @@ public final class DisbursementData implements Comparable<DisbursementData> {
@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) {
@@ -1041,22 +1041,7 @@ public class LoanTransaction extends AbstractAuditableWithUTCDateTimeCustom<Long
}
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() {
@@ -22,7 +22,8 @@ import java.util.Comparator;
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<LoanTransaction> {
@@ -30,22 +31,27 @@ public class LoanTransactionComparator implements Comparator<LoanTransaction> {
@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;
}
@@ -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<LoanTransaction> chargebacks = allTransactions.stream().filter(LoanTransaction::isChargeback).toList();
// let's figure out the original transaction for these chargebacks, and order them by ascending order
Comparator<LoanTransaction> comparator = loanTransactionDateComparator();
Comparator<LoanTransaction> comparator = LoanTransactionComparator.INSTANCE;
List<LoanTransaction> 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<LoanTransaction> 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<AllocationType, Money> chargebackAllocation) {
Money principal = chargebackAllocation.get(PRINCIPAL);
@@ -108,7 +108,7 @@ public class ChangeOperation implements Comparable<ChangeOperation> {
} 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<ChangeOperation> {
@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;
}
@@ -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);
}
@@ -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());
@@ -84,8 +84,8 @@ public class InternalClientInformationApiResource implements InitializingBean {
final Client client = clientRepositoryWrapper.findOneWithNotFoundDetection(clientId);
Map<String, Object> 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);
}
@@ -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);
}
@@ -98,8 +98,8 @@ public class InternalLoanInformationApiResource implements InitializingBean {
final Loan loan = loanRepositoryWrapper.findOneWithNotFoundDetection(loanId);
Map<String, Object> 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<String, Object> 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);
}
@@ -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);
}
}
}
@@ -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);
}
}
}
@@ -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;
}
@@ -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;
}
@@ -32,7 +32,7 @@ public class SavingsAccountTransactionComparator implements Comparator<SavingsAc
if (result != 0) {
return result;
}
result = DateUtils.compare(o1.getCreatedDateTime(), o2.getCreatedDateTime());
result = DateUtils.compareWithNullsLast(o1.getCreatedDate(), o2.getCreatedDate());
if (result != 0) {
return result;
}