FINERACT-1983: Date handling improvements - general

This commit is contained in:
jmarta
2023-10-25 22:41:23 +02:00
committed by Adam Saghy
parent 71afd6dead
commit e602fa6b3c
147 changed files with 797 additions and 1028 deletions
@@ -66,15 +66,14 @@ public class GLClosureWritePlatformServiceJpaRepositoryImpl implements GLClosure
final Office office = this.officeRepositoryWrapper.findOneWithNotFoundDetection(officeId);
// TODO: Get Tenant specific date
// ensure closure date is not in the future
final LocalDate todaysDate = DateUtils.getBusinessLocalDate();
final LocalDate closureDate = command.localDateValueOfParameterNamed(GLClosureJsonInputParams.CLOSING_DATE.getValue());
if (closureDate.isAfter(todaysDate)) {
if (DateUtils.isDateInTheFuture(closureDate)) {
throw new GLClosureInvalidException(GlClosureInvalidReason.FUTURE_DATE, closureDate);
}
// shouldn't be before an existing accounting closure
final GLClosure latestGLClosure = this.glClosureRepository.getLatestGLClosureByBranch(officeId);
if (latestGLClosure != null) {
if (latestGLClosure.getClosingDate().isAfter(closureDate)) {
if (DateUtils.isAfter(latestGLClosure.getClosingDate(), closureDate)) {
throw new GLClosureInvalidException(GlClosureInvalidReason.ACCOUNTING_CLOSED, latestGLClosure.getClosingDate());
}
}
@@ -122,7 +121,7 @@ public class GLClosureWritePlatformServiceJpaRepositoryImpl implements GLClosure
**/
final LocalDate closureDate = glClosure.getClosingDate();
final GLClosure latestGLClosure = this.glClosureRepository.getLatestGLClosureByBranch(glClosure.getOffice().getId());
if (latestGLClosure.getClosingDate().isAfter(closureDate)) {
if (DateUtils.isAfter(latestGLClosure.getClosingDate(), closureDate)) {
throw new GLClosureInvalidDeleteException(latestGLClosure.getOffice().getId(), latestGLClosure.getOffice().getName(),
latestGLClosure.getClosingDate());
}
@@ -30,6 +30,7 @@ import lombok.NoArgsConstructor;
import lombok.Setter;
import lombok.experimental.Accessors;
import org.apache.fineract.infrastructure.core.domain.AbstractPersistableCustom;
import org.apache.fineract.infrastructure.core.service.DateUtils;
@Entity
@Table(name = "m_trial_balance")
@@ -70,9 +71,8 @@ public class TrialBalance extends AbstractPersistableCustom {
}
TrialBalance other = (TrialBalance) obj;
return Objects.equals(other.officeId, officeId) && Objects.equals(other.glAccountId, glAccountId)
&& Objects.equals(other.amount, amount) && other.entryDate.compareTo(entryDate) == 0 ? Boolean.TRUE
: Boolean.FALSE && other.transactionDate.compareTo(transactionDate) == 0 ? Boolean.TRUE
: Boolean.FALSE && Objects.equals(other.closingBalance, closingBalance);
&& Objects.equals(other.amount, amount) && DateUtils.isEqual(other.entryDate, entryDate)
&& DateUtils.isEqual(other.transactionDate, transactionDate) && Objects.equals(other.closingBalance, closingBalance);
}
@Override
@@ -133,7 +133,7 @@ public class CommandSource extends AbstractPersistableCustom {
this.subResourceId = subResourceId;
this.commandAsJson = commandSerializedAsJson;
this.maker = maker;
this.madeOnDate = DateUtils.getOffsetDateTimeOfTenantWithMostPrecision();
this.madeOnDate = DateUtils.getAuditOffsetDateTime();
this.status = status;
this.idempotencyKey = idempotencyKey;
}
@@ -314,13 +314,13 @@ public class CommandSource extends AbstractPersistableCustom {
public void markAsChecked(final AppUser checker) {
this.checker = checker;
this.checkedOnDate = DateUtils.getOffsetDateTimeOfTenantWithMostPrecision();
this.checkedOnDate = DateUtils.getAuditOffsetDateTime();
this.status = CommandProcessingResultType.PROCESSED.getValue();
}
public void markAsRejected(final AppUser checker) {
this.checker = checker;
this.checkedOnDate = DateUtils.getOffsetDateTimeOfTenantWithMostPrecision();
this.checkedOnDate = DateUtils.getAuditOffsetDateTime();
this.status = CommandProcessingResultType.REJECTED.getValue();
}
@@ -43,7 +43,7 @@ public class PurgeProcessedCommandsTasklet implements Tasklet {
public RepeatStatus execute(StepContribution contribution, ChunkContext chunkContext) {
try {
Long numberOfDaysForPurgeCriteria = configurationDomainService.retrieveProcessedCommandsPurgeDaysCriteria();
OffsetDateTime dateForPurgeCriteria = DateUtils.getOffsetDateTimeOfTenant().minusDays(numberOfDaysForPurgeCriteria);
OffsetDateTime dateForPurgeCriteria = DateUtils.getAuditOffsetDateTime().minusDays(numberOfDaysForPurgeCriteria);
repository.deleteOlderEventsWithStatus(CommandProcessingResultType.PROCESSED.getValue(), dateForPurgeCriteria);
} catch (Exception e) {
log.error("Error occurred while purging processed commands: ", e);
@@ -19,7 +19,6 @@
package org.apache.fineract.infrastructure.businessdate.service;
import java.time.LocalDate;
import java.time.ZoneId;
import java.util.HashMap;
import java.util.List;
import java.util.Optional;
@@ -70,8 +69,7 @@ public class BusinessDateReadPlatformServiceImpl implements BusinessDateReadPlat
@Override
public HashMap<BusinessDateType, LocalDate> getBusinessDates() {
HashMap<BusinessDateType, LocalDate> businessDateMap = new HashMap<>();
ZoneId zone = DateUtils.getDateTimeZoneOfTenant();
LocalDate tenantDate = LocalDate.now(zone);
LocalDate tenantDate = DateUtils.getLocalDateOfTenant();
businessDateMap.put(BusinessDateType.BUSINESS_DATE, tenantDate);
businessDateMap.put(BusinessDateType.COB_DATE, tenantDate);
if (configurationDomainService.isBusinessDateEnabled()) {
@@ -80,7 +78,6 @@ public class BusinessDateReadPlatformServiceImpl implements BusinessDateReadPlat
businessDateMap.put(BusinessDateType.valueOf(businessDateData.getType()), businessDateData.getDate());
}
}
return businessDateMap;
}
}
@@ -132,15 +132,11 @@ public class BusinessDateWritePlatformServiceImpl implements BusinessDateWritePl
private void updateBusinessDate(BusinessDate businessDate, LocalDate newDate, Map<String, Object> changes) {
LocalDate oldDate = businessDate.getDate();
if (!hasChange(oldDate, newDate)) {
if (DateUtils.isEqual(oldDate, newDate)) {
return;
}
businessDate.setDate(newDate);
repository.save(businessDate);
changes.put(businessDate.getType().name(), newDate);
}
private boolean hasChange(@NotNull LocalDate oldDate, @NotNull LocalDate date) {
return (date.isBefore(oldDate) || date.isAfter(oldDate));
}
}
@@ -32,6 +32,7 @@ import net.fortuna.ical4j.model.property.RRule;
import net.fortuna.ical4j.validate.ValidationException;
import org.apache.commons.lang3.StringUtils;
import org.apache.fineract.infrastructure.core.exception.PlatformApiDataValidationException;
import org.apache.fineract.infrastructure.core.service.DateUtils;
import org.quartz.CronExpression;
import org.springframework.util.ObjectUtils;
@@ -1045,7 +1046,7 @@ public class DataValidatorBuilder {
if (this.value != null && date != null) {
final LocalDate dateVal = (LocalDate) this.value;
if (date.isAfter(dateVal)) {
if (DateUtils.isAfter(date, dateVal)) {
final StringBuilder validationErrorCode = new StringBuilder("validation.msg.").append(this.resource).append(".")
.append(this.parameter).append(".is.less.than.date");
final StringBuilder defaultEnglishMessage = new StringBuilder("The parameter `").append(this.parameter)
@@ -1065,7 +1066,7 @@ public class DataValidatorBuilder {
if (this.value != null && date != null) {
final LocalDate dateVal = (LocalDate) this.value;
if (date.isBefore(dateVal)) {
if (DateUtils.isBefore(date, dateVal)) {
final StringBuilder validationErrorCode = new StringBuilder("validation.msg.").append(this.resource).append(".")
.append(this.parameter).append(".is.greater.than.date");
final StringBuilder defaultEnglishMessage = new StringBuilder("The parameter `").append(this.parameter)
@@ -1085,7 +1086,7 @@ public class DataValidatorBuilder {
if (this.value != null && date != null) {
final LocalDate dateVal = (LocalDate) this.value;
if (dateVal.isAfter(date)) {
if (DateUtils.isAfter(dateVal, date)) {
final StringBuilder validationErrorCode = new StringBuilder("validation.msg.").append(this.resource).append(".")
.append(this.parameter).append(".is.greater.than.date");
final StringBuilder defaultEnglishMessage = new StringBuilder("The parameter `").append(this.parameter)
@@ -1105,7 +1106,7 @@ public class DataValidatorBuilder {
if (this.value != null && date != null) {
final LocalDate dateVal = (LocalDate) this.value;
if (!dateVal.isEqual(date)) {
if (!DateUtils.isEqual(dateVal, date)) {
final StringBuilder validationErrorCode = new StringBuilder("validation.msg.").append(this.resource).append(".")
.append(this.parameter).append(".is.not.equal.to.date");
final StringBuilder defaultEnglishMessage = new StringBuilder("The parameter `").append(this.parameter)
@@ -22,6 +22,7 @@ import java.time.LocalDate;
import java.time.temporal.ChronoUnit;
import org.apache.commons.lang3.builder.ToStringBuilder;
import org.apache.commons.lang3.builder.ToStringStyle;
import org.apache.fineract.infrastructure.core.service.DateUtils;
public class LocalDateInterval {
@@ -66,11 +67,11 @@ public class LocalDateInterval {
}
private boolean isBetweenInclusive(final LocalDate start, final LocalDate end, final LocalDate target) {
return !target.isBefore(start) && !target.isAfter(end);
return !DateUtils.isBefore(target, start) && !DateUtils.isAfter(target, end);
}
public boolean fallsBefore(final LocalDate dateToCheck) {
return this.endDate.isBefore(dateToCheck);
return DateUtils.isBefore(this.endDate, dateToCheck);
}
@Override
@@ -70,10 +70,6 @@ public final class DateUtils {
return truncate == null ? now : now.truncatedTo(truncate);
}
public static OffsetDateTime getOffsetDateTimeOfTenantWithMostPrecision() {
return getOffsetDateTimeOfTenant(null);
}
public static OffsetDateTime getOffsetDateTimeOfTenant() {
return getOffsetDateTimeOfTenant(null);
}
@@ -20,6 +20,7 @@ package org.apache.fineract.infrastructure.core.service.database;
import com.google.common.collect.ImmutableList;
import jakarta.validation.constraints.NotNull;
import java.io.Serializable;
import java.sql.JDBCType;
import org.apache.fineract.infrastructure.core.exception.PlatformServiceUnavailableException;
@@ -272,7 +273,7 @@ public enum JdbcJavaType {
}
@com.google.errorprone.annotations.Immutable
private static final class DialectType {
private static final class DialectType implements Serializable {
@NotNull
private final JDBCType jdbcType;
@@ -99,7 +99,7 @@ public class SendAsynchronousEventsTasklet implements Tasklet {
}
private void markEventsAsSent(List<Long> eventIds) {
OffsetDateTime sentAt = DateUtils.getOffsetDateTimeOfTenantWithMostPrecision();
OffsetDateTime sentAt = DateUtils.getAuditOffsetDateTime();
// Partitioning dataset to avoid exception: PreparedStatement can have at most 65,535 parameters
List<List<Long>> partitions = Lists.partition(eventIds, 5_000);
@@ -80,7 +80,7 @@ public class ExternalEvent extends AbstractPersistableCustom {
this.data = data;
this.idempotencyKey = idempotencyKey;
this.aggregateRootId = aggregateRootId;
this.createdAt = DateUtils.getOffsetDateTimeOfTenantWithMostPrecision();
this.createdAt = DateUtils.getAuditOffsetDateTime();
this.status = ExternalEventStatus.TO_BE_SENT;
this.businessDate = DateUtils.getBusinessLocalDate();
}
@@ -20,6 +20,7 @@ package org.apache.fineract.organisation.holiday.service;
import java.time.LocalDate;
import java.util.List;
import org.apache.fineract.infrastructure.core.service.DateUtils;
import org.apache.fineract.organisation.holiday.domain.Holiday;
import org.apache.fineract.organisation.workingdays.data.AdjustedDateDetailsDTO;
@@ -30,47 +31,29 @@ public final class HolidayUtil {
}
public static LocalDate getRepaymentRescheduleDateToIfHoliday(LocalDate repaymentDate, final List<Holiday> holidays) {
for (final Holiday holiday : holidays) {
if (repaymentDate.equals(holiday.getFromDate()) || repaymentDate.equals(holiday.getToDate())
|| (repaymentDate.isAfter(holiday.getFromDate()) && repaymentDate.isBefore(holiday.getToDate()))) {
repaymentDate = getRepaymentRescheduleDateIfHoliday(repaymentDate, holidays);
}
}
return repaymentDate;
}
private static LocalDate getRepaymentRescheduleDateIfHoliday(final LocalDate repaymentDate, final List<Holiday> holidays) {
for (final Holiday holiday : holidays) {
if (repaymentDate.equals(holiday.getFromDate()) || repaymentDate.equals(holiday.getToDate())
|| (repaymentDate.isAfter(holiday.getFromDate()) && repaymentDate.isBefore(holiday.getToDate()))) {
// should be take from holiday
return holiday.getRepaymentsRescheduledTo();
if (isHoliday(repaymentDate, holiday)) {
repaymentDate = holiday.getRepaymentsRescheduledTo();
}
}
return repaymentDate;
}
public static boolean isHoliday(final LocalDate date, final List<Holiday> holidays) {
for (final Holiday holiday : holidays) {
if (date.isEqual(holiday.getFromDate()) || date.isEqual(holiday.getToDate())
|| (date.isAfter(holiday.getFromDate()) && date.isBefore(holiday.getToDate()))) {
return true;
}
}
return false;
return getApplicableHoliday(date, holidays) != null;
}
public static Holiday getApplicableHoliday(final LocalDate repaymentDate, final List<Holiday> holidays) {
Holiday referedHoliday = null;
for (final Holiday holiday : holidays) {
if (!repaymentDate.isBefore(holiday.getFromDate()) && !repaymentDate.isAfter(holiday.getToDate())) {
referedHoliday = holiday;
if (isHoliday(repaymentDate, holiday)) {
return holiday;
}
}
return referedHoliday;
return null;
}
public static boolean isHoliday(LocalDate date, Holiday holiday) {
return !DateUtils.isBefore(date, holiday.getFromDate()) && !DateUtils.isAfter(date, holiday.getToDate());
}
public static void updateRepaymentRescheduleDateToWorkingDayIfItIsHoliday(final AdjustedDateDetailsDTO adjustedDateDetailsDTO,
@@ -39,6 +39,7 @@ import org.apache.commons.lang3.StringUtils;
import org.apache.fineract.infrastructure.core.api.JsonCommand;
import org.apache.fineract.infrastructure.core.domain.AbstractPersistableCustom;
import org.apache.fineract.infrastructure.core.domain.ExternalId;
import org.apache.fineract.infrastructure.core.service.DateUtils;
import org.apache.fineract.infrastructure.core.service.ExternalIdFactory;
import org.apache.fineract.organisation.office.exception.CannotUpdateOfficeWithParentOfficeSameAsSelf;
import org.apache.fineract.organisation.office.exception.RootOfficeParentCannotBeUpdated;
@@ -155,11 +156,11 @@ public class Office extends AbstractPersistableCustom implements Serializable {
}
public boolean isOpeningDateBefore(final LocalDate baseDate) {
return getOpeningLocalDate().isBefore(baseDate);
return DateUtils.isBefore(getOpeningLocalDate(), baseDate);
}
public boolean isOpeningDateAfter(final LocalDate activationLocalDate) {
return getOpeningLocalDate().isAfter(activationLocalDate);
public boolean isOpeningDateAfter(final LocalDate baseDate) {
return DateUtils.isAfter(getOpeningLocalDate(), baseDate);
}
public LocalDate getOpeningLocalDate() {
@@ -28,6 +28,7 @@ import lombok.Data;
import lombok.NoArgsConstructor;
import lombok.experimental.Accessors;
import org.apache.fineract.infrastructure.core.data.EnumOptionData;
import org.apache.fineract.infrastructure.core.service.DateUtils;
import org.apache.fineract.portfolio.calendar.domain.CalendarFrequencyType;
import org.apache.fineract.portfolio.calendar.domain.CalendarRemindBy;
import org.apache.fineract.portfolio.calendar.domain.CalendarType;
@@ -377,12 +378,11 @@ public final class CalendarData implements Serializable {
}
public boolean isStartDateBeforeOrEqual(final LocalDate compareDate) {
return this.startDate != null && compareDate != null
&& (this.startDate.isBefore(compareDate) || this.startDate.equals(compareDate));
return this.startDate != null && compareDate != null && !DateUtils.isAfter(this.startDate, compareDate);
}
public boolean isEndDateAfterOrEqual(final LocalDate compareDate) {
return this.endDate != null && compareDate != null && (this.endDate.isAfter(compareDate) || this.endDate.isEqual(compareDate));
return this.endDate != null && compareDate != null && !DateUtils.isBefore(this.endDate, compareDate);
}
public boolean isBetweenStartAndEndDate(final LocalDate compareDate) {
@@ -20,10 +20,10 @@ package org.apache.fineract.portfolio.calendar.data;
import java.time.LocalDate;
import java.util.ArrayList;
import java.util.Collections;
import java.util.Comparator;
import java.util.List;
import java.util.Set;
import org.apache.fineract.infrastructure.core.service.DateUtils;
import org.apache.fineract.portfolio.calendar.domain.CalendarHistory;
public class CalendarHistoryDataWrapper {
@@ -37,16 +37,16 @@ public class CalendarHistoryDataWrapper {
@Override
public int compare(CalendarHistory calendarHistory1, CalendarHistory calendarHistory2) {
return calendarHistory1.getEndDateLocalDate().compareTo(calendarHistory2.getEndDateLocalDate());
return DateUtils.compare(calendarHistory1.getEndDate(), calendarHistory2.getEndDate());
}
};
Collections.sort(this.calendarHistoryList, orderByDate);
this.calendarHistoryList.sort(orderByDate);
}
public CalendarHistory getCalendarHistory(final LocalDate dueRepaymentPeriodDate) {
CalendarHistory calendarHistory = null;
for (CalendarHistory history : this.calendarHistoryList) {
if (history.getEndDateLocalDate().isAfter(dueRepaymentPeriodDate)) {
if (DateUtils.isAfter(history.getEndDate(), dueRepaymentPeriodDate)) {
calendarHistory = history;
break;
}
@@ -175,23 +175,19 @@ public class Calendar extends AbstractAuditableWithUTCDateTimeCustom {
}
public Map<String, Object> updateStartDateAndDerivedFeilds(final LocalDate newMeetingStartDate) {
final Map<String, Object> actualChanges = new LinkedHashMap<>(9);
final LocalDate currentDate = DateUtils.getLocalDateOfTenant();
if (newMeetingStartDate.isBefore(currentDate)) {
if (DateUtils.isBefore(newMeetingStartDate, currentDate)) {
final String defaultUserMessage = "New meeting effective from date cannot be in past";
throw new CalendarDateException("new.start.date.cannot.be.in.past", defaultUserMessage, newMeetingStartDate,
getStartDateLocalDate());
} else if (isStartDateAfter(newMeetingStartDate) && isStartDateBeforeOrEqual(currentDate)) {
// new meeting date should be on or after start date or current
// date
// new meeting date should be on or after start date or current date
final String defaultUserMessage = "New meeting effective from date cannot be a date before existing meeting start date";
throw new CalendarDateException("new.start.date.before.existing.date", defaultUserMessage, newMeetingStartDate,
getStartDateLocalDate());
} else {
actualChanges.put(CalendarSupportedParameters.START_DATE.getValue(), newMeetingStartDate.toString());
this.startDate = newMeetingStartDate;
@@ -200,33 +196,25 @@ public class Calendar extends AbstractAuditableWithUTCDateTimeCustom {
* recurring day and update it if it is changed. For weekly type is weekday and for monthly type it is day
* of the month
*/
CalendarFrequencyType calendarFrequencyType = CalendarUtils.getFrequency(this.recurrence);
Integer interval = CalendarUtils.getInterval(this.recurrence);
Integer repeatsOnDay = null;
/*
* Repeats on day, need to derive based on the start date
*/
// Repeats on day, need to derive based on the start date
if (calendarFrequencyType.isWeekly()) {
repeatsOnDay = newMeetingStartDate.get(ChronoField.DAY_OF_WEEK);
} else if (calendarFrequencyType.isMonthly()) {
repeatsOnDay = newMeetingStartDate.getDayOfMonth();
}
// TODO cover other recurrence also
this.recurrence = constructRecurrence(calendarFrequencyType, interval, repeatsOnDay, null);
}
return actualChanges;
}
public Map<String, Object> update(final JsonCommand command, final Boolean areActiveEntitiesSynced) {
final Map<String, Object> actualChanges = new LinkedHashMap<>(9);
if (command.isChangeInStringParameterNamed(CalendarSupportedParameters.TITLE.getValue(), this.title)) {
@@ -234,13 +222,11 @@ public class Calendar extends AbstractAuditableWithUTCDateTimeCustom {
actualChanges.put(CalendarSupportedParameters.TITLE.getValue(), newValue);
this.title = StringUtils.defaultIfEmpty(newValue, null);
}
if (command.isChangeInStringParameterNamed(CalendarSupportedParameters.DESCRIPTION.getValue(), this.description)) {
final String newValue = command.stringValueOfParameterNamed(CalendarSupportedParameters.DESCRIPTION.getValue());
actualChanges.put(CalendarSupportedParameters.DESCRIPTION.getValue(), newValue);
this.description = StringUtils.defaultIfEmpty(newValue, null);
}
if (command.isChangeInStringParameterNamed(CalendarSupportedParameters.LOCATION.getValue(), this.location)) {
final String newValue = command.stringValueOfParameterNamed(CalendarSupportedParameters.LOCATION.getValue());
actualChanges.put(CalendarSupportedParameters.LOCATION.getValue(), newValue);
@@ -251,12 +237,11 @@ public class Calendar extends AbstractAuditableWithUTCDateTimeCustom {
final String localeAsInput = command.locale();
final String startDateParamName = CalendarSupportedParameters.START_DATE.getValue();
if (command.isChangeInLocalDateParameterNamed(startDateParamName, getStartDateLocalDate())) {
final String valueAsInput = command.stringValueOfParameterNamed(startDateParamName);
final LocalDate newValue = command.localDateValueOfParameterNamed(startDateParamName);
final LocalDate currentDate = DateUtils.getLocalDateOfTenant();
if (newValue.isBefore(currentDate)) {
if (DateUtils.isBefore(newValue, currentDate)) {
final String defaultUserMessage = "New meeting effective from date cannot be in past";
throw new CalendarDateException("new.start.date.cannot.be.in.past", defaultUserMessage, newValue, getStartDateLocalDate());
} else if (isStartDateAfter(newValue) && isStartDateBeforeOrEqual(currentDate)) {
@@ -472,24 +457,19 @@ public class Calendar extends AbstractAuditableWithUTCDateTimeCustom {
}
public boolean isStartDateBefore(final LocalDate compareDate) {
if (this.startDate != null && compareDate != null && getStartDateLocalDate().isBefore(compareDate)) {
return true;
}
return false;
return startDate != null && DateUtils.isBefore(startDate, compareDate);
}
public boolean isStartDateBeforeOrEqual(final LocalDate compareDate) {
return this.startDate != null && compareDate != null
&& (getStartDateLocalDate().isBefore(compareDate) || getStartDateLocalDate().equals(compareDate));
return startDate != null && !DateUtils.isAfter(startDate, compareDate);
}
public boolean isStartDateAfter(final LocalDate compareDate) {
return this.startDate != null && compareDate != null && getStartDateLocalDate().isAfter(compareDate);
return compareDate != null && DateUtils.isAfter(startDate, compareDate);
}
public boolean isEndDateAfterOrEqual(final LocalDate compareDate) {
return this.endDate != null && compareDate != null
&& (getEndDateLocalDate().isAfter(compareDate) || getEndDateLocalDate().isEqual(compareDate));
return compareDate != null && !DateUtils.isBefore(endDate, compareDate);
}
public boolean isBetweenStartAndEndDate(final LocalDate compareDate) {
@@ -585,7 +565,7 @@ public class Calendar extends AbstractAuditableWithUTCDateTimeCustom {
// validate with history details.
for (CalendarHistory history : history()) {
if (history.isBetweenStartAndEndDate(compareDate)) {
return CalendarUtils.isValidRedurringDate(history.getRecurrence(), history.getStartDateLocalDate(), compareDate,
return CalendarUtils.isValidRedurringDate(history.getRecurrence(), history.getStartDate(), compareDate,
isSkipRepaymentOnFirstMonth, numberOfDays);
}
}
@@ -88,51 +88,63 @@ public enum CalendarEntityType {
}
public static boolean isGroup(final Integer value) {
return CalendarEntityType.GROUPS.value.equals(value) ? true : false;
return CalendarEntityType.GROUPS.value.equals(value);
}
public static boolean isGroup(final String name) {
return CalendarEntityType.GROUPS.name().equalsIgnoreCase(name) ? true : false;
return CalendarEntityType.GROUPS.name().equalsIgnoreCase(name);
}
public static boolean isCenter(final Integer value) {
return CalendarEntityType.CENTERS.value.equals(value) ? true : false;
return CalendarEntityType.CENTERS.value.equals(value);
}
public static boolean isCenter(final String name) {
return CalendarEntityType.CENTERS.name().equalsIgnoreCase(name) ? true : false;
return CalendarEntityType.CENTERS.name().equalsIgnoreCase(name);
}
public static boolean isLoan(final Integer value) {
return CalendarEntityType.LOANS.value.equals(value) ? true : false;
return CalendarEntityType.LOANS.value.equals(value);
}
public static boolean isLoan(final String name) {
return CalendarEntityType.LOANS.name().equalsIgnoreCase(name) ? true : false;
return CalendarEntityType.LOANS.name().equalsIgnoreCase(name);
}
public static boolean isClient(final Integer value) {
return CalendarEntityType.CLIENTS.value.equals(value) ? true : false;
return CalendarEntityType.CLIENTS.value.equals(value);
}
public static boolean isClient(final String name) {
return CalendarEntityType.CLIENTS.name().equalsIgnoreCase(name) ? true : false;
return CalendarEntityType.CLIENTS.name().equalsIgnoreCase(name);
}
public static boolean isSavings(final Integer value) {
return CalendarEntityType.SAVINGS.value.equals(value);
}
public static boolean isSavings(final String name) {
return CalendarEntityType.SAVINGS.name().equalsIgnoreCase(name);
}
public boolean isCenter() {
return this.value.equals(CalendarEntityType.CENTERS.getValue());
return this == CENTERS;
}
public boolean isGroup() {
return this.value.equals(CalendarEntityType.GROUPS.getValue());
return this == GROUPS;
}
public boolean isLoan() {
return this.value.equals(CalendarEntityType.LOANS.getValue());
return this == LOANS;
}
public boolean isClient() {
return this.value.equals(CalendarEntityType.CLIENTS.getValue());
return this == CLIENTS;
}
public boolean isSavings() {
return this == SAVINGS;
}
private static final Map<String, CalendarEntityType> entityNameToEnumMap = new HashMap<>();
@@ -146,17 +158,4 @@ public enum CalendarEntityType {
public static CalendarEntityType getEntityType(String entityType) {
return entityNameToEnumMap.get(entityType.toLowerCase());
}
public static boolean isSavings(final Integer value) {
return CalendarEntityType.SAVINGS.value.equals(value) ? true : false;
}
public static boolean isSavings(final String name) {
return CalendarEntityType.SAVINGS.name().equalsIgnoreCase(name) ? true : false;
}
public boolean isSavings() {
return this.value.equals(CalendarEntityType.SAVINGS.getValue());
}
}
@@ -25,6 +25,7 @@ import jakarta.persistence.ManyToOne;
import jakarta.persistence.Table;
import java.time.LocalDate;
import org.apache.fineract.infrastructure.core.domain.AbstractPersistableCustom;
import org.apache.fineract.infrastructure.core.service.DateUtils;
@Entity
@Table(name = "m_calendar_history")
@@ -95,26 +96,24 @@ public class CalendarHistory extends AbstractPersistableCustom {
return this.recurrence;
}
public LocalDate getStartDateLocalDate() {
public LocalDate getStartDate() {
return this.startDate;
}
public LocalDate getEndDateLocalDate() {
public LocalDate getEndDate() {
return this.endDate;
}
public boolean isEndDateAfterOrEqual(final LocalDate compareDate) {
return this.endDate != null && compareDate != null
&& (getEndDateLocalDate().isAfter(compareDate) || getEndDateLocalDate().isEqual(compareDate));
public boolean isStartDateBeforeOrEqual(final LocalDate compareDate) {
return this.startDate != null && compareDate != null && !DateUtils.isAfter(this.startDate, compareDate);
}
public boolean isStartDateBeforeOrEqual(final LocalDate compareDate) {
return this.startDate != null && compareDate != null
&& (getStartDateLocalDate().isBefore(compareDate) || getStartDateLocalDate().equals(compareDate));
public boolean isEndDateAfterOrEqual(final LocalDate compareDate) {
return this.endDate != null && compareDate != null && !DateUtils.isBefore(this.endDate, compareDate);
}
public boolean isBetweenStartAndEndDate(final LocalDate compareDate) {
return isStartDateBeforeOrEqual(compareDate) && (getEndDateLocalDate() == null || isEndDateAfterOrEqual(compareDate));
return isStartDateBeforeOrEqual(compareDate) && (getEndDate() == null || isEndDateAfterOrEqual(compareDate));
}
public void updateEndDate(LocalDate historyCalEndDate) {
@@ -103,14 +103,14 @@ public final class CalendarUtils {
final DateTime periodStart = new DateTime(java.util.Date.from(startDate.atZone(ZoneId.systemDefault()).toInstant()));
final Date seed = convertToiCal4JCompatibleDate(seedDate);
final Date nextRecDate = recur.getNextDate(seed, periodStart);
return nextRecDate == null ? null : LocalDateTime.ofInstant(nextRecDate.toInstant(), DateUtils.getSystemZoneId());
return nextRecDate == null ? null : LocalDateTime.ofInstant(nextRecDate.toInstant(), DateUtils.getDateTimeZoneOfTenant());
}
private static LocalDate getNextRecurringDate(final Recur recur, final LocalDate seedDate, final LocalDate startDate) {
final DateTime periodStart = new DateTime(java.util.Date.from(startDate.atStartOfDay(ZoneId.systemDefault()).toInstant()));
final Date seed = convertToiCal4JCompatibleDate(seedDate.atStartOfDay());
final Date nextRecDate = recur.getNextDate(seed, periodStart);
return nextRecDate == null ? null : LocalDate.ofInstant(nextRecDate.toInstant(), DateUtils.getSystemZoneId());
return nextRecDate == null ? null : LocalDate.ofInstant(nextRecDate.toInstant(), DateUtils.getDateTimeZoneOfTenant());
}
private static Date convertToiCal4JCompatibleDate(final LocalDateTime inputDate) {
@@ -125,16 +125,16 @@ public final class CalendarUtils {
}
public static Collection<LocalDate> getRecurringDates(final String recurringRule, final LocalDate seedDate, final LocalDate endDate) {
final LocalDate periodStartDate = DateUtils.getLocalDateOfTenant();
final LocalDate periodEndDate = (endDate == null) ? DateUtils.getLocalDateOfTenant().plusYears(5) : endDate;
final LocalDate periodEndDate = endDate == null ? periodStartDate.plusYears(5) : endDate;
return getRecurringDates(recurringRule, seedDate, periodStartDate, periodEndDate);
}
public static Collection<LocalDate> getRecurringDatesFrom(final String recurringRule, final LocalDate seedDate,
final LocalDate startDate) {
final LocalDate periodStartDate = (startDate == null) ? DateUtils.getLocalDateOfTenant() : startDate;
final LocalDate periodEndDate = DateUtils.getLocalDateOfTenant().plusYears(5);
LocalDate currentDate = DateUtils.getLocalDateOfTenant();
final LocalDate periodStartDate = startDate == null ? currentDate : startDate;
final LocalDate periodEndDate = currentDate.plusYears(5);
return getRecurringDates(recurringRule, seedDate, periodStartDate, periodEndDate);
}
@@ -150,7 +150,6 @@ public final class CalendarUtils {
public static Collection<LocalDate> getRecurringDates(final String recurringRule, final LocalDate seedDate,
final LocalDate periodStartDate, final LocalDate periodEndDate, final int maxCount, boolean isSkippMeetingOnFirstDay,
final Integer numberOfDays) {
final Recur recur = CalendarUtils.getICalRecur(recurringRule);
return getRecurringDates(recur, seedDate, periodStartDate, periodEndDate, maxCount, isSkippMeetingOnFirstDay, numberOfDays);
@@ -173,7 +172,6 @@ public final class CalendarUtils {
private static Collection<LocalDate> convertToLocalDateList(final DateList dates, final LocalDate seedDate,
final PeriodFrequencyType frequencyType, boolean isSkippMeetingOnFirstDay, final Integer numberOfDays) {
final Collection<LocalDate> recurringDates = new ArrayList<>();
for (@SuppressWarnings("rawtypes")
@@ -407,10 +407,6 @@ public class Client extends AbstractAuditableWithUTCDateTimeCustom {
return ClientStatus.fromInt(this.status).isPending();
}
private boolean isDateInTheFuture(final LocalDate localDate) {
return localDate.isAfter(DateUtils.getBusinessLocalDate());
}
public boolean isRejected() {
return ClientStatus.fromInt(this.status).isRejected();
}
@@ -444,49 +440,40 @@ public class Client extends AbstractAuditableWithUTCDateTimeCustom {
}
private void validateActivationDate(final List<ApiParameterError> dataValidationErrors) {
if (getSubmittedOnDate() != null && isDateInTheFuture(getSubmittedOnDate())) {
if (getSubmittedOnDate() != null && DateUtils.isDateInTheFuture(getSubmittedOnDate())) {
final String defaultUserMessage = "submitted date cannot be in the future.";
final ApiParameterError error = ApiParameterError.parameterError("error.msg.clients.submittedOnDate.in.the.future",
defaultUserMessage, ClientApiConstants.submittedOnDateParamName, this.submittedOnDate);
dataValidationErrors.add(error);
}
if (getActivationLocalDate() != null && getSubmittedOnDate() != null && getSubmittedOnDate().isAfter(getActivationLocalDate())) {
if (getActivationDate() != null && DateUtils.isAfter(getSubmittedOnDate(), getActivationDate())) {
final String defaultUserMessage = "submitted date cannot be after the activation date";
final ApiParameterError error = ApiParameterError.parameterError("error.msg.clients.submittedOnDate.after.activation.date",
defaultUserMessage, ClientApiConstants.submittedOnDateParamName, this.submittedOnDate);
dataValidationErrors.add(error);
}
if (getReopenedDate() != null && getActivationLocalDate() != null && getReopenedDate().isAfter(getActivationLocalDate())) {
if (getActivationDate() != null && DateUtils.isAfter(getReopenedDate(), getActivationDate())) {
final String defaultUserMessage = "reopened date cannot be after the submittedon date";
final ApiParameterError error = ApiParameterError.parameterError("error.msg.clients.submittedOnDate.after.reopened.date",
defaultUserMessage, ClientApiConstants.reopenedDateParamName, this.reopenedDate);
dataValidationErrors.add(error);
}
if (getActivationLocalDate() != null && isDateInTheFuture(getActivationLocalDate())) {
if (DateUtils.isDateInTheFuture(getActivationDate())) {
final String defaultUserMessage = "Activation date cannot be in the future.";
final ApiParameterError error = ApiParameterError.parameterError("error.msg.clients.activationDate.in.the.future",
defaultUserMessage, ClientApiConstants.activationDateParamName, getActivationLocalDate());
defaultUserMessage, ClientApiConstants.activationDateParamName, getActivationDate());
dataValidationErrors.add(error);
}
if (getActivationLocalDate() != null) {
if (this.office.isOpeningDateAfter(getActivationLocalDate())) {
if (getActivationDate() != null) {
if (this.office.isOpeningDateAfter(getActivationDate())) {
final String defaultUserMessage = "Client activation date cannot be a date before the office opening date.";
final ApiParameterError error = ApiParameterError.parameterError(
"error.msg.clients.activationDate.cannot.be.before.office.activation.date", defaultUserMessage,
ClientApiConstants.activationDateParamName, getActivationLocalDate());
ClientApiConstants.activationDateParamName, getActivationDate());
dataValidationErrors.add(error);
}
}
@@ -518,14 +505,6 @@ public class Client extends AbstractAuditableWithUTCDateTimeCustom {
}
}
public LocalDate getActivationLocalDate() {
return this.activationDate;
}
public LocalDate getOfficeJoiningLocalDate() {
return this.officeJoiningDate;
}
public boolean isOfficeIdentifiedBy(final Long officeId) {
return this.office.identifiedBy(officeId);
}
@@ -618,7 +597,7 @@ public class Client extends AbstractAuditableWithUTCDateTimeCustom {
}
public boolean isActivatedAfter(final LocalDate submittedOn) {
return getActivationLocalDate().isAfter(submittedOn);
return DateUtils.isAfter(getActivationDate(), submittedOn);
}
public boolean isChildOfGroup(final Long groupId) {
@@ -21,6 +21,7 @@ package org.apache.fineract.portfolio.floatingrates.data;
import java.math.BigDecimal;
import java.time.LocalDate;
import java.util.Collection;
import org.apache.fineract.infrastructure.core.service.DateUtils;
public class FloatingRateDTO {
@@ -43,7 +44,7 @@ public class FloatingRateDTO {
BigDecimal rate = null;
for (FloatingRatePeriodData periodData : this.baseLendingRatePeriods) {
final LocalDate periodFromDate = periodData.getFromDate();
if (periodFromDate.isBefore(date) || periodFromDate.isEqual(date)) {
if (!DateUtils.isAfter(periodFromDate, date)) {
rate = periodData.getInterestRate();
break;
}
@@ -89,9 +89,8 @@ public class FloatingRate extends AbstractAuditableWithUTCDateTimeCustom {
final String name = command.stringValueOfParameterNamed("name");
final boolean isBaseLendingRate = command.parameterExists("isBaseLendingRate")
? command.booleanPrimitiveValueOfParameterNamed("isBaseLendingRate")
: false;
final boolean isActive = command.parameterExists("isActive") ? command.booleanPrimitiveValueOfParameterNamed("isActive") : true;
&& command.booleanPrimitiveValueOfParameterNamed("isBaseLendingRate");
final boolean isActive = !command.parameterExists("isActive") || command.booleanPrimitiveValueOfParameterNamed("isActive");
final List<FloatingRatePeriod> floatingRatePeriods = getRatePeriods(command);
return new FloatingRate(name, isBaseLendingRate, isActive, floatingRatePeriods);
@@ -109,8 +108,7 @@ public class FloatingRate extends AbstractAuditableWithUTCDateTimeCustom {
final LocalDate fromDate = helper.extractLocalDateNamed("fromDate", ratePeriod, new HashSet<String>());
final BigDecimal interestRate = ratePeriodObject.get("interestRate").getAsBigDecimal();
final boolean isDifferentialToBaseLendingRate = helper.parameterExists("isDifferentialToBaseLendingRate", ratePeriod)
? ratePeriodObject.get("isDifferentialToBaseLendingRate").getAsBoolean()
: false;
&& ratePeriodObject.get("isDifferentialToBaseLendingRate").getAsBoolean();
final boolean isActive = true;
ratePeriods.add(new FloatingRatePeriod(fromDate, interestRate, isDifferentialToBaseLendingRate, isActive));
}
@@ -170,7 +168,7 @@ public class FloatingRate extends AbstractAuditableWithUTCDateTimeCustom {
if (this.floatingRatePeriods != null) {
for (FloatingRatePeriod ratePeriod : this.floatingRatePeriods) {
LocalDate fromDate = ratePeriod.getFromDate();
if (fromDate.isAfter(today)) {
if (DateUtils.isAfter(fromDate, today)) {
ratePeriod.setActive(false);
}
}
@@ -188,7 +186,7 @@ public class FloatingRate extends AbstractAuditableWithUTCDateTimeCustom {
for (FloatingRatePeriod floatingRatePeriod : this.floatingRatePeriods) {
if (floatingRatePeriod.isActive()) {
// will enter
if (applicableRates.isEmpty() && floatingRateDTO.getStartDate().isBefore(floatingRatePeriod.fetchFromDate())) {
if (applicableRates.isEmpty() && DateUtils.isBefore(floatingRateDTO.getStartDate(), floatingRatePeriod.fetchFromDate())) {
if (floatingRateDTO.isFloatingInterestRate()) {
addPeriodData = true;
}
@@ -340,7 +340,7 @@ public class GroupGeneralData implements Serializable {
}
public boolean isChildGroup() {
return this.centerId == null ? false : true;
return this.centerId != null;
}
public Long getParentId() {
@@ -25,6 +25,7 @@ import jakarta.persistence.ManyToOne;
import jakarta.persistence.Table;
import java.time.LocalDate;
import org.apache.fineract.infrastructure.core.domain.AbstractAuditableCustom;
import org.apache.fineract.infrastructure.core.service.DateUtils;
import org.apache.fineract.organisation.staff.domain.Staff;
@Entity
@@ -73,7 +74,7 @@ public class StaffAssignmentHistory extends AbstractAuditableCustom {
}
public boolean matchesStartDateOf(final LocalDate matchingDate) {
return getStartDate().isEqual(matchingDate);
return DateUtils.isEqual(matchingDate, getStartDate());
}
public LocalDate getStartDate() {
@@ -27,6 +27,7 @@ import java.util.Map;
import lombok.Getter;
import org.apache.fineract.accounting.glaccount.data.GLAccountData;
import org.apache.fineract.infrastructure.core.data.EnumOptionData;
import org.apache.fineract.infrastructure.core.service.DateUtils;
@Getter
public final class TaxComponentData implements Serializable {
@@ -136,7 +137,7 @@ public final class TaxComponentData implements Serializable {
}
private boolean occursOnDayFrom(final LocalDate target) {
return target != null && target.isAfter(startDate());
return DateUtils.isAfter(target, startDate());
}
public LocalDate startDate() {
@@ -21,6 +21,7 @@ package org.apache.fineract.portfolio.tax.data;
import java.io.Serializable;
import java.math.BigDecimal;
import java.time.LocalDate;
import org.apache.fineract.infrastructure.core.service.DateUtils;
public class TaxComponentHistoryData implements Serializable {
@@ -38,10 +39,7 @@ public class TaxComponentHistoryData implements Serializable {
}
public boolean occursOnDayFromAndUpToAndIncluding(final LocalDate target) {
if (this.endDate == null) {
return target != null && target.isAfter(startDate());
}
return target != null && target.isAfter(startDate()) && !target.isAfter(endDate());
return DateUtils.isAfter(target, startDate()) && (endDate == null || !DateUtils.isAfter(target, endDate()));
}
public LocalDate startDate() {
@@ -20,6 +20,7 @@ package org.apache.fineract.portfolio.tax.data;
import java.io.Serializable;
import java.time.LocalDate;
import org.apache.fineract.infrastructure.core.service.DateUtils;
public class TaxGroupMappingsData implements Serializable {
@@ -44,10 +45,7 @@ public class TaxGroupMappingsData implements Serializable {
}
public boolean occursOnDayFromAndUpToAndIncluding(final LocalDate target) {
if (this.endDate == null) {
return target != null && target.isAfter(startDate());
}
return target != null && target.isAfter(startDate()) && !target.isAfter(endDate());
return DateUtils.isAfter(target, startDate()) && (endDate == null || !DateUtils.isAfter(target, endDate()));
}
public LocalDate startDate() {
@@ -167,7 +167,7 @@ public class TaxComponent extends AbstractAuditableCustom {
}
private boolean occursOnDayFrom(final LocalDate target) {
return target != null && target.isAfter(startDate());
return DateUtils.isAfter(target, startDate());
}
public Set<TaxComponentHistory> getTaxComponentHistories() {
@@ -24,6 +24,7 @@ import jakarta.persistence.Table;
import java.math.BigDecimal;
import java.time.LocalDate;
import org.apache.fineract.infrastructure.core.domain.AbstractAuditableCustom;
import org.apache.fineract.infrastructure.core.service.DateUtils;
@Entity
@Table(name = "m_tax_component_history")
@@ -62,10 +63,7 @@ public class TaxComponentHistory extends AbstractAuditableCustom {
}
public boolean occursOnDayFromAndUpToAndIncluding(final LocalDate target) {
if (this.endDate == null) {
return target != null && target.isAfter(startDate());
}
return target != null && target.isAfter(startDate()) && !target.isAfter(endDate());
return DateUtils.isAfter(target, startDate()) && (endDate == null || !DateUtils.isAfter(target, endDate()));
}
public BigDecimal getPercentage() {
@@ -28,6 +28,7 @@ import java.util.HashMap;
import java.util.List;
import java.util.Map;
import org.apache.fineract.infrastructure.core.domain.AbstractAuditableCustom;
import org.apache.fineract.infrastructure.core.service.DateUtils;
import org.apache.fineract.portfolio.tax.api.TaxApiConstants;
@Entity
@@ -81,10 +82,7 @@ public class TaxGroupMappings extends AbstractAuditableCustom {
}
public boolean occursOnDayFromAndUpToAndIncluding(final LocalDate target) {
if (this.endDate == null) {
return target != null && target.isAfter(startDate());
}
return target != null && target.isAfter(startDate()) && !target.isAfter(endDate());
return DateUtils.isAfter(target, startDate()) && (endDate == null || !DateUtils.isAfter(target, endDate()));
}
public TaxComponent getTaxComponent() {
@@ -30,4 +30,6 @@ public final class AppUserConstants {
// TODO: Remove hard coding of system user name and make this a configurable parameter
public static final String SYSTEM_USER_NAME = "system";
public static final Long ADMIN_USER_ID = 1L;
public static final Long SYSTEM_USER_ID = 2L;
}