FINERACT-1955: Timezone handling of Savings account

This commit is contained in:
jmarta
2023-10-24 16:00:57 +02:00
committed by Adam Saghy
parent 6cb8ae0ed3
commit 71afd6dead
74 changed files with 1584 additions and 1431 deletions
@@ -67,7 +67,7 @@ public abstract class AbstractAuditableCustom extends AbstractPersistableCustom
@Override
public Optional<LocalDateTime> getCreatedDate() {
return null == this.createdDate ? Optional.empty() : Optional.of(this.createdDate);
return Optional.ofNullable(this.createdDate);
}
@Override
@@ -87,7 +87,7 @@ public abstract class AbstractAuditableCustom extends AbstractPersistableCustom
@Override
public Optional<LocalDateTime> getLastModifiedDate() {
return null == this.lastModifiedDate ? Optional.empty() : Optional.of(this.lastModifiedDate);
return Optional.ofNullable(this.lastModifiedDate);
}
@Override
@@ -25,8 +25,10 @@ import static org.apache.fineract.infrastructure.core.domain.AuditableFieldsCons
import jakarta.persistence.Column;
import jakarta.persistence.MappedSuperclass;
import jakarta.validation.constraints.NotNull;
import java.time.OffsetDateTime;
import java.util.Optional;
import lombok.AccessLevel;
import lombok.Getter;
import lombok.NoArgsConstructor;
import lombok.Setter;
@@ -44,7 +46,7 @@ import org.springframework.data.jpa.domain.AbstractAuditable;
@MappedSuperclass
@Getter
@Setter
@NoArgsConstructor
@NoArgsConstructor(access = AccessLevel.PROTECTED)
public abstract class AbstractAuditableWithUTCDateTimeCustom extends AbstractPersistableCustom
implements Auditable<Long, Long, OffsetDateTime> {
@@ -67,33 +69,36 @@ public abstract class AbstractAuditableWithUTCDateTimeCustom extends AbstractPer
private OffsetDateTime lastModifiedDate;
@Override
@NotNull
public Optional<Long> getCreatedBy() {
return Optional.ofNullable(this.createdBy);
}
@Override
@NotNull
public Optional<OffsetDateTime> getCreatedDate() {
if (this.createdDate == null) {
return Optional.empty();
} else {
return Optional.of(this.createdDate
.withOffsetSameInstant(DateUtils.getDateTimeZoneOfTenant().getRules().getOffset(this.createdDate.toInstant())));
}
return Optional.ofNullable(createdDate);
}
@NotNull
public OffsetDateTime getCreatedDateTime() {
return getCreatedDate().orElseGet(DateUtils::getAuditOffsetDateTime);
}
@Override
@NotNull
public Optional<Long> getLastModifiedBy() {
return Optional.ofNullable(this.lastModifiedBy);
}
@Override
@NotNull
public Optional<OffsetDateTime> getLastModifiedDate() {
if (this.lastModifiedDate == null) {
return Optional.empty();
} else {
return Optional.of(this.lastModifiedDate
.withOffsetSameInstant(DateUtils.getDateTimeZoneOfTenant().getRules().getOffset(this.lastModifiedDate.toInstant())));
}
return Optional.ofNullable(lastModifiedDate);
}
@NotNull
public OffsetDateTime getLastModifiedDateTime() {
return getLastModifiedDate().orElseGet(DateUtils::getAuditOffsetDateTime);
}
}
@@ -20,6 +20,7 @@ package org.apache.fineract.infrastructure.core.service;
import static java.time.temporal.ChronoUnit.DAYS;
import jakarta.validation.constraints.NotNull;
import java.time.LocalDate;
import java.time.LocalDateTime;
import java.time.OffsetDateTime;
@@ -33,7 +34,6 @@ import java.util.Locale;
import org.apache.fineract.infrastructure.core.data.ApiParameterError;
import org.apache.fineract.infrastructure.core.domain.FineractPlatformTenant;
import org.apache.fineract.infrastructure.core.exception.PlatformApiDataValidationException;
import org.jetbrains.annotations.NotNull;
public final class DateUtils {
@@ -46,6 +46,8 @@ public final class DateUtils {
}
// DateTime
public static ZoneId getSystemZoneId() {
return ZoneId.systemDefault();
}
@@ -56,27 +58,38 @@ public final class DateUtils {
}
public static LocalDate getLocalDateOfTenant() {
final ZoneId zone = getDateTimeZoneOfTenant();
return LocalDate.now(zone);
return LocalDate.now(getDateTimeZoneOfTenant());
}
public static LocalDateTime getLocalDateTimeOfTenant() {
final ZoneId zone = getDateTimeZoneOfTenant();
return LocalDateTime.now(zone).truncatedTo(ChronoUnit.SECONDS);
return getLocalDateTimeOfTenant(null);
}
public static OffsetDateTime getOffsetDateTimeOfTenant() {
final ZoneId zone = getDateTimeZoneOfTenant();
return OffsetDateTime.now(zone).truncatedTo(ChronoUnit.SECONDS);
public static LocalDateTime getLocalDateTimeOfTenant(ChronoUnit truncate) {
LocalDateTime now = LocalDateTime.now(getDateTimeZoneOfTenant());
return truncate == null ? now : now.truncatedTo(truncate);
}
public static OffsetDateTime getOffsetDateTimeOfTenantWithMostPrecision() {
final ZoneId zone = getDateTimeZoneOfTenant();
return OffsetDateTime.now(zone);
return getOffsetDateTimeOfTenant(null);
}
public static OffsetDateTime getOffsetDateTimeOfTenant() {
return getOffsetDateTimeOfTenant(null);
}
public static OffsetDateTime getOffsetDateTimeOfTenant(ChronoUnit truncate) {
OffsetDateTime now = OffsetDateTime.now(getDateTimeZoneOfTenant());
return truncate == null ? now : now.truncatedTo(truncate);
}
public static LocalDateTime getLocalDateTimeOfSystem() {
return LocalDateTime.now(ZoneId.systemDefault()).truncatedTo(ChronoUnit.SECONDS);
return getLocalDateTimeOfSystem(null);
}
public static LocalDateTime getLocalDateTimeOfSystem(ChronoUnit truncate) {
LocalDateTime now = LocalDateTime.now(ZoneId.systemDefault());
return truncate == null ? now : now.truncatedTo(truncate);
}
public static LocalDateTime getAuditLocalDateTime() {
@@ -87,22 +100,176 @@ public final class DateUtils {
return OffsetDateTime.now(ZoneOffset.UTC);
}
public static boolean isDateInTheFuture(final LocalDate localDate) {
return localDate.isAfter(getBusinessLocalDate());
public static int compare(LocalDateTime first, LocalDateTime second) {
return compare(first, second, null);
}
public static int compare(LocalDateTime first, LocalDateTime second, ChronoUnit truncate) {
if (first == null) {
return second == null ? 0 : -1;
}
if (second == null) {
return 1;
}
return truncate == null ? first.compareTo(second) : first.truncatedTo(truncate).compareTo(second.truncatedTo(truncate));
}
public static boolean isEqual(LocalDateTime first, LocalDateTime second) {
return isEqual(first, second, null);
}
public static boolean isEqual(LocalDateTime first, LocalDateTime second, ChronoUnit truncate) {
return compare(first, second, truncate) == 0;
}
public static boolean isEqualTenantDateTime(LocalDateTime dateTime) {
return isEqualTenantDateTime(dateTime, null);
}
public static boolean isEqualTenantDateTime(LocalDateTime dateTime, ChronoUnit truncate) {
return isEqual(dateTime, getLocalDateTimeOfTenant(), truncate);
}
public static boolean isEqualSystemDateTime(LocalDateTime dateTime) {
return isEqualSystemDateTime(dateTime, null);
}
public static boolean isEqualSystemDateTime(LocalDateTime dateTime, ChronoUnit truncate) {
return isEqual(dateTime, getLocalDateTimeOfSystem(), truncate);
}
public static boolean isBefore(LocalDateTime first, LocalDateTime second) {
return isBefore(first, second, null);
}
public static boolean isBefore(LocalDateTime first, LocalDateTime second, ChronoUnit truncate) {
return compare(first, second, truncate) < 0;
}
public static boolean isBeforeTenantDateTime(LocalDateTime dateTime) {
return isBeforeTenantDateTime(dateTime, null);
}
public static boolean isBeforeTenantDateTime(LocalDateTime dateTime, ChronoUnit truncate) {
return isBefore(dateTime, getLocalDateTimeOfTenant(), truncate);
}
public static boolean isBeforeSystemDateTime(LocalDateTime dateTime) {
return isBeforeSystemDateTime(dateTime, null);
}
public static boolean isBeforeSystemDateTime(LocalDateTime dateTime, ChronoUnit truncate) {
return isBefore(dateTime, getLocalDateTimeOfSystem(), truncate);
}
public static boolean isAfter(LocalDateTime first, LocalDateTime second) {
return isAfter(first, second, null);
}
public static boolean isAfter(LocalDateTime first, LocalDateTime second, ChronoUnit truncate) {
return compare(first, second, truncate) > 0;
}
public static boolean isAfterTenantDateTime(LocalDateTime dateTime) {
return isAfterTenantDateTime(dateTime, null);
}
public static boolean isAfterTenantDateTime(LocalDateTime dateTime, ChronoUnit truncate) {
return isAfter(dateTime, getLocalDateTimeOfTenant(), truncate);
}
public static boolean isAfterSystemDateTime(LocalDateTime dateTime) {
return isAfterSystemDateTime(dateTime, null);
}
public static boolean isAfterSystemDateTime(LocalDateTime dateTime, ChronoUnit truncate) {
return isAfter(dateTime, getLocalDateTimeOfSystem(), truncate);
}
public static int compare(OffsetDateTime first, OffsetDateTime second) {
return compare(first, second, null);
}
public static int compare(OffsetDateTime first, OffsetDateTime second, ChronoUnit truncate) {
if (first == null) {
return second == null ? 0 : -1;
}
if (second == null) {
return 1;
}
return truncate == null ? first.compareTo(second) : first.truncatedTo(truncate).compareTo(second.truncatedTo(truncate));
}
public static boolean isEqual(OffsetDateTime first, OffsetDateTime second) {
return isEqual(first, second, null);
}
public static boolean isEqual(OffsetDateTime first, OffsetDateTime second, ChronoUnit truncate) {
return compare(first, second, truncate) == 0;
}
public static boolean isEqualTenantDateTime(OffsetDateTime dateTime) {
return isEqualTenantDateTime(dateTime, null);
}
public static boolean isEqualTenantDateTime(OffsetDateTime dateTime, ChronoUnit truncate) {
return isEqual(dateTime, getOffsetDateTimeOfTenant(), truncate);
}
public static boolean isBefore(OffsetDateTime first, OffsetDateTime second) {
return isBefore(first, second, null);
}
public static boolean isBefore(OffsetDateTime first, OffsetDateTime second, ChronoUnit truncate) {
return compare(first, second, truncate) < 0;
}
public static boolean isBeforeTenantDateTime(OffsetDateTime dateTime) {
return isBeforeTenantDateTime(dateTime, null);
}
public static boolean isBeforeTenantDateTime(OffsetDateTime dateTime, ChronoUnit truncate) {
return isBefore(dateTime, getOffsetDateTimeOfTenant(), truncate);
}
public static boolean isAfter(OffsetDateTime first, OffsetDateTime second) {
return isAfter(first, second, null);
}
public static boolean isAfter(OffsetDateTime first, OffsetDateTime second, ChronoUnit truncate) {
return compare(first, second, truncate) > 0;
}
public static boolean isAfterTenantDateTime(OffsetDateTime dateTime) {
return isAfterTenantDateTime(dateTime, null);
}
public static boolean isAfterTenantDateTime(OffsetDateTime dateTime, ChronoUnit truncate) {
return isAfter(dateTime, getOffsetDateTimeOfTenant(), truncate);
}
// Date
public static LocalDate getBusinessLocalDate() {
return ThreadLocalContextUtil.getBusinessDate();
}
public static long getDifferenceInDays(final LocalDate localDateBefore, final LocalDate localDateAfter) {
return DAYS.between(localDateBefore, localDateAfter);
}
public static int compareToBusinessDate(LocalDate date) {
return compare(date, getBusinessLocalDate());
}
public static boolean isEqualTenantDate(LocalDate date) {
return isEqual(date, getLocalDateOfTenant());
}
public static boolean isBeforeTenantDate(LocalDate date) {
return isBefore(date, getLocalDateOfTenant());
}
public static boolean isAfterTenantDate(LocalDate date) {
return isAfter(date, getLocalDateOfTenant());
}
public static boolean isEqualBusinessDate(LocalDate date) {
return isEqual(date, getBusinessLocalDate());
}
@@ -115,8 +282,12 @@ public final class DateUtils {
return isAfter(date, getBusinessLocalDate());
}
public static boolean isDateInTheFuture(final LocalDate localDate) {
return isAfterBusinessDate(localDate);
}
public static int compare(LocalDate first, LocalDate second) {
return first == null ? (second == null ? 0 : -1) : first.compareTo(second);
return first == null ? (second == null ? 0 : -1) : (second == null ? 1 : first.compareTo(second));
}
public static boolean isEqual(LocalDate first, LocalDate second) {
@@ -131,6 +302,12 @@ public final class DateUtils {
return first != null && (second == null || first.isAfter(second));
}
public static long getDifferenceInDays(final LocalDate localDateBefore, final LocalDate localDateAfter) {
return DAYS.between(localDateBefore, localDateAfter);
}
// Parse, format
public static LocalDate parseLocalDate(String stringDate) {
return parseLocalDate(stringDate, null);
}
@@ -259,7 +259,7 @@ public final class Group extends AbstractPersistableCustom {
}
public boolean isActivatedAfter(final LocalDate submittedOn) {
return getActivationLocalDate().isAfter(submittedOn);
return DateUtils.isAfter(getActivationDate(), submittedOn);
}
public boolean isNotActive() {
@@ -267,11 +267,7 @@ public final class Group extends AbstractPersistableCustom {
}
public boolean isActive() {
return this.status != null ? GroupingTypeStatus.fromInt(this.status).isActive() : false;
}
private boolean isDateInTheFuture(final LocalDate localDate) {
return localDate.isAfter(DateUtils.getBusinessLocalDate());
return this.status != null && GroupingTypeStatus.fromInt(this.status).isActive();
}
public boolean isNotPending() {
@@ -316,7 +312,7 @@ public final class Group extends AbstractPersistableCustom {
final String dateFormatAsInput = command.dateFormat();
final String localeAsInput = command.locale();
if (command.isChangeInLocalDateParameterNamed(GroupingTypesApiConstants.activationDateParamName, getActivationLocalDate())) {
if (command.isChangeInLocalDateParameterNamed(GroupingTypesApiConstants.activationDateParamName, getActivationDate())) {
final String valueAsInput = command.stringValueOfParameterNamed(GroupingTypesApiConstants.activationDateParamName);
actualChanges.put(GroupingTypesApiConstants.activationDateParamName, valueAsInput);
actualChanges.put(GroupingTypesApiConstants.dateFormatParamName, dateFormatAsInput);
@@ -347,7 +343,7 @@ public final class Group extends AbstractPersistableCustom {
return this.submittedOnDate;
}
public LocalDate getActivationLocalDate() {
public LocalDate getActivationDate() {
return this.activationDate;
}
@@ -494,7 +490,7 @@ public final class Group extends AbstractPersistableCustom {
}
public boolean isChildGroup() {
return this.parent == null ? false : true;
return this.parent != null;
}
@@ -503,18 +499,17 @@ public final class Group extends AbstractPersistableCustom {
}
public void close(final AppUser currentUser, final CodeValue closureReason, final LocalDate closureDate) {
if (isClosed()) {
final String errorMessage = "Group with identifier " + getId() + " is alread closed.";
throw new InvalidGroupStateTransitionException(this.groupLevel.getLevelName(), "close", "already.closed", errorMessage,
getId());
}
if (isNotPending() && getActivationLocalDate().isAfter(closureDate)) {
if (isNotPending() && DateUtils.isAfter(getActivationDate(), closureDate)) {
final String errorMessage = "The Group closure Date " + closureDate + " cannot be before the group Activation Date "
+ getActivationLocalDate() + ".";
+ getActivationDate() + ".";
throw new InvalidGroupStateTransitionException(this.groupLevel.getLevelName(), "close",
"date.cannot.before.group.actvation.date", errorMessage, closureDate, getActivationLocalDate());
"date.cannot.before.group.actvation.date", errorMessage, closureDate, getActivationDate());
}
this.closureReason = closureReason;
@@ -644,9 +639,7 @@ public final class Group extends AbstractPersistableCustom {
}
private void validateActivationDate(final List<ApiParameterError> dataValidationErrors) {
if (getSubmittedOnDate() != null && isDateInTheFuture(getSubmittedOnDate())) {
if (getSubmittedOnDate() != null && DateUtils.isDateInTheFuture(getSubmittedOnDate())) {
final String defaultUserMessage = "Submitted on date cannot be in the future.";
final String globalisationMessageCode = "error.msg.group.submittedOnDate.in.the.future";
final ApiParameterError error = ApiParameterError.parameterError(globalisationMessageCode, defaultUserMessage,
@@ -654,31 +647,26 @@ public final class Group extends AbstractPersistableCustom {
dataValidationErrors.add(error);
}
if (getActivationLocalDate() != null && getSubmittedOnDate() != null && getSubmittedOnDate().isAfter(getActivationLocalDate())) {
if (getActivationDate() != null && DateUtils.isAfter(getSubmittedOnDate(), getActivationDate())) {
final String defaultUserMessage = "Submitted on date cannot be after the activation date";
final ApiParameterError error = ApiParameterError.parameterError("error.msg.group.submittedOnDate.after.activation.date",
defaultUserMessage, GroupingTypesApiConstants.submittedOnDateParamName, this.submittedOnDate);
dataValidationErrors.add(error);
}
if (getActivationLocalDate() != null && isDateInTheFuture(getActivationLocalDate())) {
if (getActivationDate() != null && DateUtils.isDateInTheFuture(getActivationDate())) {
final String defaultUserMessage = "Activation date cannot be in the future.";
final ApiParameterError error = ApiParameterError.parameterError("error.msg.group.activationDate.in.the.future",
defaultUserMessage, GroupingTypesApiConstants.activationDateParamName, getActivationLocalDate());
defaultUserMessage, GroupingTypesApiConstants.activationDateParamName, getActivationDate());
dataValidationErrors.add(error);
}
if (getActivationLocalDate() != null) {
if (this.office.isOpeningDateAfter(getActivationLocalDate())) {
if (getActivationDate() != null) {
if (this.office.isOpeningDateAfter(getActivationDate())) {
final String defaultUserMessage = "Activation date cannot be a date before the office opening date.";
final ApiParameterError error = ApiParameterError.parameterError(
"error.msg.group.activationDate.cannot.be.before.office.activation.date", defaultUserMessage,
GroupingTypesApiConstants.activationDateParamName, getActivationLocalDate());
GroupingTypesApiConstants.activationDateParamName, getActivationDate());
dataValidationErrors.add(error);
}
}
@@ -402,7 +402,7 @@ public final class SavingsAccountTransactionData implements Serializable {
}
public boolean occursOn(final LocalDate occursOnDate) {
return getTransactionDate().isEqual(occursOnDate);
return DateUtils.isEqual(occursOnDate, getTransactionDate());
}
public EndOfDayBalance toEndOfDayBalanceBoundedBy(final Money openingBalance, final LocalDateInterval boundedBy,
@@ -416,7 +416,7 @@ public final class SavingsAccountTransactionData implements Serializable {
LocalDate balanceStartDate = getTransactionDate();
LocalDate balanceEndDate = getEndOfBalanceLocalDate();
if (boundedBy.startDate().isAfter(balanceStartDate)) {
if (DateUtils.isAfter(boundedBy.startDate(), balanceStartDate)) {
balanceStartDate = boundedBy.startDate();
final LocalDateInterval spanOfBalance = LocalDateInterval.create(balanceStartDate, balanceEndDate);
numberOfDaysOfBalance = spanOfBalance.daysInPeriodInclusiveOfEndDate();
@@ -432,7 +432,7 @@ public final class SavingsAccountTransactionData implements Serializable {
}
}
if (balanceEndDate.isAfter(boundedBy.endDate())) {
if (DateUtils.isAfter(balanceEndDate, boundedBy.endDate())) {
balanceEndDate = boundedBy.endDate();
final LocalDateInterval spanOfBalance = LocalDateInterval.create(balanceStartDate, balanceEndDate);
numberOfDaysOfBalance = spanOfBalance.daysInPeriodInclusiveOfEndDate();
@@ -479,7 +479,7 @@ public final class SavingsAccountTransactionData implements Serializable {
public void updateCumulativeBalanceAndDates(final MonetaryCurrency currency, final LocalDate endOfBalanceDate) {
// balance end date should not be before transaction date
if (endOfBalanceDate != null && endOfBalanceDate.isBefore(this.transactionDate)) {
if (endOfBalanceDate != null && DateUtils.isBefore(endOfBalanceDate, this.transactionDate)) {
this.balanceEndDate = this.transactionDate;
} else if (endOfBalanceDate != null) {
this.balanceEndDate = endOfBalanceDate;
@@ -501,7 +501,7 @@ public final class SavingsAccountTransactionData implements Serializable {
public boolean isFeeCharge() {
final SavingsAccountChargesPaidByData chargePaidBy = getSavingsAccountChargePaidBy();
return (isPayCharge() && chargePaidBy != null) ? chargePaidBy.isFeeCharge() : false;
return isPayCharge() && chargePaidBy != null && chargePaidBy.isFeeCharge();
}
public void setChargesPaidByData(final SavingsAccountChargesPaidByData savingsAccountChargesPaidByData) {
@@ -518,7 +518,7 @@ public final class SavingsAccountTransactionData implements Serializable {
public boolean isPenaltyCharge() {
final SavingsAccountChargesPaidByData chargePaidBy = getSavingsAccountChargePaidBy();
return (isPayCharge() && chargePaidBy != null) ? chargePaidBy.isPenaltyCharge() : false;
return isPayCharge() && chargePaidBy != null && chargePaidBy.isPenaltyCharge();
}
public boolean isWaiveFeeChargeAndNotReversed() {
@@ -527,7 +527,7 @@ public final class SavingsAccountTransactionData implements Serializable {
public boolean isWaiveFeeCharge() {
final SavingsAccountChargesPaidByData chargePaidBy = getSavingsAccountChargePaidBy();
return (isWaiveCharge() && chargePaidBy != null) ? chargePaidBy.isFeeCharge() : false;
return isWaiveCharge() && chargePaidBy != null && chargePaidBy.isFeeCharge();
}
public boolean isWaiveCharge() {
@@ -540,7 +540,7 @@ public final class SavingsAccountTransactionData implements Serializable {
public boolean isWaivePenaltyCharge() {
final SavingsAccountChargesPaidByData chargePaidBy = getSavingsAccountChargePaidBy();
return (isWaiveCharge() && chargePaidBy != null) ? chargePaidBy.isPenaltyCharge() : false;
return isWaiveCharge() && chargePaidBy != null && chargePaidBy.isPenaltyCharge();
}
private SavingsAccountChargesPaidByData getSavingsAccountChargePaidBy() {
@@ -572,7 +572,7 @@ public final class SavingsAccountTransactionData implements Serializable {
thisTransactionData.put("id", getId());
thisTransactionData.put("officeId", officeId);
thisTransactionData.put("type", transactionType);
thisTransactionData.put("reversed", Boolean.valueOf(isReversed()));
thisTransactionData.put("reversed", isReversed());
thisTransactionData.put("date", getTransactionDate());
thisTransactionData.put("currency", currencyData);
thisTransactionData.put("amount", this.amount);
@@ -582,10 +582,8 @@ public final class SavingsAccountTransactionData implements Serializable {
thisTransactionData.put("paymentTypeId", this.paymentDetailData.getPaymentType().getId());
}
/***
* Sending data in a map, though in savings we currently expect a transaction to always repay a single charge
* (or may repay a part of a single charge too)
***/
// Sending data in a map, though in savings we currently expect a transaction to always repay a single charge
// (or may repay a part of a single charge too)
if (!this.chargesPaidByData.isEmpty()) {
final List<Map<String, Object>> savingsChargesPaidData = new ArrayList<>();
for (final SavingsAccountChargesPaidByData chargePaidBy : this.chargesPaidByData) {
@@ -25,6 +25,7 @@ import java.util.Collection;
import java.util.Collections;
import java.util.List;
import org.apache.fineract.infrastructure.core.domain.LocalDateInterval;
import org.apache.fineract.infrastructure.core.service.DateUtils;
import org.apache.fineract.organisation.monetary.domain.MonetaryCurrency;
import org.apache.fineract.organisation.monetary.domain.Money;
import org.apache.fineract.portfolio.account.service.AccountTransfersReadPlatformService;
@@ -55,8 +56,7 @@ public final class SavingsHelper {
LocalDate periodEndDate = periodStartDate;
LocalDate actualPeriodStartDate = periodStartDate;
while (!periodStartDate.isAfter(interestPostingUpToDate) && !periodEndDate.isAfter(interestPostingUpToDate)) {
while (!DateUtils.isAfter(periodStartDate, interestPostingUpToDate) && !DateUtils.isAfter(periodEndDate, interestPostingUpToDate)) {
final LocalDate interestPostingLocalDate = determineInterestPostingPeriodEndDateFrom(periodStartDate, postingPeriodType,
interestPostingUpToDate, financialYearBeginningMonth);
@@ -64,8 +64,7 @@ public final class SavingsHelper {
if (!postInterestAsOn.isEmpty()) {
for (LocalDate transactiondate : postInterestAsOn) {
if (periodStartDate.isBefore(transactiondate)
&& (periodEndDate.isAfter(transactiondate) || periodEndDate.isEqual(transactiondate))) {
if (DateUtils.isAfter(transactiondate, periodStartDate) && !DateUtils.isAfter(transactiondate, periodEndDate)) {
periodEndDate = transactiondate.minusDays(1);
actualPeriodStartDate = periodEndDate;
break;
@@ -75,7 +74,7 @@ public final class SavingsHelper {
postingPeriods.add(LocalDateInterval.create(periodStartDate, periodEndDate));
if (actualPeriodStartDate.isEqual(periodEndDate)) {
if (DateUtils.isEqual(actualPeriodStartDate, periodEndDate)) {
periodEndDate = actualPeriodStartDate.plusDays(1);
periodStartDate = actualPeriodStartDate.plusDays(1);
} else {
@@ -128,7 +127,7 @@ public final class SavingsHelper {
break;
case QUATERLY:
for (LocalDate quarterlyDate : quarterlyDates) {
if (quarterlyDate.isAfter(periodStartDate)) {
if (DateUtils.isAfter(quarterlyDate, periodStartDate)) {
periodEndDate = quarterlyDate;
isEndDateSet = true;
break;
@@ -141,7 +140,7 @@ public final class SavingsHelper {
break;
case BIANNUAL:
for (LocalDate biannualDate : biannualDates) {
if (biannualDate.isAfter(periodStartDate)) {
if (DateUtils.isAfter(biannualDate, periodStartDate)) {
periodEndDate = biannualDate;
isEndDateSet = true;
break;
@@ -21,6 +21,7 @@ package org.apache.fineract.portfolio.savings.domain.interest;
import java.math.BigDecimal;
import java.time.LocalDate;
import java.util.List;
import org.apache.fineract.infrastructure.core.service.DateUtils;
import org.apache.fineract.organisation.monetary.domain.MonetaryCurrency;
import org.apache.fineract.organisation.monetary.domain.Money;
@@ -59,7 +60,7 @@ public class CompoundInterestHelper {
// account and if already transfered then it includes in interest
// calculation.
if (!(postingPeriod.isInterestTransfered() || !interestTransferEnabled
|| (lockUntil != null && !postingPeriod.dateOfPostingTransaction().isAfter(lockUntil)))) {
|| (lockUntil != null && !DateUtils.isAfter(postingPeriod.dateOfPostingTransaction(), lockUntil)))) {
compoundInterestValues.setcompoundedInterest(BigDecimal.ZERO);
}
}
@@ -22,6 +22,7 @@ import java.math.BigDecimal;
import java.math.MathContext;
import java.time.LocalDate;
import org.apache.fineract.infrastructure.core.domain.LocalDateInterval;
import org.apache.fineract.infrastructure.core.service.DateUtils;
import org.apache.fineract.organisation.monetary.domain.Money;
import org.apache.fineract.organisation.monetary.domain.MoneyHelper;
@@ -136,7 +137,6 @@ public class EndOfDayBalance {
* @return
*/
public EndOfDayBalance upTo(final LocalDateInterval compoundingPeriodInterval, final LocalDate upToInterestCalculationDate) {
Money startingBalance = this.openingBalance;
LocalDate balanceStartDate = this.date;
@@ -144,7 +144,7 @@ public class EndOfDayBalance {
int daysOfBalance = this.numberOfDays;
if (this.date.isBefore(compoundingPeriodInterval.startDate())) {
if (DateUtils.isBefore(this.date, compoundingPeriodInterval.startDate())) {
balanceStartDate = compoundingPeriodInterval.startDate();
startingBalance = this.endOfDayBalance;
final LocalDateInterval balancePeriodInterval = LocalDateInterval.create(balanceStartDate, oldBalanceEndDate);
@@ -152,12 +152,12 @@ public class EndOfDayBalance {
}
LocalDate balanceEndDate = balanceStartDate.plusDays(daysOfBalance - 1);
if (balanceEndDate.isAfter(compoundingPeriodInterval.endDate())) {
if (DateUtils.isAfter(balanceEndDate, compoundingPeriodInterval.endDate())) {
balanceEndDate = compoundingPeriodInterval.endDate();
final LocalDateInterval balancePeriodInterval = LocalDateInterval.create(balanceStartDate, balanceEndDate);
daysOfBalance = balancePeriodInterval.daysInPeriodInclusiveOfEndDate();
}
if (balanceEndDate.isAfter(upToInterestCalculationDate)) {
if (DateUtils.isAfter(balanceEndDate, upToInterestCalculationDate)) {
balanceEndDate = upToInterestCalculationDate;
final LocalDateInterval balancePeriodInterval = LocalDateInterval.create(balanceStartDate, balanceEndDate);
daysOfBalance = balancePeriodInterval.daysInPeriodInclusiveOfEndDate();
@@ -167,7 +167,6 @@ public class EndOfDayBalance {
}
public boolean contains(final LocalDateInterval compoundingPeriodInterval) {
final LocalDate balanceUpToDate = this.date.plusDays(this.numberOfDays - 1);
final LocalDateInterval balanceInterval = LocalDateInterval.create(this.date, balanceUpToDate);
@@ -132,7 +132,7 @@ public final class PostingPeriod {
LocalDate balanceEndDate = periodInterval.endDate();
Integer numberOfDaysOfBalance = periodInterval.daysInPeriodInclusiveOfEndDate();
if (balanceEndDate.isAfter(upToInterestCalculationDate)) {
if (DateUtils.isAfter(balanceEndDate, upToInterestCalculationDate)) {
balanceEndDate = upToInterestCalculationDate;
final LocalDateInterval spanOfBalance = LocalDateInterval.create(balanceStartDate, balanceEndDate);
numberOfDaysOfBalance = spanOfBalance.daysInPeriodInclusiveOfEndDate();
@@ -206,7 +206,7 @@ public final class PostingPeriod {
LocalDate balanceEndDate = periodInterval.endDate();
Integer numberOfDaysOfBalance = periodInterval.daysInPeriodInclusiveOfEndDate();
if (balanceEndDate.isAfter(upToInterestCalculationDate)) {
if (DateUtils.isAfter(balanceEndDate, upToInterestCalculationDate)) {
balanceEndDate = upToInterestCalculationDate;
final LocalDateInterval spanOfBalance = LocalDateInterval.create(balanceStartDate, balanceEndDate);
numberOfDaysOfBalance = spanOfBalance.daysInPeriodInclusiveOfEndDate();
@@ -328,23 +328,21 @@ public final class PostingPeriod {
compoundingPeriods.add(compoundingPeriod);
break;
case MONTHLY:
final LocalDate postingPeriodEndDate = postingPeriodInterval.endDate();
LocalDate periodStartDate = postingPeriodInterval.startDate();
LocalDate periodEndDate = periodStartDate;
while (!periodStartDate.isAfter(postingPeriodEndDate) && !periodEndDate.isAfter(postingPeriodEndDate)) {
while (!DateUtils.isAfter(periodStartDate, postingPeriodEndDate)
&& !DateUtils.isAfter(periodEndDate, postingPeriodEndDate)) {
periodEndDate = determineInterestPeriodEndDateFrom(periodStartDate, interestPeriodType, upToInterestCalculationDate,
financialYearBeginningMonth);
if (periodEndDate.isAfter(postingPeriodEndDate)) {
if (DateUtils.isAfter(periodEndDate, postingPeriodEndDate)) {
periodEndDate = postingPeriodEndDate;
}
final LocalDateInterval compoundingPeriodInterval = LocalDateInterval.create(periodStartDate, periodEndDate);
if (postingPeriodInterval.contains(compoundingPeriodInterval)) {
compoundingPeriod = MonthlyCompoundingPeriod.create(compoundingPeriodInterval, allEndOfDayBalances,
upToInterestCalculationDate);
compoundingPeriods.add(compoundingPeriod);
@@ -364,17 +362,16 @@ public final class PostingPeriod {
periodStartDate = postingPeriodInterval.startDate();
periodEndDate = periodStartDate;
while (!periodStartDate.isAfter(qPostingPeriodEndDate) && !periodEndDate.isAfter(qPostingPeriodEndDate)) {
while (!DateUtils.isAfter(periodStartDate, qPostingPeriodEndDate)
&& !DateUtils.isAfter(periodEndDate, qPostingPeriodEndDate)) {
periodEndDate = determineInterestPeriodEndDateFrom(periodStartDate, interestPeriodType, upToInterestCalculationDate,
financialYearBeginningMonth);
if (periodEndDate.isAfter(qPostingPeriodEndDate)) {
if (DateUtils.isAfter(periodEndDate, qPostingPeriodEndDate)) {
periodEndDate = qPostingPeriodEndDate;
}
final LocalDateInterval compoundingPeriodInterval = LocalDateInterval.create(periodStartDate, periodEndDate);
if (postingPeriodInterval.contains(compoundingPeriodInterval)) {
compoundingPeriod = QuarterlyCompoundingPeriod.create(compoundingPeriodInterval, allEndOfDayBalances,
upToInterestCalculationDate);
compoundingPeriods.add(compoundingPeriod);
@@ -390,11 +387,11 @@ public final class PostingPeriod {
periodStartDate = postingPeriodInterval.startDate();
periodEndDate = periodStartDate;
while (!periodStartDate.isAfter(bPostingPeriodEndDate) && !periodEndDate.isAfter(bPostingPeriodEndDate)) {
while (!DateUtils.isAfter(periodStartDate, bPostingPeriodEndDate)
&& !DateUtils.isAfter(periodEndDate, bPostingPeriodEndDate)) {
periodEndDate = determineInterestPeriodEndDateFrom(periodStartDate, interestPeriodType, upToInterestCalculationDate,
financialYearBeginningMonth);
if (periodEndDate.isAfter(bPostingPeriodEndDate)) {
if (DateUtils.isAfter(periodEndDate, bPostingPeriodEndDate)) {
periodEndDate = bPostingPeriodEndDate;
}
@@ -416,11 +413,12 @@ public final class PostingPeriod {
periodStartDate = postingPeriodInterval.startDate();
periodEndDate = periodStartDate;
while (!periodStartDate.isAfter(aPostingPeriodEndDate) && !periodEndDate.isAfter(aPostingPeriodEndDate)) {
while (!DateUtils.isAfter(periodStartDate, aPostingPeriodEndDate)
&& !DateUtils.isAfter(periodEndDate, aPostingPeriodEndDate)) {
periodEndDate = determineInterestPeriodEndDateFrom(periodStartDate, interestPeriodType, upToInterestCalculationDate,
financialYearBeginningMonth);
if (periodEndDate.isAfter(aPostingPeriodEndDate)) {
if (DateUtils.isAfter(periodEndDate, aPostingPeriodEndDate)) {
periodEndDate = aPostingPeriodEndDate;
}
@@ -483,7 +481,7 @@ public final class PostingPeriod {
case ANNUAL:
periodEndDate = periodStartDate.withMonth(previousMonth);
periodEndDate = periodEndDate.with(TemporalAdjusters.lastDayOfMonth());
if (periodEndDate.isBefore(periodStartDate)) {
if (DateUtils.isBefore(periodEndDate, periodStartDate)) {
periodEndDate = periodEndDate.plusYears(1);
}
break;
@@ -23,6 +23,7 @@ import java.time.LocalDate;
import lombok.Getter;
import lombok.RequiredArgsConstructor;
import org.apache.fineract.infrastructure.core.domain.LocalDateInterval;
import org.apache.fineract.infrastructure.core.service.DateUtils;
import org.apache.fineract.organisation.monetary.domain.MonetaryCurrency;
import org.apache.fineract.organisation.monetary.domain.Money;
@@ -54,7 +55,7 @@ public class SavingsAccountTransactionDetailsForPostingPeriod {
}
public boolean occursOn(final LocalDate occursOnDate) {
return getTransactionDate().isEqual(occursOnDate);
return DateUtils.isEqual(occursOnDate, getTransactionDate());
}
public EndOfDayBalance toEndOfDayBalance(final Money openingBalance) {
@@ -92,7 +93,6 @@ public class SavingsAccountTransactionDetailsForPostingPeriod {
}
public EndOfDayBalance toEndOfDayBalanceBoundedBy(final Money openingBalance, final LocalDateInterval boundedBy) {
final MonetaryCurrency currency = openingBalance.getCurrency();
Money endOfDayBalance = openingBalance.copy();
@@ -101,7 +101,7 @@ public class SavingsAccountTransactionDetailsForPostingPeriod {
LocalDate balanceStartDate = getTransactionDate();
LocalDate balanceEndDate = getEndOfBalanceDate();
if (boundedBy.startDate().isAfter(balanceStartDate)) {
if (DateUtils.isAfter(boundedBy.startDate(), balanceStartDate)) {
balanceStartDate = boundedBy.startDate();
final LocalDateInterval spanOfBalance = LocalDateInterval.create(balanceStartDate, balanceEndDate);
numberOfDaysOfBalance = spanOfBalance.daysInPeriodInclusiveOfEndDate();
@@ -121,7 +121,7 @@ public class SavingsAccountTransactionDetailsForPostingPeriod {
}
}
if (balanceEndDate.isAfter(boundedBy.endDate())) {
if (DateUtils.isAfter(balanceEndDate, boundedBy.endDate())) {
balanceEndDate = boundedBy.endDate();
final LocalDateInterval spanOfBalance = LocalDateInterval.create(balanceStartDate, balanceEndDate);
numberOfDaysOfBalance = spanOfBalance.daysInPeriodInclusiveOfEndDate();