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;
}
@@ -37,6 +37,7 @@ import org.apache.fineract.accounting.producttoaccountmapping.domain.PortfolioPr
import org.apache.fineract.accounting.producttoaccountmapping.domain.ProductToGLAccountMapping;
import org.apache.fineract.accounting.producttoaccountmapping.domain.ProductToGLAccountMappingRepository;
import org.apache.fineract.accounting.producttoaccountmapping.exception.ProductToGLAccountMappingNotFoundException;
import org.apache.fineract.infrastructure.core.service.DateUtils;
import org.apache.fineract.organisation.office.domain.Office;
import org.springframework.stereotype.Service;
@@ -61,7 +62,7 @@ public class InvestorAccountingHelper {
**/
GLClosure gLClosure = getLatestClosureByBranch(officeId);
if (gLClosure != null) {
if (gLClosure.getClosingDate().isAfter(transactionDate) || gLClosure.getClosingDate().isEqual(transactionDate)) {
if (!DateUtils.isAfter(transactionDate, gLClosure.getClosingDate())) {
throw new JournalEntryInvalidException(GlJournalEntryInvalidReason.ACCOUNTING_CLOSED, gLClosure.getClosingDate(), null,
null);
}
@@ -170,7 +170,7 @@ public class ExternalAssetOwnersWriteServiceImpl implements ExternalAssetOwnersW
throw new ExternalAssetOwnerInitiateTransferException(
String.format("This loan cannot be bought back, effective transfer is not in right state: %s",
effectiveTransfers.get(0).getStatus()));
} else if (settlementDate.isBefore(effectiveTransfers.get(0).getSettlementDate())) {
} else if (DateUtils.isBefore(settlementDate, effectiveTransfers.get(0).getSettlementDate())) {
throw new ExternalAssetOwnerInitiateTransferException(
String.format("This loan cannot be bought back, settlement date is earlier than effective transfer settlement date: %s",
effectiveTransfers.get(0).getSettlementDate()));
@@ -251,7 +251,7 @@ public class ExternalAssetOwnersWriteServiceImpl implements ExternalAssetOwnersW
}
private void validateSettlementDate(LocalDate settlementDate) {
if (settlementDate.isBefore(ThreadLocalContextUtil.getBusinessDate())) {
if (DateUtils.isBeforeBusinessDate(settlementDate)) {
throw new ExternalAssetOwnerInitiateTransferException("Settlement date cannot be in the past");
}
}
@@ -22,6 +22,7 @@ import java.math.BigDecimal;
import java.time.LocalDate;
import lombok.Getter;
import lombok.RequiredArgsConstructor;
import org.apache.fineract.infrastructure.core.service.DateUtils;
/**
* Immutable data object representing disbursement information.
@@ -85,8 +86,7 @@ public final class DisbursementData implements Comparable<DisbursementData> {
if (obj == null) {
return -1;
}
return obj.expectedDisbursementDate.compareTo(this.expectedDisbursementDate);
return DateUtils.compare(obj.expectedDisbursementDate, this.expectedDisbursementDate);
}
public boolean isDueForDisbursement(final LocalDate fromNotInclusive, final LocalDate upToAndInclusive) {
@@ -96,14 +96,11 @@ public final class DisbursementData implements Comparable<DisbursementData> {
private boolean occursOnDayFromAndUpToAndIncluding(final LocalDate fromNotInclusive, final LocalDate upToAndInclusive,
final LocalDate target) {
return target != null && target.isAfter(fromNotInclusive) && !target.isAfter(upToAndInclusive);
return DateUtils.isAfter(target, fromNotInclusive) && !DateUtils.isAfter(target, upToAndInclusive);
}
public BigDecimal getWaivedChargeAmount() {
if (this.waivedChargeAmount == null) {
return BigDecimal.ZERO;
}
return this.waivedChargeAmount;
return this.waivedChargeAmount == null ? BigDecimal.ZERO : this.waivedChargeAmount;
}
}
@@ -22,6 +22,7 @@ import java.math.BigDecimal;
import java.time.LocalDate;
import lombok.Getter;
import org.apache.fineract.infrastructure.core.data.EnumOptionData;
import org.apache.fineract.infrastructure.core.service.DateUtils;
import org.apache.fineract.portfolio.loanaccount.domain.LoanTermVariationType;
@Getter
@@ -64,7 +65,7 @@ public class LoanTermVariationsData implements Comparable<LoanTermVariationsData
}
private boolean occursOnDayFromAndUpTo(final LocalDate fromNotInclusive, final LocalDate upToInclusive, final LocalDate target) {
return target != null && target.isAfter(fromNotInclusive) && !target.isAfter(upToInclusive);
return DateUtils.isAfter(target, fromNotInclusive) && !DateUtils.isAfter(target, upToInclusive);
}
public boolean isApplicable(final LocalDate fromDate) {
@@ -72,7 +73,7 @@ public class LoanTermVariationsData implements Comparable<LoanTermVariationsData
}
private boolean occursBefore(final LocalDate date, final LocalDate target) {
return target != null && !target.isAfter(date);
return target != null && !DateUtils.isAfter(target, date);
}
public boolean isSpecificToInstallment() {
@@ -84,7 +85,7 @@ public class LoanTermVariationsData implements Comparable<LoanTermVariationsData
}
public Boolean isProcessed() {
return this.isProcessed == null ? false : this.isProcessed;
return this.isProcessed != null && this.isProcessed;
}
public void setProcessed(Boolean isProcessed) {
@@ -23,6 +23,7 @@ import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
import java.util.ListIterator;
import org.apache.fineract.infrastructure.core.service.DateUtils;
public class LoanTermVariationsDataWrapper {
@@ -54,7 +55,7 @@ public class LoanTermVariationsDataWrapper {
boolean hasVariation = false;
if (iterator.hasNext()) {
LoanTermVariationsData loanTermVariationsData = iterator.next();
if (!loanTermVariationsData.getTermVariationApplicableFrom().isAfter(date)) {
if (!DateUtils.isAfter(loanTermVariationsData.getTermVariationApplicableFrom(), date)) {
hasVariation = true;
}
iterator.previous();
@@ -123,7 +124,7 @@ public class LoanTermVariationsDataWrapper {
public LoanTermVariationsData fetchLoanTermDueDateVariationsData(final LocalDate onDate) {
LoanTermVariationsData data = null;
for (LoanTermVariationsData termVariationsData : this.dueDateVariation) {
if (onDate.isEqual(termVariationsData.getTermVariationApplicableFrom())) {
if (DateUtils.isEqual(onDate, termVariationsData.getTermVariationApplicableFrom())) {
data = termVariationsData;
break;
}
@@ -2352,8 +2352,7 @@ public class Loan extends AbstractAuditableWithUTCDateTimeCustom {
final LocalDate submittalDate = this.submittedOnDate;
if (DateUtils.isBefore(approvedOn, submittalDate)) {
final String errorMessage = "The date on which a loan is approved cannot be before its submittal date: "
+ submittalDate.toString();
final String errorMessage = "The date on which a loan is approved cannot be before its submittal date: " + submittalDate;
throw new InvalidLoanStateTransitionException("approval", "cannot.be.before.submittal.date", errorMessage,
getApprovedOnDate(), submittalDate);
}
@@ -3394,8 +3393,7 @@ public class Loan extends AbstractAuditableWithUTCDateTimeCustom {
incomePostTransactions.add(transaction);
}
}
final LoanTransactionComparator transactionComparator = new LoanTransactionComparator();
Collections.sort(incomePostTransactions, transactionComparator);
incomePostTransactions.sort(LoanTransactionComparator.INSTANCE);
return incomePostTransactions;
}
@@ -3408,8 +3406,7 @@ public class Loan extends AbstractAuditableWithUTCDateTimeCustom {
repaymentsOrWaivers.add(transaction);
}
}
final LoanTransactionComparator transactionComparator = new LoanTransactionComparator();
Collections.sort(repaymentsOrWaivers, transactionComparator);
repaymentsOrWaivers.sort(LoanTransactionComparator.INSTANCE);
return repaymentsOrWaivers;
}
@@ -3422,8 +3419,7 @@ public class Loan extends AbstractAuditableWithUTCDateTimeCustom {
repaymentsOrWaivers.add(transaction);
}
}
final LoanTransactionComparator transactionComparator = new LoanTransactionComparator();
Collections.sort(repaymentsOrWaivers, transactionComparator);
repaymentsOrWaivers.sort(LoanTransactionComparator.INSTANCE);
return repaymentsOrWaivers;
}
@@ -3434,8 +3430,7 @@ public class Loan extends AbstractAuditableWithUTCDateTimeCustom {
repaymentsOrWaivers.add(transaction);
}
}
final LoanTransactionComparator transactionComparator = new LoanTransactionComparator();
Collections.sort(repaymentsOrWaivers, transactionComparator);
repaymentsOrWaivers.sort(LoanTransactionComparator.INSTANCE);
return repaymentsOrWaivers;
}
@@ -3446,8 +3441,7 @@ public class Loan extends AbstractAuditableWithUTCDateTimeCustom {
transactions.add(transaction);
}
}
final LoanTransactionComparator transactionComparator = new LoanTransactionComparator();
Collections.sort(transactions, transactionComparator);
transactions.sort(LoanTransactionComparator.INSTANCE);
return transactions;
}
@@ -3458,8 +3452,7 @@ public class Loan extends AbstractAuditableWithUTCDateTimeCustom {
transactions.add(transaction);
}
}
final LoanTransactionComparator transactionComparator = new LoanTransactionComparator();
Collections.sort(transactions, transactionComparator);
transactions.sort(LoanTransactionComparator.INSTANCE);
return transactions;
}
@@ -6670,7 +6663,7 @@ public class Loan extends AbstractAuditableWithUTCDateTimeCustom {
paidFromFutureInstallments = paidFromFutureInstallments.plus(balancesForCurrentPeroid[4])
.minus(balancesForCurrentPeroid[2]);
}
} else if (installment.getDueDate().isAfter(paymentDate)) {
} else {
paidFromFutureInstallments = paidFromFutureInstallments.plus(installment.getInterestPaid(currency))
.plus(installment.getPenaltyChargesPaid(currency)).plus(installment.getFeeChargesPaid(currency));
}
@@ -363,13 +363,11 @@ public class LoanCharge extends AbstractAuditableWithUTCDateTimeCustom {
if (this.loan != null) {
switch (ChargeCalculationType.fromInt(this.chargeCalculation)) {
case PERCENT_OF_AMOUNT:
// If charge type is specified due date and loan is multi
// disburment loan.
// Then we need to get as of this loan charge due date how
// much amount disbursed.
// If charge type is specified due date and loan is multi disburment loan.
// Then we need to get as of this loan charge due date how much amount disbursed.
if (this.loan.isMultiDisburmentLoan() && this.isSpecifiedDueDate()) {
for (final LoanDisbursementDetails loanDisbursementDetails : this.loan.getDisbursementDetails()) {
if (!loanDisbursementDetails.expectedDisbursementDate().isAfter(this.getDueDate())) {
if (!DateUtils.isAfter(loanDisbursementDetails.expectedDisbursementDate(), this.getDueDate())) {
amountPercentageAppliedTo = amountPercentageAppliedTo.add(loanDisbursementDetails.principal());
}
}
@@ -635,13 +633,12 @@ public class LoanCharge extends AbstractAuditableWithUTCDateTimeCustom {
private boolean occursOnDayFromExclusiveAndUpToAndIncluding(final LocalDate fromNotInclusive, final LocalDate upToAndInclusive,
final LocalDate target) {
return target != null && target.isAfter(fromNotInclusive) && !target.isAfter(upToAndInclusive);
return DateUtils.isAfter(target, fromNotInclusive) && !DateUtils.isAfter(target, upToAndInclusive);
}
private boolean occursOnDayFromAndUpToAndIncluding(final LocalDate fromAndInclusive, final LocalDate upToAndInclusive,
final LocalDate target) {
return target != null && (target.isEqual(fromAndInclusive) || target.isAfter(fromAndInclusive))
&& !target.isAfter(upToAndInclusive);
return target != null && !DateUtils.isBefore(target, fromAndInclusive) && !DateUtils.isAfter(target, upToAndInclusive);
}
public boolean isFeeCharge() {
@@ -792,8 +789,9 @@ public class LoanCharge extends AbstractAuditableWithUTCDateTimeCustom {
public LoanInstallmentCharge getUnpaidInstallmentLoanCharge() {
LoanInstallmentCharge unpaidChargePerInstallment = null;
for (final LoanInstallmentCharge loanChargePerInstallment : this.loanInstallmentCharge) {
if (loanChargePerInstallment.isPending() && (unpaidChargePerInstallment == null || unpaidChargePerInstallment
.getRepaymentInstallment().getDueDate().isAfter(loanChargePerInstallment.getRepaymentInstallment().getDueDate()))) {
if (loanChargePerInstallment.isPending() && (unpaidChargePerInstallment == null
|| DateUtils.isAfter(unpaidChargePerInstallment.getRepaymentInstallment().getDueDate(),
loanChargePerInstallment.getRepaymentInstallment().getDueDate()))) {
unpaidChargePerInstallment = loanChargePerInstallment;
}
}
@@ -802,7 +800,7 @@ public class LoanCharge extends AbstractAuditableWithUTCDateTimeCustom {
public LoanInstallmentCharge getInstallmentLoanCharge(final LocalDate periodDueDate) {
for (final LoanInstallmentCharge loanChargePerInstallment : this.loanInstallmentCharge) {
if (periodDueDate.isEqual(loanChargePerInstallment.getRepaymentInstallment().getDueDate())) {
if (DateUtils.isEqual(periodDueDate, loanChargePerInstallment.getRepaymentInstallment().getDueDate())) {
return loanChargePerInstallment;
}
}
@@ -974,8 +972,9 @@ public class LoanCharge extends AbstractAuditableWithUTCDateTimeCustom {
Money outstanding = Money.of(currency, loanChargePerInstallment.getAmountOutstanding());
final boolean partiallyPaid = outstanding.isGreaterThanZero()
&& outstanding.isLessThan(loanChargePerInstallment.getAmount(currency));
if ((partiallyPaid || loanChargePerInstallment.isPaid()) && (paidChargePerInstallment == null || paidChargePerInstallment
.getRepaymentInstallment().getDueDate().isBefore(loanChargePerInstallment.getRepaymentInstallment().getDueDate()))) {
if ((partiallyPaid || loanChargePerInstallment.isPaid()) && (paidChargePerInstallment == null
|| DateUtils.isBefore(paidChargePerInstallment.getRepaymentInstallment().getDueDate(),
loanChargePerInstallment.getRepaymentInstallment().getDueDate()))) {
paidChargePerInstallment = loanChargePerInstallment;
}
}
@@ -27,6 +27,7 @@ import java.math.BigDecimal;
import java.time.LocalDate;
import java.util.Objects;
import org.apache.fineract.infrastructure.core.domain.AbstractPersistableCustom;
import org.apache.fineract.infrastructure.core.service.DateUtils;
import org.apache.fineract.portfolio.loanaccount.data.DisbursementData;
@Entity
@@ -71,16 +72,11 @@ public class LoanDisbursementDetails extends AbstractPersistableCustom {
@Override
public boolean equals(final Object obj) {
if (!(obj instanceof LoanDisbursementDetails)) {
if (!(obj instanceof LoanDisbursementDetails loanDisbursementDetails)) {
return false;
}
final LoanDisbursementDetails loanDisbursementDetails = (LoanDisbursementDetails) obj;
if (loanDisbursementDetails.principal.equals(this.principal)
&& loanDisbursementDetails.expectedDisbursementDate.compareTo(this.expectedDisbursementDate) == 0 ? Boolean.TRUE
: Boolean.FALSE) {
return true;
}
return false;
return loanDisbursementDetails.principal.equals(this.principal)
&& DateUtils.isEqual(loanDisbursementDetails.expectedDisbursementDate, this.expectedDisbursementDate);
}
@Override
@@ -22,6 +22,7 @@ import java.math.BigDecimal;
import java.time.LocalDate;
import java.util.List;
import java.util.Set;
import org.apache.fineract.infrastructure.core.service.DateUtils;
import org.apache.fineract.organisation.monetary.domain.MonetaryCurrency;
import org.apache.fineract.organisation.monetary.domain.Money;
@@ -114,7 +115,7 @@ public class LoanRepaymentScheduleProcessingWrapper {
if (loanCharge.getLoan() != null && loanCharge.isSpecifiedDueDate()
&& loanCharge.getLoan().isMultiDisburmentLoan()) {
for (final LoanDisbursementDetails loanDisbursementDetails : loanCharge.getLoan().getDisbursementDetails()) {
if (!loanDisbursementDetails.expectedDisbursementDate().isAfter(loanCharge.getDueDate())) {
if (!DateUtils.isAfter(loanDisbursementDetails.expectedDisbursementDate(), loanCharge.getDueDate())) {
amount = amount.add(loanDisbursementDetails.principal());
}
}
@@ -21,6 +21,7 @@ package org.apache.fineract.portfolio.loanaccount.domain;
import java.time.LocalDate;
import java.util.List;
import java.util.Set;
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.springframework.stereotype.Component;
@@ -230,7 +231,7 @@ public final class LoanSummaryWrapper {
if (totalOverdue.isGreaterThanZero()) {
for (final LoanRepaymentScheduleInstallment installment : repaymentScheduleInstallments) {
if (installment.isOverdueOn(from)) {
if (overdueSince == null || overdueSince.isAfter(installment.getDueDate())) {
if (overdueSince == null || DateUtils.isAfter(overdueSince, installment.getDueDate())) {
overdueSince = installment.getDueDate();
}
}
@@ -29,7 +29,6 @@ import jakarta.persistence.Table;
import jakarta.persistence.UniqueConstraint;
import java.math.BigDecimal;
import java.time.LocalDate;
import java.time.OffsetDateTime;
import java.util.ArrayList;
import java.util.Collection;
import java.util.HashSet;
@@ -850,29 +849,6 @@ public class LoanTransaction extends AbstractAuditableWithUTCDateTimeCustom {
this.manuallyAdjustedOrReversed = true;
}
@Override
public OffsetDateTime getCreatedDateTime() {
return (this.getCreatedDate().isPresent() ? this.getCreatedDate().get() : DateUtils.getOffsetDateTimeOfTenantWithMostPrecision());
}
public boolean isLastTransaction(final LoanTransaction loanTransaction) {
boolean isLatest = false;
if (loanTransaction != null) {
isLatest = this.getTransactionDate().isBefore(loanTransaction.getTransactionDate())
|| (this.getTransactionDate().isEqual(loanTransaction.getTransactionDate())
&& this.getCreatedDateTime().isBefore(loanTransaction.getCreatedDateTime()));
}
return isLatest;
}
public boolean isLatestTransaction(final LoanTransaction loanTransaction) {
boolean isLatest = false;
if (loanTransaction != null) {
isLatest = this.getCreatedDateTime().isBefore(loanTransaction.getCreatedDateTime());
}
return isLatest;
}
public void updateLoanTransactionToRepaymentScheduleMappings(final Collection<LoanTransactionToRepaymentScheduleMapping> mappings) {
Collection<LoanTransactionToRepaymentScheduleMapping> retainMappings = new ArrayList<>();
for (LoanTransactionToRepaymentScheduleMapping updatedrepaymentScheduleMapping : mappings) {
@@ -963,6 +939,18 @@ public class LoanTransaction extends AbstractAuditableWithUTCDateTimeCustom {
return amount;
}
public boolean isBefore(final LocalDate date) {
return DateUtils.isBefore(getTransactionDate(), date);
}
public boolean isAfter(final LocalDate date) {
return DateUtils.isAfter(getTransactionDate(), date);
}
public boolean isOn(final LocalDate date) {
return DateUtils.isEqual(getTransactionDate(), date);
}
// TODO missing hashCode(), equals(Object obj), but probably OK as long as
// this is never stored in a Collection.
}
@@ -19,47 +19,40 @@
package org.apache.fineract.portfolio.loanaccount.domain;
import java.util.Comparator;
import org.apache.fineract.infrastructure.core.service.DateUtils;
/**
* Sort loan transactions by transaction date, created date and transaction type placing
*/
public class LoanTransactionComparator implements Comparator<LoanTransaction> {
public static final LoanTransactionComparator INSTANCE = new LoanTransactionComparator();
@Override
public int compare(final LoanTransaction o1, final LoanTransaction o2) {
int compareResult = 0;
final int comparsion = o1.getTransactionDate().compareTo(o2.getTransactionDate());
/**
* For transactions bearing the same transaction date, we sort transactions based on created date (when
* available) after which sorting for waivers takes place
**/
if (comparsion == 0) {
int comparisonBasedOnCreatedDate = 0;
if (o1.isIncomePosting() && o2.isNotIncomePosting()) {
compareResult = -1;
} else if (o1.isNotIncomePosting() && o2.isIncomePosting()) {
compareResult = 1;
} else {
compareResult = 0;
}
if (o1.getCreatedDateTime() != null && o2.getCreatedDateTime() != null) {
comparisonBasedOnCreatedDate = o1.getCreatedDateTime().compareTo(o2.getCreatedDateTime());
}
// equal transaction dates
if (comparisonBasedOnCreatedDate == 0) {
if (o1.isWaiver() && o2.isNotWaiver()) {
compareResult = -1;
} else if (o1.isNotWaiver() && o2.isWaiver()) {
compareResult = 1;
} else {
compareResult = 0;
}
}
} else {
compareResult = comparsion;
int result = DateUtils.compare(o1.getTransactionDate(), o2.getTransactionDate());
if (result != 0) {
return result;
}
return compareResult;
// 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);
if (result != 0) {
return result;
}
// equal transaction dates
if (o1.isIncomePosting() != o2.isIncomePosting()) {
return o1.isIncomePosting() ? -1 : 1;
}
if (o1.isWaiver() != o2.isWaiver()) {
return o1.isWaiver() ? -1 : 1;
}
result = o1.getId() != null ? (o2.getId() != null ? Long.compare(o1.getId(), o2.getId()) : -1) : (o2.getId() != null ? 1 : 0);
if (result != 0) {
return result;
}
return 0;
}
}
@@ -200,11 +200,7 @@ public final class LoanSchedulePeriodData {
this.totalOutstandingForPeriod = this.feeChargesOutstanding;
this.totalActualCostOfLoanForPeriod = this.feeChargesDue;
this.totalInstallmentAmountForPeriod = null;
if (dueDate.isBefore(DateUtils.getBusinessLocalDate())) {
this.totalOverdue = this.totalOutstandingForPeriod;
} else {
this.totalOverdue = null;
}
this.totalOverdue = DateUtils.isBeforeBusinessDate(dueDate) ? this.totalOutstandingForPeriod : null;
this.totalCredits = BigDecimal.ZERO;
this.downPaymentPeriod = false;
}
@@ -263,12 +259,7 @@ public final class LoanSchedulePeriodData {
this.totalOutstandingForPeriod = totalDueForPeriod;
this.totalActualCostOfLoanForPeriod = interestDueOnPrincipalOutstanding.add(feeChargesDueForPeriod);
this.totalInstallmentAmountForPeriod = totalInstallmentAmountForPeriod;
if (dueDate.isBefore(DateUtils.getBusinessLocalDate())) {
this.totalOverdue = this.totalOutstandingForPeriod;
} else {
this.totalOverdue = null;
}
this.totalOverdue = DateUtils.isBeforeBusinessDate(dueDate) ? this.totalOutstandingForPeriod : null;
this.totalCredits = BigDecimal.ZERO;
this.downPaymentPeriod = false;
}
@@ -322,12 +313,7 @@ public final class LoanSchedulePeriodData {
this.totalOutstandingForPeriod = totalDueForPeriod;
this.totalActualCostOfLoanForPeriod = null;
this.totalInstallmentAmountForPeriod = totalDueForPeriod;
if (dueDate.isBefore(DateUtils.getBusinessLocalDate())) {
this.totalOverdue = this.totalOutstandingForPeriod;
} else {
this.totalOverdue = null;
}
this.totalOverdue = DateUtils.isBeforeBusinessDate(dueDate) ? this.totalOutstandingForPeriod : null;
this.totalCredits = BigDecimal.ZERO;
this.downPaymentPeriod = true;
}
@@ -396,12 +382,7 @@ public final class LoanSchedulePeriodData {
this.totalOutstandingForPeriod = totalOutstanding;
this.totalActualCostOfLoanForPeriod = totalActualCostOfLoanForPeriod;
this.totalInstallmentAmountForPeriod = totalInstallmentAmountForPeriod;
if (dueDate.isBefore(DateUtils.getBusinessLocalDate())) {
this.totalOverdue = this.totalOutstandingForPeriod;
} else {
this.totalOverdue = null;
}
this.totalOverdue = DateUtils.isBeforeBusinessDate(dueDate) ? this.totalOutstandingForPeriod : null;
this.totalCredits = totalCredits;
this.downPaymentPeriod = isDownPayment;
}
@@ -18,6 +18,7 @@
*/
package org.apache.fineract.portfolio.loanaccount.loanschedule.domain;
import jakarta.validation.constraints.NotNull;
import java.math.BigDecimal;
import java.math.MathContext;
import java.time.LocalDate;
@@ -26,6 +27,7 @@ import java.util.HashSet;
import java.util.List;
import java.util.Set;
import lombok.extern.slf4j.Slf4j;
import org.apache.fineract.infrastructure.core.service.DateUtils;
import org.apache.fineract.organisation.monetary.domain.ApplicationCurrency;
import org.apache.fineract.organisation.monetary.domain.MonetaryCurrency;
import org.apache.fineract.organisation.monetary.domain.Money;
@@ -716,7 +718,7 @@ public final class LoanApplicationTerms {
// number of days from 'ideal disbursement' to final date
LocalDate loanStartDate = getExpectedDisbursementDate();
if (getInterestChargedFromDate() != null && loanStartDate.isBefore(getInterestChargedFromLocalDate())) {
if (DateUtils.isBefore(loanStartDate, getInterestChargedFromLocalDate())) {
loanStartDate = getInterestChargedFromLocalDate();
}
@@ -773,7 +775,7 @@ public final class LoanApplicationTerms {
CalendarUtils.getMeetingFrequencyFromPeriodFrequencyType(getLoanTermPeriodFrequencyType()),
this.holidayDetailDTO.getWorkingDays(), isSkipRepaymentOnFirstDayOfMonth, numberOfDays);
}
if (!expectedStartDate.isEqual(startDate)) {
if (!DateUtils.isEqual(expectedStartDate, startDate)) {
diffDays = Math.toIntExact(ChronoUnit.DAYS.between(startDate, expectedStartDate));
}
if (numberOfMonths == 0) {
@@ -1368,6 +1370,7 @@ public final class LoanApplicationTerms {
return this.multiDisburseLoan;
}
@NotNull
public Money getMaxOutstandingBalance() {
return Money.of(getCurrency(), this.maxOutstandingBalance);
}
@@ -1440,7 +1443,7 @@ public final class LoanApplicationTerms {
int months = getPeriodsBetween(fromDate, toDate);
fromDate = fromDate.plusMonths(months);
isSameAsRepaymentPeriod = fromDate.isEqual(toDate);
isSameAsRepaymentPeriod = DateUtils.isEqual(fromDate, toDate);
}
break;
@@ -59,6 +59,7 @@ import org.apache.fineract.accounting.producttoaccountmapping.domain.ProductToGL
import org.apache.fineract.accounting.producttoaccountmapping.exception.ProductToGLAccountMappingNotFoundException;
import org.apache.fineract.infrastructure.core.data.EnumOptionData;
import org.apache.fineract.infrastructure.core.exception.PlatformDataIntegrityException;
import org.apache.fineract.infrastructure.core.service.DateUtils;
import org.apache.fineract.infrastructure.event.business.domain.journalentry.LoanJournalEntryCreatedBusinessEvent;
import org.apache.fineract.infrastructure.event.business.service.BusinessEventNotifierService;
import org.apache.fineract.organisation.office.domain.Office;
@@ -502,12 +503,9 @@ public class AccountingProcessorHelper {
* @param transactionDate
*/
public void checkForBranchClosures(final GLClosure latestGLClosure, final LocalDate transactionDate) {
/**
* check if an accounting closure has happened for this branch after the transaction Date
**/
// check if an accounting closure has happened for this branch after the transaction Date
if (latestGLClosure != null) {
if (latestGLClosure.getClosingDate().isAfter(transactionDate)
|| latestGLClosure.getClosingDate().compareTo(transactionDate) == 0 ? Boolean.TRUE : Boolean.FALSE) {
if (!DateUtils.isBefore(latestGLClosure.getClosingDate(), transactionDate)) {
throw new JournalEntryInvalidException(GlJournalEntryInvalidReason.ACCOUNTING_CLOSED, latestGLClosure.getClosingDate(),
null, null);
}
@@ -175,8 +175,7 @@ public class JournalEntryRunningBalanceUpdateServiceImpl implements JournalEntry
BigDecimal runningBalance = calculateRunningBalance(entryData, runningBalanceMap);
params.add(new Object[] { Boolean.TRUE, runningBalance, officeRunningBalance,
platformSecurityContext.authenticatedUser().getId(), DateUtils.getOffsetDateTimeOfTenantWithMostPrecision(),
entryData.getId() });
platformSecurityContext.authenticatedUser().getId(), DateUtils.getAuditOffsetDateTime(), entryData.getId() });
batchIndex++;
if (batchIndex == batchUpdateSize || index == entryDataList.size() - 1) {
this.jdbcTemplate.batchUpdate(sql, params);
@@ -213,7 +212,7 @@ public class JournalEntryRunningBalanceUpdateServiceImpl implements JournalEntry
for (JournalEntryData entryData : entryDataList) {
BigDecimal runningBalance = calculateRunningBalance(entryData, runningBalanceMap);
params.add(new Object[] { runningBalance, platformSecurityContext.authenticatedUser().getId(),
DateUtils.getOffsetDateTimeOfTenantWithMostPrecision(), entryData.getId() });
DateUtils.getAuditOffsetDateTime(), entryData.getId() });
}
this.jdbcTemplate.batchUpdate(sql, params);
}
@@ -314,9 +314,7 @@ public class JournalEntryWritePlatformServiceJpaRepositoryImpl implements Journa
final LocalDate journalEntriesTransactionDate = journalEntries.get(0).getTransactionDate();
final GLClosure latestGLClosureByBranch = this.glClosureRepository.getLatestGLClosureByBranch(officeId);
if (latestGLClosureByBranch != null) {
if (latestGLClosureByBranch.getClosingDate().isAfter(journalEntriesTransactionDate)
|| latestGLClosureByBranch.getClosingDate().compareTo(journalEntriesTransactionDate) == 0 ? Boolean.TRUE
: Boolean.FALSE) {
if (!DateUtils.isBefore(latestGLClosureByBranch.getClosingDate(), journalEntriesTransactionDate)) {
final String accountName = null;
final String accountGLCode = null;
throw new JournalEntryInvalidException(GlJournalEntryInvalidReason.ACCOUNTING_CLOSED,
@@ -555,24 +553,22 @@ public class JournalEntryWritePlatformServiceJpaRepositoryImpl implements Journa
}
private void validateBusinessRulesForJournalEntries(final JournalEntryCommand command) {
/** check if date of Journal entry is valid ***/
// check if date of Journal entry is valid
final LocalDate transactionDate = command.getTransactionDate();
// shouldn't be in the future
final LocalDate todaysDate = DateUtils.getBusinessLocalDate();
if (transactionDate.isAfter(todaysDate)) {
if (DateUtils.isDateInTheFuture(transactionDate)) {
throw new JournalEntryInvalidException(GlJournalEntryInvalidReason.FUTURE_DATE, transactionDate, null, null);
}
// shouldn't be before an accounting closure
final GLClosure latestGLClosure = this.glClosureRepository.getLatestGLClosureByBranch(command.getOfficeId());
if (latestGLClosure != null) {
if (latestGLClosure.getClosingDate().isAfter(transactionDate)
|| latestGLClosure.getClosingDate().compareTo(transactionDate) == 0 ? Boolean.TRUE : Boolean.FALSE) {
if (!DateUtils.isBefore(latestGLClosure.getClosingDate(), transactionDate)) {
throw new JournalEntryInvalidException(GlJournalEntryInvalidReason.ACCOUNTING_CLOSED, latestGLClosure.getClosingDate(),
null, null);
}
}
/*** check if credits and debits are valid **/
// check if credits and debits are valid
final SingleDebitOrCreditEntryCommand[] credits = command.getCredits();
final SingleDebitOrCreditEntryCommand[] debits = command.getDebits();
@@ -43,6 +43,7 @@ import org.apache.fineract.infrastructure.core.api.JsonCommand;
import org.apache.fineract.infrastructure.core.data.CommandProcessingResult;
import org.apache.fineract.infrastructure.core.data.CommandProcessingResultBuilder;
import org.apache.fineract.infrastructure.core.serialization.FromJsonHelper;
import org.apache.fineract.infrastructure.core.service.DateUtils;
import org.apache.fineract.infrastructure.security.service.PlatformSecurityContext;
import org.apache.fineract.organisation.monetary.domain.MonetaryCurrency;
import org.apache.fineract.organisation.monetary.domain.Money;
@@ -107,7 +108,7 @@ public class ProvisioningEntriesWritePlatformServiceJpaRepositoryImpl implements
private void validateForCreateJournalEntry(ProvisioningEntryData existingEntry, ProvisioningEntry requested) {
LocalDate existingDate = existingEntry.getCreatedDate();
LocalDate requestedDate = requested.getCreatedDate();
if (existingDate.isAfter(requestedDate) || existingDate.compareTo(requestedDate) == 0 ? Boolean.TRUE : Boolean.FALSE) {
if (!DateUtils.isBefore(existingDate, requestedDate)) {
throw new ProvisioningJournalEntriesCannotbeCreatedException(existingEntry.getCreatedDate(), requestedDate);
}
}
@@ -64,7 +64,7 @@ public class LoanAccountLock {
public LoanAccountLock(Long loanId, LockOwner lockOwner, LocalDate lockPlacedOnCobBusinessDate) {
this.loanId = loanId;
this.lockOwner = lockOwner;
this.lockPlacedOn = DateUtils.getOffsetDateTimeOfTenantWithMostPrecision();
this.lockPlacedOn = DateUtils.getAuditOffsetDateTime();
this.lockPlacedOnCobBusinessDate = lockPlacedOnCobBusinessDate;
}
@@ -75,6 +75,6 @@ public class LoanAccountLock {
public void setNewLockOwner(LockOwner newLockOwner) {
this.lockOwner = newLockOwner;
this.lockPlacedOn = DateUtils.getOffsetDateTimeOfTenantWithMostPrecision();
this.lockPlacedOn = DateUtils.getAuditOffsetDateTime();
}
}
@@ -81,8 +81,8 @@ public class LoanCOBPartitioner implements Partitioner {
}
StopWatch sw = new StopWatch();
sw.start();
List<LoanCOBPartition> loanCOBPartitions = new ArrayList<>(retrieveLoanIdService.retrieveLoanCOBPartitions(numberOfDays,
businessDate, isCatchUp != null ? isCatchUp : false, partitionSize));
List<LoanCOBPartition> loanCOBPartitions = new ArrayList<>(
retrieveLoanIdService.retrieveLoanCOBPartitions(numberOfDays, businessDate, isCatchUp != null && isCatchUp, partitionSize));
sw.stop();
// if there is no loan to be closed, we still would like to create at least one partition
@@ -67,7 +67,7 @@ public class LoanLockingServiceImpl implements LoanLockingService {
UPDATE m_loan_account_locks SET version= version + 1, lock_owner = ?, lock_placed_on = ? WHERE loan_id = ?
""", accountsToLock, getInClauseParameterSizeLimit(), (ps, id) -> {
ps.setString(1, lockOwner.name());
ps.setObject(2, DateUtils.getOffsetDateTimeOfTenantWithMostPrecision());
ps.setObject(2, DateUtils.getAuditOffsetDateTime());
ps.setLong(3, id);
});
}
@@ -97,7 +97,7 @@ public class LoanLockingServiceImpl implements LoanLockingService {
ps.setLong(1, loanId);
ps.setLong(2, 1);
ps.setString(3, lockOwner.name());
ps.setObject(4, DateUtils.getOffsetDateTimeOfTenantWithMostPrecision());
ps.setObject(4, DateUtils.getAuditOffsetDateTime());
ps.setObject(5, cobBusinessDate);
});
}
@@ -32,6 +32,7 @@ import org.apache.fineract.cob.loan.RetrieveLoanIdService;
import org.apache.fineract.infrastructure.businessdate.domain.BusinessDateType;
import org.apache.fineract.infrastructure.core.config.TaskExecutorConstant;
import org.apache.fineract.infrastructure.core.domain.FineractContext;
import org.apache.fineract.infrastructure.core.service.DateUtils;
import org.apache.fineract.infrastructure.core.service.ThreadLocalContextUtil;
import org.apache.fineract.infrastructure.jobs.data.JobParameterDTO;
import org.apache.fineract.infrastructure.jobs.domain.JobParameterRepository;
@@ -73,7 +74,7 @@ public class AsyncLoanCOBExecutorServiceImpl implements AsyncLoanCOBExecutorServ
LocalDate oldestCOBProcessedDate = !loanIdAndLastClosedBusinessDate.isEmpty()
? loanIdAndLastClosedBusinessDate.get(0).getLastClosedBusinessDate()
: cobBusinessDate;
if (oldestCOBProcessedDate.isBefore(cobBusinessDate)) {
if (DateUtils.isBefore(oldestCOBProcessedDate, cobBusinessDate)) {
executeLoanCOBDayByDayUntilCOBBusinessDate(oldestCOBProcessedDate, cobBusinessDate);
}
} catch (NoSuchJobException e) {
@@ -92,7 +93,7 @@ public class AsyncLoanCOBExecutorServiceImpl implements AsyncLoanCOBExecutorServ
Job job = jobLocator.getJob(LoanCOBConstant.JOB_NAME);
ScheduledJobDetail scheduledJobDetail = scheduledJobDetailRepository.findByJobName(LoanCOBConstant.JOB_HUMAN_READABLE_NAME);
LocalDate executingBusinessDate = oldestCOBProcessedDate.plusDays(1);
while (!executingBusinessDate.isAfter(cobBusinessDate)) {
while (!DateUtils.isAfter(executingBusinessDate, cobBusinessDate)) {
JobParameterDTO jobParameterDTO = new JobParameterDTO(LoanCOBConstant.BUSINESS_DATE_PARAMETER_NAME,
executingBusinessDate.format(DateTimeFormatter.ISO_DATE));
JobParameterDTO jobParameterCatchUpDTO = new JobParameterDTO(LoanCOBConstant.IS_CATCH_UP_PARAMETER_NAME, "true");
@@ -51,6 +51,7 @@ import org.apache.fineract.infrastructure.core.data.CommandProcessingResultBuild
import org.apache.fineract.infrastructure.core.exception.PlatformInternalServerException;
import org.apache.fineract.infrastructure.core.exception.PlatformRequestBodyItemLimitValidationException;
import org.apache.fineract.infrastructure.core.serialization.GoogleGsonSerializerHelper;
import org.apache.fineract.infrastructure.core.service.DateUtils;
import org.apache.fineract.infrastructure.core.service.ThreadLocalContextUtil;
import org.apache.fineract.infrastructure.jobs.data.JobParameterDTO;
import org.apache.fineract.infrastructure.jobs.domain.CustomJobParameterRepository;
@@ -112,7 +113,7 @@ public class InlineLoanCOBExecutorServiceImpl implements InlineExecutorService<L
List<LoanIdAndLastClosedBusinessDate> loansToBeProcessed = getLoansToBeProcessed(loanIds, cobBusinessDate);
LocalDate executingBusinessDate = getOldestCOBBusinessDate(loansToBeProcessed).plusDays(1);
if (!loansToBeProcessed.isEmpty()) {
while (!executingBusinessDate.isAfter(cobBusinessDate)) {
while (!DateUtils.isAfter(executingBusinessDate, cobBusinessDate)) {
execute(getLoanIdsToBeProcessed(loansToBeProcessed, executingBusinessDate), jobName, executingBusinessDate);
executingBusinessDate = executingBusinessDate.plusDays(1);
}
@@ -123,7 +124,7 @@ public class InlineLoanCOBExecutorServiceImpl implements InlineExecutorService<L
List<Long> loanIdsToBeProcessed = new ArrayList<>();
loansToBeProcessed.forEach(loan -> {
if (loan.getLastClosedBusinessDate() != null) {
if (loan.getLastClosedBusinessDate().isBefore(executingBusinessDate)) {
if (DateUtils.isBefore(loan.getLastClosedBusinessDate(), executingBusinessDate)) {
loanIdsToBeProcessed.add(loan.getId());
}
} else {
@@ -73,7 +73,7 @@ public class ImportDocument extends AbstractPersistableCustom {
final Boolean completed = Boolean.FALSE;
final Integer successCount = 0;
final Integer failureCount = 0;
final LocalDateTime endTime = LocalDateTime.now(DateUtils.getDateTimeZoneOfTenant());
final LocalDateTime endTime = DateUtils.getLocalDateTimeOfTenant();
return new ImportDocument(document, importTime, endTime, completed, entityType, createdBy, totalRecords, successCount,
failureCount);
@@ -145,8 +145,7 @@ public final class ImportHandlerUtils {
return null;
}
LocalDate localDate = LocalDate.ofInstant(c.getDateCellValue().toInstant(), DateUtils.getDateTimeZoneOfTenant());
return localDate;
return LocalDate.ofInstant(c.getDateCellValue().toInstant(), DateUtils.getDateTimeZoneOfTenant());
}
public static Boolean readAsBoolean(int colIndex, Row row) {
@@ -101,8 +101,7 @@ public class SharedProductsSheetPopulator extends AbstractWorkbookPopulator {
if (marketDataSet != null && !marketDataSet.isEmpty()) {
LocalDate currentDate = DateUtils.getBusinessLocalDate();
for (ShareProductMarketPriceData data : marketDataSet) {
LocalDate futureDate = data.getFromDate();
if (currentDate.isAfter(futureDate)) {
if (DateUtils.isBefore(data.getFromDate(), currentDate)) {
marketValue = data.getShareValue();
}
}
@@ -160,7 +160,7 @@ public class EmailCampaign extends AbstractPersistableCustom {
final Locale locale = command.extractLocale();
final DateTimeFormatter fmt = DateTimeFormatter.ofPattern(command.dateFormat()).withLocale(locale);
LocalDateTime recurrenceStartDate = LocalDateTime.now(DateUtils.getDateTimeZoneOfTenant());
LocalDateTime recurrenceStartDate = DateUtils.getLocalDateTimeOfTenant();
if (EmailCampaignType.fromInt(campaignType.intValue()).isSchedule()) {
if (command.hasParameter(EmailCampaignValidator.recurrenceStartDate)) {
recurrenceStartDate = LocalDateTime.parse(command.stringValueOfParameterNamed(EmailCampaignValidator.recurrenceStartDate),
@@ -178,7 +178,6 @@ public class EmailCampaign extends AbstractPersistableCustom {
}
public Map<String, Object> update(JsonCommand command) {
final Map<String, Object> actualChanges = new LinkedHashMap<>(5);
if (command.isChangeInStringParameterNamed(EmailCampaignValidator.campaignName, this.campaignName)) {
@@ -229,7 +228,6 @@ public class EmailCampaign extends AbstractPersistableCustom {
}
public void activate(final AppUser currentUser, final DateTimeFormatter formatter, final LocalDate activationLocalDate) {
if (isActive()) {
// handle errors if already activated
final String defaultUserMessage = "Cannot activate campaign. Campaign is already active.";
@@ -271,14 +269,13 @@ public class EmailCampaign extends AbstractPersistableCustom {
}
public void reactivate(final AppUser currentUser, final DateTimeFormatter dateTimeFormat, final LocalDate reactivateLocalDate) {
if (!isClosed()) {
// handle errors if already activated
final String defaultUserMessage = "Cannot reactivate campaign. Campaign must be in closed state.";
final ApiParameterError error = ApiParameterError.parameterError("error.msg.campaign.must.be.closed", defaultUserMessage,
EmailCampaignValidator.statusParamName, EmailCampaignStatus.fromInt(this.status).getCode());
final List<ApiParameterError> dataValidationErrors = new ArrayList<ApiParameterError>();
final List<ApiParameterError> dataValidationErrors = new ArrayList<>();
dataValidationErrors.add(error);
throw new PlatformApiDataValidationException(dataValidationErrors);
@@ -352,55 +349,45 @@ public class EmailCampaign extends AbstractPersistableCustom {
}
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.campaign.submittedOnDate.in.the.future",
defaultUserMessage, EmailCampaignValidator.submittedOnDateParamName, this.submittedOnDate);
dataValidationErrors.add(error);
}
if (getApprovedOnDate() != null && getSubmittedOnDate() != null && getSubmittedOnDate().isAfter(getApprovedOnDate())) {
if (getApprovedOnDate() != null && DateUtils.isAfter(getSubmittedOnDate(), getApprovedOnDate())) {
final String defaultUserMessage = "submitted date cannot be after the activation date";
final ApiParameterError error = ApiParameterError.parameterError("error.msg.campaign.submittedOnDate.after.activation.date",
defaultUserMessage, EmailCampaignValidator.submittedOnDateParamName, this.submittedOnDate);
dataValidationErrors.add(error);
}
if (getApprovedOnDate() != null && isDateInTheFuture(getApprovedOnDate())) {
if (DateUtils.isDateInTheFuture(getApprovedOnDate())) {
final String defaultUserMessage = "Activation date cannot be in the future.";
final ApiParameterError error = ApiParameterError.parameterError("error.msg.campaign.activationDate.in.the.future",
defaultUserMessage, EmailCampaignValidator.activationDateParamName, getApprovedOnDate());
dataValidationErrors.add(error);
}
}
private void validateReactivationDate(final List<ApiParameterError> dataValidationErrors) {
if (getApprovedOnDate() != null && isDateInTheFuture(getApprovedOnDate())) {
if (DateUtils.isDateInTheFuture(getApprovedOnDate())) {
final String defaultUserMessage = "Activation date cannot be in the future.";
final ApiParameterError error = ApiParameterError.parameterError("error.msg.campaign.activationDate.in.the.future",
defaultUserMessage, EmailCampaignValidator.activationDateParamName, getApprovedOnDate());
dataValidationErrors.add(error);
}
if (getApprovedOnDate() != null && getSubmittedOnDate() != null && getSubmittedOnDate().isAfter(getApprovedOnDate())) {
if (getApprovedOnDate() != null && DateUtils.isAfter(getSubmittedOnDate(), getApprovedOnDate())) {
final String defaultUserMessage = "submitted date cannot be after the activation date";
final ApiParameterError error = ApiParameterError.parameterError("error.msg.campaign.submittedOnDate.after.activation.date",
defaultUserMessage, EmailCampaignValidator.submittedOnDateParamName, this.submittedOnDate);
dataValidationErrors.add(error);
}
if (getSubmittedOnDate() != null && isDateInTheFuture(getSubmittedOnDate())) {
if (DateUtils.isDateInTheFuture(getSubmittedOnDate())) {
final String defaultUserMessage = "submitted date cannot be in the future.";
final ApiParameterError error = ApiParameterError.parameterError("error.msg.campaign.submittedOnDate.in.the.future",
defaultUserMessage, EmailCampaignValidator.submittedOnDateParamName, this.submittedOnDate);
@@ -411,7 +398,7 @@ public class EmailCampaign extends AbstractPersistableCustom {
}
private void validateClosureDate(final List<ApiParameterError> dataValidationErrors) {
if (getClosureDate() != null && isDateInTheFuture(getClosureDate())) {
if (getClosureDate() != null && DateUtils.isDateInTheFuture(getClosureDate())) {
final String defaultUserMessage = "closure date cannot be in the future.";
final ApiParameterError error = ApiParameterError.parameterError("error.msg.campaign.closureDate.in.the.future",
defaultUserMessage, EmailCampaignValidator.closureDateParamName, this.closureDate);
@@ -419,9 +406,4 @@ public class EmailCampaign extends AbstractPersistableCustom {
dataValidationErrors.add(error);
}
}
private boolean isDateInTheFuture(final LocalDate localDate) {
return localDate.isAfter(DateUtils.getBusinessLocalDate());
}
}
@@ -31,7 +31,6 @@ import java.io.StringReader;
import java.io.StringWriter;
import java.time.LocalDate;
import java.time.LocalDateTime;
import java.time.ZoneId;
import java.time.format.DateTimeFormatter;
import java.time.format.DateTimeFormatterBuilder;
import java.util.ArrayList;
@@ -56,11 +55,9 @@ import org.apache.fineract.infrastructure.core.api.JsonCommand;
import org.apache.fineract.infrastructure.core.api.JsonQuery;
import org.apache.fineract.infrastructure.core.data.CommandProcessingResult;
import org.apache.fineract.infrastructure.core.data.CommandProcessingResultBuilder;
import org.apache.fineract.infrastructure.core.domain.FineractPlatformTenant;
import org.apache.fineract.infrastructure.core.exception.PlatformDataIntegrityException;
import org.apache.fineract.infrastructure.core.serialization.FromJsonHelper;
import org.apache.fineract.infrastructure.core.service.DateUtils;
import org.apache.fineract.infrastructure.core.service.ThreadLocalContextUtil;
import org.apache.fineract.infrastructure.dataqueries.data.GenericResultsetData;
import org.apache.fineract.infrastructure.dataqueries.domain.Report;
import org.apache.fineract.infrastructure.dataqueries.domain.ReportParameterUsage;
@@ -98,7 +95,6 @@ public class EmailCampaignWritePlatformCommandHandlerImpl implements EmailCampai
@Transactional
@Override
public CommandProcessingResult create(JsonCommand command) {
final AppUser currentUser = this.context.authenticatedUser();
this.emailCampaignValidator.validateCreate(command.json());
@@ -286,24 +282,21 @@ public class EmailCampaignWritePlatformCommandHandlerImpl implements EmailCampai
if (emailCampaign.isDirect()) {
insertDirectCampaignIntoEmailOutboundTable(emailCampaign.getParamValue(), emailCampaign.getEmailSubject(),
emailCampaign.getEmailMessage(), emailCampaign.getCampaignName(), emailCampaign.getId());
} else {
if (emailCampaign.isSchedule()) {
/**
* if recurrence start date is in the future calculate next trigger date if not use recurrence start
* date us next trigger date when activating
*/
LocalDateTime nextTriggerDateWithTime;
if (emailCampaign.getRecurrenceStartDate().isBefore(tenantDateTime())) {
nextTriggerDateWithTime = CalendarUtils.getNextRecurringDate(emailCampaign.getRecurrence(),
emailCampaign.getRecurrenceStartDate(), DateUtils.getLocalDateTimeOfTenant());
} else {
nextTriggerDateWithTime = emailCampaign.getRecurrenceStartDate();
}
emailCampaign.setNextTriggerDate(nextTriggerDateWithTime);
this.emailCampaignRepository.saveAndFlush(emailCampaign);
} else if (emailCampaign.isSchedule()) {
// if recurrence start date is in the past, calculate next trigger date, otherwise use recurrence start
// date as next trigger date when activating
LocalDateTime nextTriggerDateWithTime;
LocalDateTime recurrenceStartDate = emailCampaign.getRecurrenceStartDate();
LocalDateTime tenantDateTime = DateUtils.getLocalDateTimeOfTenant();
if (DateUtils.isBefore(recurrenceStartDate, tenantDateTime)) {
nextTriggerDateWithTime = CalendarUtils.getNextRecurringDate(emailCampaign.getRecurrence(), recurrenceStartDate,
tenantDateTime);
} else {
nextTriggerDateWithTime = recurrenceStartDate;
}
emailCampaign.setNextTriggerDate(nextTriggerDateWithTime);
this.emailCampaignRepository.saveAndFlush(emailCampaign);
}
/*
@@ -420,7 +413,6 @@ public class EmailCampaignWritePlatformCommandHandlerImpl implements EmailCampai
@Transactional
@Override
public CommandProcessingResult reactivateEmailCampaign(final Long campaignId, JsonCommand command) {
this.emailCampaignValidator.validateActivation(command.json());
final AppUser currentUser = this.context.authenticatedUser();
@@ -433,23 +425,18 @@ public class EmailCampaignWritePlatformCommandHandlerImpl implements EmailCampai
final LocalDate reactivationDate = command.localDateValueOfParameterNamed("activationDate");
emailCampaign.reactivate(currentUser, fmt, reactivationDate);
if (emailCampaign.isSchedule()) {
/**
* if recurrence start date is in the future calculate next trigger date if not use recurrence start date us
* next trigger date when activating
*/
// if recurrence start date is in the past, calculate next trigger date, otherwise use recurrence start date
// as next trigger date when activating
LocalDateTime nextTriggerDate = null;
if (emailCampaign.getRecurrenceStartDate().isBefore(tenantDateTime())) {
nextTriggerDate = CalendarUtils.getNextRecurringDate(emailCampaign.getRecurrence(), emailCampaign.getRecurrenceStartDate(),
DateUtils.getLocalDateTimeOfTenant());
LocalDateTime tenantDateTime = DateUtils.getLocalDateTimeOfTenant();
LocalDateTime recurrenceStartDate = emailCampaign.getRecurrenceStartDate();
if (DateUtils.isBefore(recurrenceStartDate, tenantDateTime)) {
nextTriggerDate = CalendarUtils.getNextRecurringDate(emailCampaign.getRecurrence(), recurrenceStartDate, tenantDateTime);
} else {
nextTriggerDate = emailCampaign.getRecurrenceStartDate();
nextTriggerDate = recurrenceStartDate;
}
// to get time of tenant
final LocalDateTime getTime = emailCampaign.getRecurrenceStartDate();
final String dateString = nextTriggerDate.toString() + " " + getTime.getHour() + ":" + getTime.getMinute() + ":"
+ getTime.getSecond();
final String dateString = nextTriggerDate.toString() + " " + recurrenceStartDate.getHour() + ":"
+ recurrenceStartDate.getMinute() + ":" + recurrenceStartDate.getSecond();
final DateTimeFormatter simpleDateFormat = new DateTimeFormatterBuilder().parseCaseInsensitive().parseLenient()
.appendPattern("yyyy-MM-dd HH:mm:ss").toFormatter();
final LocalDateTime nextTriggerDateWithTime = LocalDateTime.parse(dateString, simpleDateFormat);
@@ -470,17 +457,4 @@ public class EmailCampaignWritePlatformCommandHandlerImpl implements EmailCampai
throw new PlatformDataIntegrityException("error.msg.email.campaign.unknown.data.integrity.issue",
"Unknown data integrity issue with resource: " + realCause.getMessage());
}
private LocalDateTime tenantDateTime() {
LocalDateTime today = LocalDateTime.now(DateUtils.getDateTimeZoneOfTenant());
final FineractPlatformTenant tenant = ThreadLocalContextUtil.getTenant();
if (tenant != null) {
final ZoneId zone = ZoneId.of(tenant.getTimezoneId());
if (zone != null) {
today = LocalDateTime.now(zone);
}
}
return today;
}
}
@@ -1,41 +0,0 @@
/**
* Licensed to the Apache Software Foundation (ASF) under one
* or more contributor license agreements. See the NOTICE file
* distributed with this work for additional information
* regarding copyright ownership. The ASF licenses this file
* to you under the Apache License, Version 2.0 (the
* "License"); you may not use this file except in compliance
* with the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing,
* software distributed under the License is distributed on an
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
* KIND, either express or implied. See the License for the
* specific language governing permissions and limitations
* under the License.
*/
package org.apache.fineract.infrastructure.campaigns.jobs;
import java.time.LocalDateTime;
import java.time.ZoneId;
import org.apache.fineract.infrastructure.core.domain.FineractPlatformTenant;
import org.apache.fineract.infrastructure.core.service.DateUtils;
import org.apache.fineract.infrastructure.core.service.ThreadLocalContextUtil;
public final class TenantDateTimeUtil {
private TenantDateTimeUtil() {}
public static LocalDateTime tenantDateTime() {
LocalDateTime today = LocalDateTime.now(DateUtils.getDateTimeZoneOfTenant());
final FineractPlatformTenant tenant = ThreadLocalContextUtil.getTenant();
if (tenant != null) {
final ZoneId zone = ZoneId.of(tenant.getTimezoneId());
today = LocalDateTime.now(zone);
}
return today;
}
}
@@ -80,7 +80,7 @@ public class ExecuteReportMailingJobsTasklet implements Tasklet {
final LocalDateTime localDateTimeOftenant = DateUtils.getLocalDateTimeOfTenant();
final LocalDateTime nextRunDateTime = reportMailingJob.getNextRunDateTime();
if (nextRunDateTime != null && nextRunDateTime.isBefore(localDateTimeOftenant)) {
if (nextRunDateTime != null && DateUtils.isBefore(nextRunDateTime, localDateTimeOftenant)) {
final ReportMailingJobEmailAttachmentFileFormat emailAttachmentFileFormat = ReportMailingJobEmailAttachmentFileFormat
.newInstance(reportMailingJob.getEmailAttachmentFileFormat());
@@ -43,7 +43,6 @@ import org.apache.fineract.infrastructure.campaigns.email.domain.EmailMessageRep
import org.apache.fineract.infrastructure.campaigns.email.exception.EmailCampaignNotFound;
import org.apache.fineract.infrastructure.campaigns.email.service.EmailCampaignReadPlatformService;
import org.apache.fineract.infrastructure.campaigns.email.service.EmailCampaignWritePlatformService;
import org.apache.fineract.infrastructure.campaigns.jobs.TenantDateTimeUtil;
import org.apache.fineract.infrastructure.core.service.DateUtils;
import org.apache.fineract.portfolio.calendar.service.CalendarUtils;
import org.apache.fineract.portfolio.client.domain.Client;
@@ -69,11 +68,11 @@ public class UpdateEmailOutboundWithCampaignMessageTasklet implements Tasklet {
.retrieveAllScheduleActiveCampaign();
if (emailCampaignDataCollection != null) {
for (EmailCampaignData emailCampaignData : emailCampaignDataCollection) {
LocalDateTime tenantDateNow = TenantDateTimeUtil.tenantDateTime();
LocalDateTime tenantDateNow = DateUtils.getLocalDateTimeOfTenant();
LocalDateTime nextTriggerDate = emailCampaignData.getNextTriggerDate().toLocalDateTime();
log.debug("tenant time {} trigger time {}", tenantDateNow, nextTriggerDate);
if (nextTriggerDate.isBefore(tenantDateNow)) {
if (DateUtils.isBefore(nextTriggerDate, tenantDateNow)) {
insertDirectCampaignIntoEmailOutboundTable(emailCampaignData.getParamValue(), emailCampaignData.getEmailSubject(),
emailCampaignData.getEmailMessage(), emailCampaignData.getCampaignName(), emailCampaignData.getId());
updateTriggerDates(emailCampaignData.getId());
@@ -115,13 +114,12 @@ public class UpdateEmailOutboundWithCampaignMessageTasklet implements Tasklet {
.orElseThrow(() -> new EmailCampaignNotFound(campaignId));
LocalDateTime nextTriggerDate = emailCampaign.getNextTriggerDate();
emailCampaign.setLastTriggerDate(nextTriggerDate);
LocalDateTime newTriggerDateWithTime = CalendarUtils.getNextRecurringDate(emailCampaign.getRecurrence(),
emailCampaign.getNextTriggerDate(), nextTriggerDate);
if (newTriggerDateWithTime.isBefore(DateUtils.getLocalDateTimeOfTenant())) {
newTriggerDateWithTime = CalendarUtils.getNextRecurringDate(emailCampaign.getRecurrence(), emailCampaign.getNextTriggerDate(),
DateUtils.getLocalDateTimeOfTenant());
LocalDateTime newTriggerDateWithTime = CalendarUtils.getNextRecurringDate(emailCampaign.getRecurrence(), nextTriggerDate,
nextTriggerDate);
LocalDateTime tenantDateTime = DateUtils.getLocalDateTimeOfTenant();
if (DateUtils.isBefore(newTriggerDateWithTime, tenantDateTime)) {
newTriggerDateWithTime = CalendarUtils.getNextRecurringDate(emailCampaign.getRecurrence(), nextTriggerDate, tenantDateTime);
}
emailCampaign.setNextTriggerDate(newTriggerDateWithTime);
emailCampaignRepository.saveAndFlush(emailCampaign);
}
@@ -23,7 +23,6 @@ import java.util.Collection;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.collections4.CollectionUtils;
import org.apache.fineract.infrastructure.campaigns.jobs.TenantDateTimeUtil;
import org.apache.fineract.infrastructure.campaigns.sms.constants.SmsCampaignStatus;
import org.apache.fineract.infrastructure.campaigns.sms.constants.SmsCampaignTriggerType;
import org.apache.fineract.infrastructure.campaigns.sms.domain.SmsCampaign;
@@ -51,12 +50,12 @@ public class UpdateSmsOutboundWithCampaignMessageTasklet implements Tasklet {
.findByTriggerTypeAndStatus(SmsCampaignTriggerType.SCHEDULE.getValue(), SmsCampaignStatus.ACTIVE.getValue());
if (!CollectionUtils.isEmpty(smsCampaignDataCollection)) {
for (SmsCampaign smsCampaign : smsCampaignDataCollection) {
LocalDateTime tenantDateNow = TenantDateTimeUtil.tenantDateTime();
LocalDateTime tenantDateNow = DateUtils.getLocalDateTimeOfTenant();
LocalDateTime nextTriggerDate = smsCampaign.getNextTriggerDate();
log.debug("tenant time {} trigger time {} {}", tenantDateNow, nextTriggerDate,
JobName.UPDATE_SMS_OUTBOUND_WITH_CAMPAIGN_MESSAGE.name());
if (nextTriggerDate.isBefore(tenantDateNow)) {
if (DateUtils.isBefore(nextTriggerDate, tenantDateNow)) {
smsCampaignWritePlatformService.insertDirectCampaignIntoSmsOutboundTable(smsCampaign);
updateTriggerDates(smsCampaign.getId());
}
@@ -70,11 +69,10 @@ public class UpdateSmsOutboundWithCampaignMessageTasklet implements Tasklet {
.orElseThrow(() -> new SmsCampaignNotFound(campaignId));
LocalDateTime nextTriggerDate = smsCampaign.getNextTriggerDate();
smsCampaign.setLastTriggerDate(nextTriggerDate);
LocalDateTime nextRuntime = CalendarUtils.getNextRecurringDate(smsCampaign.getRecurrence(), smsCampaign.getNextTriggerDate(),
nextTriggerDate);
if (nextRuntime.isBefore(DateUtils.getLocalDateTimeOfTenant())) {
nextRuntime = CalendarUtils.getNextRecurringDate(smsCampaign.getRecurrence(), smsCampaign.getNextTriggerDate(),
DateUtils.getLocalDateTimeOfTenant());
LocalDateTime nextRuntime = CalendarUtils.getNextRecurringDate(smsCampaign.getRecurrence(), nextTriggerDate, nextTriggerDate);
LocalDateTime tenantDateTime = DateUtils.getLocalDateTimeOfTenant();
if (DateUtils.isBefore(nextRuntime, tenantDateTime)) {
nextRuntime = CalendarUtils.getNextRecurringDate(smsCampaign.getRecurrence(), nextTriggerDate, tenantDateTime);
}
smsCampaign.setNextTriggerDate(nextRuntime);
@@ -18,10 +18,10 @@
*/
package org.apache.fineract.infrastructure.core.domain;
import static org.apache.fineract.useradministration.service.AppUserConstants.ADMIN_USER_ID;
import java.util.Optional;
import org.apache.fineract.useradministration.domain.AppUser;
import org.apache.fineract.useradministration.domain.AppUserRepository;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.domain.AuditorAware;
import org.springframework.security.core.Authentication;
import org.springframework.security.core.context.SecurityContext;
@@ -29,9 +29,6 @@ import org.springframework.security.core.context.SecurityContextHolder;
public class AuditorAwareImpl implements AuditorAware<Long> {
@Autowired
private AppUserRepository userRepository;
@Override
public Optional<Long> getCurrentAuditor() {
Optional<Long> currentUserId;
@@ -50,6 +47,6 @@ public class AuditorAwareImpl implements AuditorAware<Long> {
}
private Optional<Long> retrieveSuperUser() {
return Optional.of(1L);
return Optional.of(ADMIN_USER_ID); // TODO change to SYSTEM_USER_ID and add rights
}
}
@@ -420,7 +420,7 @@ public class ThitsaWorksCreditBureauIntegrationWritePlatformServiceImpl implemen
LocalDate current = DateUtils.getLocalDateOfTenant();
LocalDate getExpiryDate = creditBureauToken.getExpires();
if (getExpiryDate.isBefore(current)) {
if (DateUtils.isBefore(getExpiryDate, current)) {
this.tokenRepositoryWrapper.delete(creditBureauToken);
creditBureauToken = null;
}
@@ -33,6 +33,7 @@ import lombok.Setter;
import lombok.experimental.Accessors;
import org.apache.fineract.infrastructure.core.api.JsonCommand;
import org.apache.fineract.infrastructure.core.domain.AbstractPersistableCustom;
import org.apache.fineract.infrastructure.core.service.DateUtils;
import org.apache.fineract.infrastructure.entityaccess.api.FineractEntityApiResourceConstants;
import org.apache.fineract.infrastructure.entityaccess.exception.FineractEntityToEntityMappingDateException;
@@ -69,7 +70,6 @@ public class FineractEntityToEntityMapping extends AbstractPersistableCustom {
}
public Map<String, Object> updateMap(final JsonCommand command) {
final Map<String, Object> actualChanges = new LinkedHashMap<>(9);
if (command.isChangeInLongParameterNamed(FineractEntityApiResourceConstants.fromEnityType, this.fromId)) {
@@ -95,10 +95,8 @@ public class FineractEntityToEntityMapping extends AbstractPersistableCustom {
actualChanges.put(FineractEntityApiResourceConstants.endDate, valueAsInput);
this.endDate = command.localDateValueOfParameterNamed(FineractEntityApiResourceConstants.endDate);
}
if (startDate != null && endDate != null) {
if (endDate.isBefore(startDate)) {
throw new FineractEntityToEntityMappingDateException(startDate.toString(), endDate.toString());
}
if (endDate != null && DateUtils.isBefore(endDate, startDate)) {
throw new FineractEntityToEntityMappingDateException(startDate.toString(), endDate.toString());
}
return actualChanges;
@@ -27,6 +27,7 @@ import org.apache.fineract.infrastructure.core.api.JsonCommand;
import org.apache.fineract.infrastructure.core.data.CommandProcessingResult;
import org.apache.fineract.infrastructure.core.data.CommandProcessingResultBuilder;
import org.apache.fineract.infrastructure.core.exception.PlatformDataIntegrityException;
import org.apache.fineract.infrastructure.core.service.DateUtils;
import org.apache.fineract.infrastructure.entityaccess.api.FineractEntityApiResourceConstants;
import org.apache.fineract.infrastructure.entityaccess.data.FineractEntityDataValidator;
import org.apache.fineract.infrastructure.entityaccess.domain.FineractEntityAccess;
@@ -86,9 +87,7 @@ public class FineractEntityAccessWriteServiceImpl implements FineractEntityAcces
@Override
@Transactional
public CommandProcessingResult createEntityToEntityMapping(Long relId, JsonCommand command) {
try {
this.fromApiJsonDeserializer.validateForCreate(command.json());
final FineractEntityRelation mapId = this.fineractEntityRelationRepositoryWrapper.findOneWithNotFoundDetection(relId);
@@ -99,10 +98,8 @@ public class FineractEntityAccessWriteServiceImpl implements FineractEntityAcces
final LocalDate endDate = command.localDateValueOfParameterNamed(FineractEntityApiResourceConstants.endDate);
fromApiJsonDeserializer.checkForEntity(relId.toString(), fromId, toId);
if (startDate != null && endDate != null) {
if (endDate.isBefore(startDate)) {
throw new FineractEntityToEntityMappingDateException(startDate.toString(), endDate.toString());
}
if (endDate != null && DateUtils.isBefore(endDate, startDate)) {
throw new FineractEntityToEntityMappingDateException(startDate.toString(), endDate.toString());
}
final FineractEntityToEntityMapping newMap = FineractEntityToEntityMapping.newMap(mapId, fromId, toId, startDate, endDate);
@@ -123,9 +120,7 @@ public class FineractEntityAccessWriteServiceImpl implements FineractEntityAcces
@Override
@Transactional
public CommandProcessingResult updateEntityToEntityMapping(Long mapId, JsonCommand command) {
try {
this.fromApiJsonDeserializer.validateForUpdate(command.json());
final FineractEntityToEntityMapping mapForUpdate = this.fineractEntityToEntityMappingRepositoryWrapper
@@ -63,7 +63,7 @@ public class UpdateNpaTasklet implements Tasklet {
resetNPASqlBuilder.append("set is_npa = false").append(", last_modified_by = ?, last_modified_on_utc = ? ").append(" FROM ")
.append(fromPart).append(wherePart);
}
jdbcTemplate.update(resetNPASqlBuilder.toString(), user.getId(), DateUtils.getOffsetDateTimeOfTenantWithMostPrecision());
jdbcTemplate.update(resetNPASqlBuilder.toString(), user.getId(), DateUtils.getAuditOffsetDateTime());
final StringBuilder updateSqlBuilder = new StringBuilder(900);
@@ -82,8 +82,7 @@ public class UpdateNpaTasklet implements Tasklet {
.append(fromPart).append(wherePart);
}
final int result = jdbcTemplate.update(updateSqlBuilder.toString(), user.getId(),
DateUtils.getOffsetDateTimeOfTenantWithMostPrecision());
final int result = jdbcTemplate.update(updateSqlBuilder.toString(), user.getId(), DateUtils.getAuditOffsetDateTime());
log.debug("{}: Records affected by updateNPA: {}", ThreadLocalContextUtil.getTenant().getName(), result);
return RepeatStatus.FINISHED;
@@ -67,19 +67,12 @@ public class TFAccessToken extends AbstractPersistableCustom {
}
public boolean isValid() {
return this.enabled && isDateInTheFuture(getValidTo()) && isDateInThePast(getValidFrom());
// valid_from is in the past inclusive, valid_to is in the future exclusive
return this.enabled && !DateUtils.isAfterTenantDateTime(getValidFrom()) && DateUtils.isAfterTenantDateTime(getValidTo());
}
public AccessTokenData toTokenData() {
return new AccessTokenData().setToken(this.token).setValidFrom(getValidFrom().atZone(DateUtils.getDateTimeZoneOfTenant()))
.setValidTo(getValidTo().atZone(DateUtils.getDateTimeZoneOfTenant()));
}
private boolean isDateInTheFuture(LocalDateTime dateTime) {
return dateTime.isAfter(DateUtils.getLocalDateTimeOfTenant());
}
private boolean isDateInThePast(LocalDateTime dateTime) {
return (dateTime.isBefore(DateUtils.getLocalDateTimeOfTenant()) || dateTime.isEqual(DateUtils.getLocalDateTimeOfTenant()));
}
}
@@ -157,7 +157,7 @@ public class SpringSecurityPlatformSecurityContext implements PlatformSecurityCo
final LocalDate passwordExpirationDate = passWordLastUpdateDate.plusDays(passwordDurationDays);
if (DateUtils.getLocalDateOfTenant().isAfter(passwordExpirationDate)) {
if (DateUtils.isBeforeTenantDate(passwordExpirationDate)) {
return true;
}
}
@@ -23,6 +23,7 @@ import java.util.List;
import java.util.function.Predicate;
import java.util.stream.Collectors;
import org.apache.fineract.infrastructure.core.data.CommandProcessingResult;
import org.apache.fineract.infrastructure.core.service.DateUtils;
import org.apache.fineract.portfolio.savings.domain.SavingsAccount;
import org.apache.fineract.portfolio.savings.domain.SavingsAccountTransaction;
@@ -41,7 +42,7 @@ public class InteropTransactionsData extends CommandProcessingResult {
}
List<InteropTransactionData> trans = account.getTransactions().stream().filter(filter).sorted((t1, t2) -> {
int i = t2.getDateOf().compareTo(t1.getDateOf());
int i = DateUtils.compare(t2.getDateOf(), t1.getDateOf());
return i != 0 ? i : Long.signum(t2.getId() - t1.getId());
}).map(InteropTransactionData::build).collect(Collectors.toList());
return new InteropTransactionsData(account.getId(), trans);
@@ -33,6 +33,7 @@ import org.apache.fineract.infrastructure.core.data.CommandProcessingResult;
import org.apache.fineract.infrastructure.core.data.CommandProcessingResultBuilder;
import org.apache.fineract.infrastructure.core.exception.PlatformDataIntegrityException;
import org.apache.fineract.infrastructure.core.serialization.FromJsonHelper;
import org.apache.fineract.infrastructure.core.service.DateUtils;
import org.apache.fineract.infrastructure.security.service.PlatformSecurityContext;
import org.apache.fineract.organisation.holiday.api.HolidayApiConstants;
import org.apache.fineract.organisation.holiday.data.HolidayDataValidator;
@@ -206,18 +207,15 @@ public class HolidayWritePlatformServiceJpaRepositoryImpl implements HolidayWrit
}
private void validateInputDates(final LocalDate fromDate, final LocalDate toDate, final LocalDate repaymentsRescheduledTo) {
String defaultUserMessage = "";
if (toDate.isBefore(fromDate)) {
if (DateUtils.isBefore(toDate, fromDate)) {
defaultUserMessage = "To Date date cannot be before the From Date.";
throw new HolidayDateException("to.date.cannot.be.before.from.date", defaultUserMessage, fromDate.toString(),
toDate.toString());
}
if (repaymentsRescheduledTo != null) {
if ((repaymentsRescheduledTo.isEqual(fromDate) || repaymentsRescheduledTo.isEqual(toDate)
|| (repaymentsRescheduledTo.isAfter(fromDate) && repaymentsRescheduledTo.isBefore(toDate)))) {
if (!DateUtils.isBefore(repaymentsRescheduledTo, fromDate) && !DateUtils.isAfter(repaymentsRescheduledTo, toDate)) {
defaultUserMessage = "Repayments rescheduled date should be before from date or after to date.";
throw new HolidayDateException("repayments.rescheduled.date.should.be.before.from.date.or.after.to.date",
defaultUserMessage, repaymentsRescheduledTo.toString());
@@ -235,13 +233,12 @@ public class HolidayWritePlatformServiceJpaRepositoryImpl implements HolidayWrit
// validate repaymentsRescheduledTo date
// 1. should be within a 30 days date range.
// 2. Alternative date should not be an exist holiday.//TBD
// 3. Holiday should not be on an repaymentsRescheduledTo date of
// another holiday.//TBD
// 3. Holiday should not be on an repaymentsRescheduledTo date of another holiday.//TBD
// restricting repaymentsRescheduledTo date to be within 30 days
// range
// before or after from date and to date.
if (repaymentsRescheduledTo.isBefore(fromDate.minusDays(30)) || repaymentsRescheduledTo.isAfter(toDate.plusDays(30))) {
// restricting repaymentsRescheduledTo date to be within 30 days range before or after from date and to
// date.
if (DateUtils.isBefore(repaymentsRescheduledTo, fromDate.minusDays(30))
|| DateUtils.isAfter(repaymentsRescheduledTo, toDate.plusDays(30))) {
defaultUserMessage = "Repayments Rescheduled to date must be within 30 days before or after from and to dates";
throw new HolidayDateException("repayments.rescheduled.to.must.be.within.range", defaultUserMessage, fromDate.toString(),
toDate.toString(), repaymentsRescheduledTo.toString());
@@ -20,10 +20,10 @@ package org.apache.fineract.organisation.teller.data;
import java.math.BigDecimal;
import java.time.LocalDate;
import java.time.LocalDateTime;
import java.time.ZonedDateTime;
import java.time.OffsetDateTime;
import org.apache.fineract.infrastructure.core.api.JsonCommand;
import org.apache.fineract.infrastructure.core.service.DateUtils;
import org.apache.fineract.infrastructure.core.service.MathUtil;
import org.apache.fineract.infrastructure.core.service.SearchParameters;
import org.apache.fineract.organisation.teller.domain.Cashier;
import org.apache.fineract.organisation.teller.domain.Teller;
@@ -54,7 +54,6 @@ public class CashierTransactionDataValidator {
}
public void validateSettleCashAndCashOutTransactions(final Long cashierId, String currencyCode, final BigDecimal transactionAmount) {
final Integer offset = null;
final Integer limit = null;
final String orderBy = null;
@@ -64,7 +63,7 @@ public class CashierTransactionDataValidator {
final SearchParameters searchParameters = SearchParameters.forPagination(offset, limit, orderBy, sortOrder);
final CashierTransactionsWithSummaryData cashierTxnWithSummary = this.tellerManagementReadPlatformService
.retrieveCashierTransactionsWithSummary(cashierId, false, fromDate, toDate, currencyCode, searchParameters);
if (cashierTxnWithSummary.getNetCash().subtract(transactionAmount).compareTo(BigDecimal.ZERO) < 0) {
if (MathUtil.isGreaterThan(transactionAmount, cashierTxnWithSummary.getNetCash())) {
throw new CashierInsufficientAmountException();
}
}
@@ -81,16 +80,12 @@ public class CashierTransactionDataValidator {
final LocalDate endDate = cashier.getEndDate();
final LocalDate tellerFromDate = teller.getStartDate();
final LocalDate tellerEndDate = teller.getEndDate();
/**
* to validate cashier date range in range of teller date range
*/
if (fromDate.isBefore(tellerFromDate) || endDate.isBefore(tellerFromDate)
|| (tellerEndDate != null && (fromDate.isAfter(tellerEndDate) || endDate.isAfter(tellerEndDate)))) {
// to validate cashier date range in range of teller date range
if (DateUtils.isBefore(fromDate, tellerFromDate) || DateUtils.isBefore(endDate, tellerFromDate)
|| (tellerEndDate != null && (DateUtils.isAfter(fromDate, tellerEndDate) || DateUtils.isAfter(endDate, tellerEndDate)))) {
throw new CashierDateRangeOutOfTellerDateRangeException();
}
/**
* to validate cashier has not been assigned for same duration
*/
// to validate cashier has not been assigned for same duration
String sql = "select count(*) from m_cashiers c where c.staff_id = " + staffId + " AND " + "(('" + fromDate
+ "' BETWEEN c.start_date AND c.end_date OR '" + endDate + "' BETWEEN c.start_date AND c.end_date )"
+ " OR ( c.start_date BETWEEN '" + fromDate + "' AND '" + endDate + "' OR c.end_date BETWEEN '" + fromDate + "' AND '"
@@ -98,8 +93,8 @@ public class CashierTransactionDataValidator {
if (!cashier.getIsFullDay()) {
String startTime = cashier.getStartTime();
String endTime = cashier.getEndTime();
sql = sql + " AND ( Time(c.start_time) BETWEEN TIME(?) and TIME('" + endTime + "') or Time(c.end_time) BETWEEN TIME('"
+ startTime + "') and TIME('" + endTime + "')) ";
sql = sql + " AND ( Time(c.start_time) BETWEEN TIME('" + startTime + "') and TIME('" + endTime
+ "') or Time(c.end_time) BETWEEN TIME('" + startTime + "') and TIME('" + endTime + "')) ";
}
int count = this.jdbcTemplate.queryForObject(sql, Integer.class); // NOSONAR
if (count > 0) {
@@ -108,13 +103,13 @@ public class CashierTransactionDataValidator {
}
public void validateOnLoanDisbursal(AppUser user, String currencyCode, BigDecimal transactionAmount) {
LocalDateTime localDateTime = DateUtils.getLocalDateTimeOfTenant();
LocalDate tenantDate = DateUtils.getLocalDateOfTenant();
OffsetDateTime tenantDateTime = DateUtils.getOffsetDateTimeOfTenant();
if (user.getStaff() != null) {
String sql = "select c.id from m_cashiers c where c.staff_id = " + user.getStaff().getId() + " AND "
+ " (case when c.full_day then '" + localDateTime.toLocalDate() + "' BETWEEN c.start_date AND c.end_date " + " else ('"
+ localDateTime.toLocalDate() + "' BETWEEN c.start_date AND c.end_date and " + " TIME('"
+ ZonedDateTime.of(localDateTime, DateUtils.getDateTimeZoneOfTenant())
+ "') BETWEEN TIME(c.start_time) AND TIME(c.end_time) ) end)";
String sql = "select c.id from m_cashiers c where c.staff_id = " + user.getStaff().getId() + " AND (case when c.full_day then '"
+ tenantDate + "' BETWEEN c.start_date AND c.end_date else ('" + tenantDate
+ "' BETWEEN c.start_date AND c.end_date and TIME('" + tenantDateTime
+ "') BETWEEN TIME(c.start_time) AND TIME(c.end_time)) end)";
try {
Long cashierId = this.jdbcTemplate.queryForObject(sql, Long.class); // NOSONAR
validateSettleCashAndCashOutTransactions(cashierId, currencyCode, transactionAmount);
@@ -122,6 +117,5 @@ public class CashierTransactionDataValidator {
LOG.error("Problem occurred in validateOnLoanDisbursal function", e);
}
}
}
}
@@ -35,6 +35,7 @@ import org.apache.fineract.infrastructure.core.data.DataValidatorBuilder;
import org.apache.fineract.infrastructure.core.exception.InvalidJsonException;
import org.apache.fineract.infrastructure.core.exception.PlatformApiDataValidationException;
import org.apache.fineract.infrastructure.core.serialization.FromJsonHelper;
import org.apache.fineract.infrastructure.core.service.DateUtils;
import org.apache.fineract.organisation.teller.exception.InvalidDateInputException;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;
@@ -113,7 +114,7 @@ public final class TellerCommandFromApiJsonDeserializer {
final String status = this.fromApiJsonHelper.extractStringNamed(STATUS, element);
baseDataValidator.reset().parameter(STATUS).value(status).notBlank().notExceedingLengthOf(50);
if (endDate != null && endDate.isBefore(startDate)) {
if (endDate != null && DateUtils.isBefore(endDate, startDate)) {
throw new InvalidDateInputException(startDate.toString(), endDate.toString());
}
throwExceptionIfValidationWarningsExist(dataValidationErrors);
@@ -75,12 +75,12 @@ public class ExecuteStandingInstructionsTasklet implements Tasklet {
LocalDate startDate = data.validFrom();
if (frequencyType.isMonthly()) {
startDate = startDate.withDayOfMonth(data.recurrenceOnDay());
if (startDate.isBefore(data.validFrom())) {
if (DateUtils.isBefore(startDate, data.validFrom())) {
startDate = startDate.plusMonths(1);
}
} else if (frequencyType.isYearly()) {
startDate = startDate.withDayOfMonth(data.recurrenceOnDay()).withMonth(data.recurrenceOnMonth());
if (startDate.isBefore(data.validFrom())) {
if (DateUtils.isBefore(startDate, data.validFrom())) {
startDate = startDate.plusYears(1);
}
}
@@ -536,8 +536,7 @@ public class AccountTransfersWritePlatformServiceImpl implements AccountTransfer
BigDecimal overpaid = this.loanReadPlatformService.retrieveTotalPaidInAdvance(fromLoanAccountId).getPaidInAdvance();
final boolean backdatedTxnsAllowedTill = false;
if (overpaid == null || overpaid.compareTo(BigDecimal.ZERO) == 0 ? Boolean.TRUE
: Boolean.FALSE || transactionAmount.floatValue() > overpaid.floatValue()) {
if (overpaid == null || overpaid.compareTo(BigDecimal.ZERO) == 0 || transactionAmount.floatValue() > overpaid.floatValue()) {
if (overpaid == null) {
overpaid = BigDecimal.ZERO;
}
@@ -279,7 +279,7 @@ public class CalendarReadPlatformServiceImpl implements CalendarReadPlatformServ
periodStartDate = fromDate;
} else {
final LocalDate currentDate = DateUtils.getLocalDateOfTenant();
if (seedDate.isBefore(currentDate.minusYears(1))) {
if (DateUtils.isBefore(seedDate, currentDate.minusYears(1))) {
periodStartDate = currentDate.minusYears(1);
} else {
periodStartDate = recurrenceStartDate;
@@ -294,7 +294,7 @@ public class CalendarReadPlatformServiceImpl implements CalendarReadPlatformServ
if (tillDate != null) {
if (endDate != null) {
if (endDate.isAfter(tillDate)) {
if (DateUtils.isAfter(endDate, tillDate)) {
// to retrieve meeting dates tillspecified date (tillDate)
periodEndDate = tillDate;
}
@@ -302,7 +302,7 @@ public class CalendarReadPlatformServiceImpl implements CalendarReadPlatformServ
// end date is null then fetch meeting dates tillDate
periodEndDate = tillDate;
}
} else if (endDate == null || endDate.isAfter(currentDate.plusYears(1))) {
} else if (endDate == null || DateUtils.isAfter(endDate, currentDate.plusYears(1))) {
periodEndDate = currentDate.plusYears(1);
}
return periodEndDate;
@@ -80,8 +80,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.getCreatedDate().orElse(null), LAST_MODIFIED_BY,
client.getLastModifiedBy().orElse(null), LAST_MODIFIED_DATE, client.getLastModifiedDate().orElse(null)));
Map.of(CREATED_BY, client.getCreatedBy().orElse(null), CREATED_DATE, client.getCreatedDateTime(), LAST_MODIFIED_BY,
client.getLastModifiedBy().orElse(null), LAST_MODIFIED_DATE, client.getLastModifiedDateTime()));
final ApiRequestJsonSerializationSettings settings = this.apiRequestParameterHelper.process(uriInfo.getQueryParameters());
return this.toApiJsonSerializer.serialize(settings, auditFields);
}
@@ -36,6 +36,7 @@ import org.apache.fineract.infrastructure.core.api.JsonCommand;
import org.apache.fineract.infrastructure.core.data.ApiParameterError;
import org.apache.fineract.infrastructure.core.domain.AbstractPersistableCustom;
import org.apache.fineract.infrastructure.core.exception.PlatformApiDataValidationException;
import org.apache.fineract.infrastructure.core.service.DateUtils;
import org.apache.fineract.portfolio.client.api.ClientApiConstants;
@Entity
@@ -116,8 +117,7 @@ public class ClientNonPerson extends AbstractPersistableCustom {
private void validateIncorpValidityTillDate(final Client client, final List<ApiParameterError> dataValidationErrors) {
if (getIncorpValidityTillLocalDate() != null && client.dateOfBirthLocalDate() != null
&& client.dateOfBirthLocalDate().isAfter(getIncorpValidityTillLocalDate())) {
&& DateUtils.isAfter(client.dateOfBirthLocalDate(), getIncorpValidityTillLocalDate())) {
final String defaultUserMessage = "incorpvaliditytill date cannot be after the incorporation date";
final ApiParameterError error = ApiParameterError.parameterError("error.msg.clients.incorpValidityTill.after.incorp.date",
defaultUserMessage, ClientApiConstants.incorpValidityTillParamName, this.incorpValidityTill);
@@ -99,9 +99,9 @@ public class ClientChargeWritePlatformServiceImpl implements ClientChargeWritePl
final List<ApiParameterError> dataValidationErrors = new ArrayList<>();
final DataValidatorBuilder baseDataValidator = new DataValidatorBuilder(dataValidationErrors)
.resource(ClientApiConstants.CLIENT_CHARGES_RESOURCE_NAME);
LocalDate activationDate = client.getActivationLocalDate();
LocalDate activationDate = client.getActivationDate();
LocalDate dueDate = clientCharge.getDueLocalDate();
if (dueDate.isBefore(activationDate)) {
if (DateUtils.isBefore(dueDate, activationDate)) {
baseDataValidator.reset().parameter(ClientApiConstants.dueAsOfDateParamName).value(dueDate.format(fmt))
.failWithCodeNoParameterAddedToErrorCode("dueDate.before.activationDate");
@@ -275,7 +275,7 @@ public class ClientChargeWritePlatformServiceImpl implements ClientChargeWritePl
if (requiresTransactionDateValidation) {
validateTransactionDateOnWorkingDay(transactionDate, clientCharge, fmt);
if (client.getActivationLocalDate() != null && transactionDate.isBefore(client.getActivationLocalDate())) {
if (DateUtils.isBefore(transactionDate, client.getActivationDate())) {
baseDataValidator.reset().parameter(ClientApiConstants.transactionDateParamName).value(transactionDate.format(fmt))
.failWithCodeNoParameterAddedToErrorCode("transaction.before.activationDate");
throw new PlatformApiDataValidationException(dataValidationErrors);
@@ -277,7 +277,7 @@ public class ClientWritePlatformServiceJpaRepositoryImpl implements ClientWriteP
if (command.hasParameter(ClientApiConstants.submittedOnDateParamName)) {
submittedOnDate = command.localDateValueOfParameterNamed(ClientApiConstants.submittedOnDateParamName);
}
if (active && submittedOnDate.isAfter(activationDate)) {
if (active && DateUtils.isAfter(submittedOnDate, activationDate)) {
submittedOnDate = activationDate;
}
final Long savingsAccountId = null;
@@ -743,7 +743,7 @@ public class ClientWritePlatformServiceJpaRepositoryImpl implements ClientWriteP
CommandProcessingResult commandProcessingResult = CommandProcessingResult.empty();
if (client.isActive() && client.savingsProductId() != null) {
SavingsAccountDataDTO savingsAccountDataDTO = new SavingsAccountDataDTO(client, null, client.savingsProductId(),
client.getActivationLocalDate(), client.activatedBy(), fmt);
client.getActivationDate(), client.activatedBy(), fmt);
commandProcessingResult = this.savingsApplicationProcessWritePlatformService.createActiveApplication(savingsAccountDataDTO);
if (commandProcessingResult.getSavingsId() != null) {
this.savingsRepositoryWrapper.findOneWithNotFoundDetection(commandProcessingResult.getSavingsId());
@@ -851,10 +851,10 @@ public class ClientWritePlatformServiceJpaRepositoryImpl implements ClientWriteP
throw new InvalidClientStateTransitionException("close", "is.under.transfer", errorMessage);
}
if (client.isNotPending() && client.getActivationLocalDate() != null && client.getActivationLocalDate().isAfter(closureDate)) {
if (client.isNotPending() && DateUtils.isAfter(client.getActivationDate(), closureDate)) {
final String errorMessage = "The client closureDate cannot be before the client ActivationDate.";
throw new InvalidClientStateTransitionException("close", "date.cannot.before.client.actvation.date", errorMessage,
closureDate, client.getActivationLocalDate());
closureDate, client.getActivationDate());
}
final LegalForm legalForm = LegalForm.fromInt(client.getLegalForm());
entityDatatableChecksWritePlatformService.runTheCheck(clientId, EntityTables.CLIENT.getName(), StatusEnum.CLOSE.getCode(),
@@ -866,7 +866,7 @@ public class ClientWritePlatformServiceJpaRepositoryImpl implements ClientWriteP
if (loanStatus.isOpen() || loanStatus.isPendingApproval() || loanStatus.isAwaitingDisbursal()) {
final String errorMessage = "Client cannot be closed because of non-closed loans.";
throw new InvalidClientStateTransitionException("close", "loan.non-closed", errorMessage);
} else if (loanStatus.isClosed() && loan.getClosedOnDate().isAfter(closureDate)) {
} else if (loanStatus.isClosed() && DateUtils.isAfter(loan.getClosedOnDate(), closureDate)) {
final String errorMessage = "The client closureDate cannot be before the loan closedOnDate.";
throw new InvalidClientStateTransitionException("close", "date.cannot.before.loan.closed.date", errorMessage,
closureDate, loan.getClosedOnDate());
@@ -976,7 +976,7 @@ public class ClientWritePlatformServiceJpaRepositoryImpl implements ClientWriteP
final String errorMessage = "Only clients pending activation may be withdrawn.";
throw new InvalidClientStateTransitionException("rejection", "on.account.not.in.pending.activation.status", errorMessage,
rejectionDate, client.getSubmittedOnDate());
} else if (client.getSubmittedOnDate().isAfter(rejectionDate)) {
} else if (DateUtils.isAfter(client.getSubmittedOnDate(), rejectionDate)) {
final String errorMessage = "The client rejection date cannot be before the client submitted date.";
throw new InvalidClientStateTransitionException("rejection", "date.cannot.before.client.submitted.date", errorMessage,
rejectionDate, client.getSubmittedOnDate());
@@ -1008,7 +1008,7 @@ public class ClientWritePlatformServiceJpaRepositoryImpl implements ClientWriteP
final String errorMessage = "Only clients pending activation may be withdrawn.";
throw new InvalidClientStateTransitionException("withdrawal", "on.account.not.in.pending.activation.status", errorMessage,
withdrawalDate, client.getSubmittedOnDate());
} else if (client.getSubmittedOnDate().isAfter(withdrawalDate)) {
} else if (DateUtils.isAfter(client.getSubmittedOnDate(), withdrawalDate)) {
final String errorMessage = "The client withdrawal date cannot be before the client submitted date.";
throw new InvalidClientStateTransitionException("withdrawal", "date.cannot.before.client.submitted.date", errorMessage,
withdrawalDate, client.getSubmittedOnDate());
@@ -1034,7 +1034,7 @@ public class ClientWritePlatformServiceJpaRepositoryImpl implements ClientWriteP
if (!client.isClosed()) {
final String errorMessage = "only closed clients may be reactivated.";
throw new InvalidClientStateTransitionException("reactivation", "on.nonclosed.account", errorMessage);
} else if (client.getClosureDate().isAfter(reactivateDate)) {
} else if (DateUtils.isAfter(client.getClosureDate(), reactivateDate)) {
final String errorMessage = "The client reactivation date cannot be before the client closed date.";
throw new InvalidClientStateTransitionException("reactivation", "date.cannot.before.client.closed.date", errorMessage,
reactivateDate, client.getClosureDate());
@@ -1060,7 +1060,7 @@ public class ClientWritePlatformServiceJpaRepositoryImpl implements ClientWriteP
if (!client.isRejected()) {
final String errorMessage = "only rejected clients may be reactivated.";
throw new InvalidClientStateTransitionException("undorejection", "on.nonrejected.account", errorMessage);
} else if (client.getRejectedDate().isAfter(undoRejectDate)) {
} else if (DateUtils.isAfter(client.getRejectedDate(), undoRejectDate)) {
final String errorMessage = "The client reactivation date cannot be before the client rejected date.";
throw new InvalidClientStateTransitionException("reopened", "date.cannot.before.client.rejected.date", errorMessage,
undoRejectDate, client.getRejectedDate());
@@ -1088,7 +1088,7 @@ public class ClientWritePlatformServiceJpaRepositoryImpl implements ClientWriteP
if (!client.isWithdrawn()) {
final String errorMessage = "only withdrawal clients may be reactivated.";
throw new InvalidClientStateTransitionException("undoWithdrawal", "on.nonwithdrawal.account", errorMessage);
} else if (client.getWithdrawalDate().isAfter(undoWithdrawalDate)) {
} else if (DateUtils.isAfter(client.getWithdrawalDate(), undoWithdrawalDate)) {
final String errorMessage = "The client reactivation date cannot be before the client withdrawal date.";
throw new InvalidClientStateTransitionException("reopened", "date.cannot.before.client.withdrawal.date", errorMessage,
undoWithdrawalDate, client.getWithdrawalDate());
@@ -55,7 +55,7 @@ public class LoanDelinquencyDomainServiceImpl implements LoanDelinquencyDomainSe
// Get the oldest overdue installment if exists one
for (LoanRepaymentScheduleInstallment installment : loan.getRepaymentScheduleInstallments()) {
if (!installment.isObligationsMet()) {
if (installment.getDueDate().isBefore(businessDate)) {
if (DateUtils.isBefore(installment.getDueDate(), businessDate)) {
log.debug("Loan Id: {} with installment {} due date {}", loan.getId(), installment.getInstallmentNumber(),
installment.getDueDate());
outstandingAmount = outstandingAmount.add(installment.getTotalOutstanding(loanCurrency).getAmount());
@@ -69,13 +69,13 @@ public class LoanDelinquencyDomainServiceImpl implements LoanDelinquencyDomainSe
boolean isLatestInstallment = Objects.equals(installment.getId(), latestInstallment.getId());
for (LoanTransaction loanTransaction : chargebackTransactions) {
boolean isLoanTransactionIsOnOrAfterInstallmentFromDate = loanTransaction.getTransactionDate().isEqual(
installment.getFromDate()) || loanTransaction.getTransactionDate().isAfter(installment.getFromDate());
boolean isLoanTransactionIsOnOrAfterInstallmentFromDate = DateUtils
.isEqual(loanTransaction.getTransactionDate(), installment.getFromDate())
|| DateUtils.isAfter(loanTransaction.getTransactionDate(), installment.getFromDate());
boolean isLoanTransactionIsBeforeNotLastInstallmentDueDate = !isLatestInstallment
&& loanTransaction.getTransactionDate().isBefore(installment.getDueDate());
&& DateUtils.isBefore(loanTransaction.getTransactionDate(), installment.getDueDate());
boolean isLoanTransactionIsOnOrBeforeLastInstallmentDueDate = isLatestInstallment
&& (loanTransaction.getTransactionDate().isEqual(installment.getDueDate())
|| loanTransaction.getTransactionDate().isBefore(installment.getDueDate()));
&& !DateUtils.isAfter(loanTransaction.getTransactionDate(), installment.getDueDate());
if (isLoanTransactionIsOnOrAfterInstallmentFromDate && (isLoanTransactionIsBeforeNotLastInstallmentDueDate
|| isLoanTransactionIsOnOrBeforeLastInstallmentDueDate)) {
amountAvailable = amountAvailable.subtract(loanTransaction.getAmount());
@@ -93,11 +93,12 @@ public class LoanDelinquencyDomainServiceImpl implements LoanDelinquencyDomainSe
amountAvailable = installment.getTotalPaid(loanCurrency).getAmount();
log.debug("Amount available {}", amountAvailable);
for (LoanTransaction loanTransaction : chargebackTransactions) {
boolean isLoanTransactionIsOnOrAfterInstallmentFromDate = loanTransaction.getTransactionDate().isEqual(
installment.getFromDate()) || loanTransaction.getTransactionDate().isAfter(installment.getFromDate());
boolean isLoanTransactionIsBeforeInstallmentDueDate = loanTransaction.getTransactionDate()
.isBefore(installment.getDueDate());
boolean isLoanTransactionIsBeforeBusinessDate = loanTransaction.getTransactionDate().isBefore(businessDate);
boolean isLoanTransactionIsOnOrAfterInstallmentFromDate = !DateUtils.isBefore(loanTransaction.getTransactionDate(),
installment.getFromDate());
boolean isLoanTransactionIsBeforeInstallmentDueDate = DateUtils.isBefore(loanTransaction.getTransactionDate(),
installment.getDueDate());
boolean isLoanTransactionIsBeforeBusinessDate = DateUtils.isBefore(loanTransaction.getTransactionDate(),
businessDate);
if (isLoanTransactionIsOnOrAfterInstallmentFromDate && isLoanTransactionIsBeforeInstallmentDueDate
&& isLoanTransactionIsBeforeBusinessDate) {
log.debug("Loan CB Transaction: {} {} {}", loanTransaction.getId(), loanTransaction.getTransactionDate(),
@@ -153,7 +153,7 @@ public class GroupingTypesWritePlatformServiceJpaRepositoryImpl implements Group
final boolean active = command.booleanPrimitiveValueOfParameterNamed(GroupingTypesApiConstants.activeParamName);
LocalDate submittedOnDate = DateUtils.getBusinessLocalDate();
if (active && submittedOnDate.isAfter(activationDate)) {
if (active && DateUtils.isAfter(submittedOnDate, activationDate)) {
submittedOnDate = activationDate;
}
if (command.hasParameter(GroupingTypesApiConstants.submittedOnDateParamName)) {
@@ -616,7 +616,7 @@ public class GroupingTypesWritePlatformServiceJpaRepositoryImpl implements Group
final String errorMessage = groupOrCenter.getGroupLevel().getLevelName() + " cannot be closed because of non-closed loans.";
throw new InvalidGroupStateTransitionException(groupOrCenter.getGroupLevel().getLevelName(), "close", "loan.not.closed",
errorMessage);
} else if (loanStatus.isClosed() && loan.getClosedOnDate().isAfter(closureDate)) {
} else if (loanStatus.isClosed() && DateUtils.isAfter(loan.getClosedOnDate(), closureDate)) {
final String errorMessage = groupOrCenter.getGroupLevel().getLevelName()
+ "closureDate cannot be before the loan closedOnDate.";
throw new InvalidGroupStateTransitionException(groupOrCenter.getGroupLevel().getLevelName(), "close",
@@ -640,7 +640,7 @@ public class GroupingTypesWritePlatformServiceJpaRepositoryImpl implements Group
+ " cannot be closed with active savings accounts associated.";
throw new InvalidGroupStateTransitionException(groupOrCenter.getGroupLevel().getLevelName(), "close",
"savings.account.not.closed", errorMessage);
} else if (saving.isClosed() && saving.getClosedOnDate().isAfter(closureDate)) {
} else if (saving.isClosed() && DateUtils.isAfter(saving.getClosedOnDate(), closureDate)) {
final String errorMessage = groupOrCenter.getGroupLevel().getLevelName()
+ " closureDate cannot be before the loan closedOnDate.";
throw new InvalidGroupStateTransitionException(groupOrCenter.getGroupLevel().getLevelName(), "close",
@@ -906,7 +906,7 @@ public class GroupingTypesWritePlatformServiceJpaRepositoryImpl implements Group
public void validateOfficeOpeningDateisAfterGroupOrCenterOpeningDate(final Office groupOffice, final GroupLevel groupLevel,
final LocalDate activationDate) {
if (activationDate != null && groupOffice.getOpeningLocalDate().isAfter(activationDate)) {
if (activationDate != null && DateUtils.isAfter(groupOffice.getOpeningLocalDate(), activationDate)) {
final String levelName = groupLevel.getLevelName();
final String errorMessage = levelName + " activation date should be greater than or equal to the parent Office's creation date "
+ activationDate.toString();
@@ -916,10 +916,7 @@ public class GroupingTypesWritePlatformServiceJpaRepositoryImpl implements Group
}
private void checkGroupMembersMeetingSyncWithCenterMeeting(final Long centerId, final Set<Group> groupMembers) {
/**
* Get parent(center) calendar
*/
// Get parent(center) calendar
Calendar ceneterCalendar = null;
final CalendarInstance parentCalendarInstance = this.calendarInstanceRepository.findByEntityIdAndEntityTypeIdAndCalendarTypeId(
centerId, CalendarEntityType.CENTERS.getValue(), CalendarType.COLLECTION.getValue());
@@ -928,9 +925,7 @@ public class GroupingTypesWritePlatformServiceJpaRepositoryImpl implements Group
}
for (final Group group : groupMembers) {
/**
* Get child(group) calendar
*/
// Get child(group) calendar
Calendar groupCalendar = null;
final CalendarInstance groupCalendarInstance = this.calendarInstanceRepository.findByEntityIdAndEntityTypeIdAndCalendarTypeId(
group.getId(), CalendarEntityType.GROUPS.getValue(), CalendarType.COLLECTION.getValue());
@@ -938,19 +933,14 @@ public class GroupingTypesWritePlatformServiceJpaRepositoryImpl implements Group
groupCalendar = groupCalendarInstance.getCalendar();
}
/**
* Group shouldn't have a meeting when no meeting attached for center
*/
// Group shouldn't have a meeting when no meeting attached for center
if (ceneterCalendar == null && groupCalendar != null) {
throw new GeneralPlatformDomainRuleException(
"error.msg.center.associating.group.not.allowed.with.meeting.attached.to.group",
"Group with id " + group.getId() + " is already associated with meeting", group.getId());
}
/**
* Group meeting recurrence should match with center meeting recurrence
*/
// Group meeting recurrence should match with center meeting recurrence
else if (ceneterCalendar != null && groupCalendar != null) {
if (!ceneterCalendar.getRecurrence().equalsIgnoreCase(groupCalendar.getRecurrence())) {
throw new GeneralPlatformDomainRuleException("error.msg.center.associating.group.not.allowed.with.different.meeting",
"Group with id " + group.getId() + " meeting recurrence doesnot matched with center meeting recurrence",
@@ -23,6 +23,7 @@ import java.util.ArrayList;
import java.util.Collection;
import org.apache.fineract.infrastructure.codes.data.CodeValueData;
import org.apache.fineract.infrastructure.core.data.EnumOptionData;
import org.apache.fineract.infrastructure.core.service.DateUtils;
/**
* Immutable data object representing a InterestRateChart.
@@ -143,7 +144,7 @@ public final class InterestRateChartData {
}
public boolean isFromDateAfter(final LocalDate compareDate) {
return (compareDate == null) ? false : this.fromDate.isAfter(compareDate);
return compareDate != null && DateUtils.isAfter(this.fromDate, compareDate);
}
public LocalDate endDate() {
@@ -47,6 +47,7 @@ import org.apache.fineract.infrastructure.core.data.DataValidatorBuilder;
import org.apache.fineract.infrastructure.core.exception.InvalidJsonException;
import org.apache.fineract.infrastructure.core.exception.PlatformApiDataValidationException;
import org.apache.fineract.infrastructure.core.serialization.FromJsonHelper;
import org.apache.fineract.infrastructure.core.service.DateUtils;
import org.apache.fineract.portfolio.interestratechart.InterestRateChartApiConstants;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;
@@ -115,10 +116,8 @@ public class InterestRateChartDataValidator {
isPrimaryGroupingByAmount = false;
}
if (fromDate != null && toDate != null) {
if (fromDate.isAfter(toDate)) {
baseDataValidator.parameter(fromDateParamName).value(fromDate).failWithCode("from.date.is.after.to.date");
}
if (toDate != null && DateUtils.isAfter(fromDate, toDate)) {
baseDataValidator.parameter(fromDateParamName).value(fromDate).failWithCode("from.date.is.after.to.date");
}
// validate chart Slabs - mandatory when creating
@@ -177,11 +176,8 @@ public class InterestRateChartDataValidator {
if (isPrimaryGroupingByAmount == null) {
isPrimaryGroupingByAmount = false;
}
if (fromDate != null && toDate != null) {
if (fromDate.isAfter(toDate)) {
baseDataValidator.parameter(fromDateParamName).value(fromDate).failWithCode("from.date.is.after.to.date");
}
if (toDate != null && DateUtils.isAfter(fromDate, toDate)) {
baseDataValidator.parameter(fromDateParamName).value(fromDate).failWithCode("from.date.is.after.to.date");
}
validateChartSlabs(element, baseDataValidator, isPrimaryGroupingByAmount);
@@ -312,10 +312,7 @@ public class InterestRateChartSlabFields {
public boolean isBigDecimalSame(final BigDecimal obj1, final BigDecimal obj2) {
if (obj1 == null || obj2 == null) {
if (Objects.compare(obj1, obj2, Comparator.nullsFirst(Comparator.naturalOrder())) == 0 ? Boolean.TRUE : Boolean.FALSE) {
return true;
}
return false;
return Objects.compare(obj1, obj2, Comparator.nullsFirst(Comparator.naturalOrder())) == 0;
}
return obj1.compareTo(obj2) == 0;
}
@@ -326,7 +323,7 @@ public class InterestRateChartSlabFields {
}
public boolean isAmountRangeProvided() {
return (this.amountRangeFrom == null) ? false : true;
return this.amountRangeFrom != null;
}
public BigDecimal annualInterestRate() {
@@ -88,8 +88,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.getCreatedDate().orElse(null), LAST_MODIFIED_BY,
loan.getLastModifiedBy().orElse(null), LAST_MODIFIED_DATE, loan.getLastModifiedDate().orElse(null)));
Map.of(CREATED_BY, loan.getCreatedBy().orElse(null), CREATED_DATE, loan.getCreatedDateTime(), LAST_MODIFIED_BY,
loan.getLastModifiedBy().orElse(null), LAST_MODIFIED_DATE, loan.getLastModifiedDateTime()));
final ApiRequestJsonSerializationSettings settings = this.apiRequestParameterHelper.process(uriInfo.getQueryParameters());
return this.toApiJsonSerializerForMap.serialize(settings, auditFields);
}
@@ -108,8 +108,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.getCreatedDate().orElse(null), LAST_MODIFIED_BY, transaction.getLastModifiedBy().orElse(null),
LAST_MODIFIED_DATE, transaction.getLastModifiedDate().orElse(null)));
transaction.getCreatedDateTime(), LAST_MODIFIED_BY, transaction.getLastModifiedBy().orElse(null), LAST_MODIFIED_DATE,
transaction.getLastModifiedDateTime()));
final ApiRequestJsonSerializationSettings settings = this.apiRequestParameterHelper.process(uriInfo.getQueryParameters());
return this.toApiJsonSerializerForMap.serialize(settings, auditFields);
}
@@ -369,7 +369,7 @@ public class LoanAccountDomainServiceJpa implements LoanAccountDomainService {
final Integer transactionType, Integer installmentNumber) {
boolean isAccountTransfer = true;
checkClientOrGroupActive(loan);
if (loan.isChargedOff() && transactionDate.isBefore(loan.getChargedOffOnDate())) {
if (loan.isChargedOff() && DateUtils.isBefore(transactionDate, loan.getChargedOffOnDate())) {
throw new GeneralPlatformDomainRuleException("error.msg.transaction.date.cannot.be.earlier.than.charge.off.date", "Loan: "
+ loan.getId()
+ " backdated transaction is not allowed. Transaction date cannot be earlier than the charge-off date of the loan",
@@ -465,7 +465,7 @@ public class LoanAccountDomainServiceJpa implements LoanAccountDomainService {
boolean isAccountTransfer = true;
final Loan loan = this.loanAccountAssembler.assembleFrom(accountId);
checkClientOrGroupActive(loan);
if (loan.isChargedOff() && transactionDate.isBefore(loan.getChargedOffOnDate())) {
if (loan.isChargedOff() && DateUtils.isBefore(transactionDate, loan.getChargedOffOnDate())) {
throw new GeneralPlatformDomainRuleException("error.msg.transaction.date.cannot.be.earlier.than.charge.off.date", "Loan: "
+ loan.getId()
+ " backdated transaction is not allowed. Transaction date cannot be earlier than the charge-off date of the loan",
@@ -518,7 +518,7 @@ public class LoanAccountDomainServiceJpa implements LoanAccountDomainService {
final PaymentDetail paymentDetail, final String noteText, final ExternalId txnExternalId, final boolean isLoanToLoanTransfer) {
final Loan loan = this.loanAccountAssembler.assembleFrom(loanId);
checkClientOrGroupActive(loan);
if (loan.isChargedOff() && transactionDate.isBefore(loan.getChargedOffOnDate())) {
if (loan.isChargedOff() && DateUtils.isBefore(transactionDate, loan.getChargedOffOnDate())) {
throw new GeneralPlatformDomainRuleException("error.msg.transaction.date.cannot.be.earlier.than.charge.off.date", "Loan: "
+ loan.getId()
+ " backdated transaction is not allowed. Transaction date cannot be earlier than the charge-off date of the loan",
@@ -551,7 +551,7 @@ public class LoanAccountDomainServiceJpa implements LoanAccountDomainService {
@Override
public void reverseTransfer(final LoanTransaction loanTransaction) {
if (loanTransaction.getLoan().isChargedOff()
&& loanTransaction.getTransactionDate().isBefore(loanTransaction.getLoan().getChargedOffOnDate())) {
&& DateUtils.isBefore(loanTransaction.getTransactionDate(), loanTransaction.getLoan().getChargedOffOnDate())) {
throw new GeneralPlatformDomainRuleException("error.msg.transaction.date.cannot.be.earlier.than.charge.off.date",
"Loan transaction: " + loanTransaction.getId()
+ " reversal is not allowed before or on the date when the loan got charged-off",
@@ -614,10 +614,10 @@ public class LoanAccountDomainServiceJpa implements LoanAccountDomainService {
Set<LoanCharge> loanCharges = loan.getActiveCharges();
for (LoanRepaymentScheduleInstallment installment : installments) {
if (installment.getDueDate().isAfter(loan.getMaturityDate())) {
if (DateUtils.isAfter(installment.getDueDate(), loan.getMaturityDate())) {
accruedTill = DateUtils.getBusinessLocalDate();
}
if (!isOrganisationDateEnabled || organisationStartDate.isBefore(installment.getDueDate())) {
if (!isOrganisationDateEnabled || DateUtils.isBefore(organisationStartDate, installment.getDueDate())) {
generateLoanScheduleAccrualData(accruedTill, loanScheduleAccrualList, loanId, officeId, accrualStartDate,
repaymentFrequency, repayEvery, interestCalculatedFrom, loanProductId, currency, currencyData, loanCharges,
installment);
@@ -641,12 +641,12 @@ public class LoanAccountDomainServiceJpa implements LoanAccountDomainService {
final LocalDate interestCalculatedFrom, final Long loanProductId, final MonetaryCurrency currency,
final CurrencyData currencyData, final Set<LoanCharge> loanCharges, final LoanRepaymentScheduleInstallment installment) {
if (!accruedTill.isBefore(installment.getDueDate())
|| (accruedTill.isAfter(installment.getFromDate()) && !accruedTill.isAfter(installment.getDueDate()))) {
if (!DateUtils.isBefore(accruedTill, installment.getDueDate()) || (DateUtils.isAfter(accruedTill, installment.getFromDate())
&& !DateUtils.isAfter(accruedTill, installment.getDueDate()))) {
BigDecimal dueDateFeeIncome = BigDecimal.ZERO;
BigDecimal dueDatePenaltyIncome = BigDecimal.ZERO;
LocalDate chargesTillDate = installment.getDueDate();
if (!accruedTill.isAfter(installment.getDueDate())) {
if (!DateUtils.isAfter(accruedTill, installment.getDueDate())) {
chargesTillDate = accruedTill;
}
@@ -685,7 +685,7 @@ public class LoanAccountDomainServiceJpa implements LoanAccountDomainService {
@Override
public LoanTransaction creditBalanceRefund(final Loan loan, final LocalDate transactionDate, final BigDecimal transactionAmount,
final String noteText, final ExternalId externalId, PaymentDetail paymentDetail) {
if (loan.isChargedOff() && transactionDate.isBefore(loan.getChargedOffOnDate())) {
if (loan.isChargedOff() && DateUtils.isBefore(transactionDate, loan.getChargedOffOnDate())) {
throw new GeneralPlatformDomainRuleException("error.msg.transaction.date.cannot.be.earlier.than.charge.off.date", "Loan: "
+ loan.getId()
+ " backdated transaction is not allowed. Transaction date cannot be earlier than the charge-off date of the loan",
@@ -729,7 +729,7 @@ public class LoanAccountDomainServiceJpa implements LoanAccountDomainService {
final List<Long> existingReversedTransactionIds = new ArrayList<>();
final Money refundAmount = Money.of(loan.getCurrency(), transactionAmount);
if (loan.isChargedOff() && transactionDate.isBefore(loan.getChargedOffOnDate())) {
if (loan.isChargedOff() && DateUtils.isBefore(transactionDate, loan.getChargedOffOnDate())) {
throw new GeneralPlatformDomainRuleException("error.msg.transaction.date.cannot.be.earlier.than.charge.off.date", "Loan: "
+ loan.getId()
+ " backdated transaction is not allowed. Transaction date cannot be earlier than the charge-off date of the loan",
@@ -768,7 +768,7 @@ public class LoanAccountDomainServiceJpa implements LoanAccountDomainService {
@Override
public LoanTransaction foreCloseLoan(Loan loan, final LocalDate foreClosureDate, final String noteText, final ExternalId externalId,
Map<String, Object> changes) {
if (loan.isChargedOff() && foreClosureDate.isBefore(loan.getChargedOffOnDate())) {
if (loan.isChargedOff() && DateUtils.isBefore(foreClosureDate, loan.getChargedOffOnDate())) {
throw new GeneralPlatformDomainRuleException("error.msg.transaction.date.cannot.be.earlier.than.charge.off.date", "Loan: "
+ loan.getId()
+ " backdated transaction is not allowed. Transaction date cannot be earlier than the charge-off date of the loan",
@@ -785,7 +785,7 @@ public class LoanAccountDomainServiceJpa implements LoanAccountDomainService {
final ScheduleGeneratorDTO scheduleGeneratorDTO = null;
final LoanRepaymentScheduleInstallment foreCloseDetail = loan.fetchLoanForeclosureDetail(foreClosureDate);
if (loan.isPeriodicAccrualAccountingEnabledOnLoanProduct()
&& (loan.getAccruedTill() == null || !foreClosureDate.isEqual(loan.getAccruedTill()))) {
&& (loan.getAccruedTill() == null || !DateUtils.isEqual(foreClosureDate, loan.getAccruedTill()))) {
loan.reverseAccrualsAfter(foreClosureDate);
Money[] accruedReceivables = loan.getReceivableIncome(foreClosureDate);
Money interestPortion = foreCloseDetail.getInterestCharged(currency).minus(accruedReceivables[0]);
@@ -805,7 +805,7 @@ public class LoanAccountDomainServiceJpa implements LoanAccountDomainService {
loan.addLoanTransaction(accrualTransaction);
Set<LoanChargePaidBy> accrualCharges = accrualTransaction.getLoanChargesPaid();
for (LoanCharge loanCharge : loan.getActiveCharges()) {
boolean isDue = fromDate.isEqual(loan.getDisbursementDate())
boolean isDue = DateUtils.isEqual(fromDate, loan.getDisbursementDate())
? loanCharge.isDueForCollectionFromIncludingAndUpToAndIncluding(fromDate, foreClosureDate)
: loanCharge.isDueForCollectionFromAndUpToAndIncluding(fromDate, foreClosureDate);
if (loanCharge.isActive() && !loanCharge.isPaid() && (isDue || loanCharge.isInstalmentFee())) {
@@ -1,30 +0,0 @@
/**
* Licensed to the Apache Software Foundation (ASF) under one
* or more contributor license agreements. See the NOTICE file
* distributed with this work for additional information
* regarding copyright ownership. The ASF licenses this file
* to you under the Apache License, Version 2.0 (the
* "License"); you may not use this file except in compliance
* with the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing,
* software distributed under the License is distributed on an
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
* KIND, either express or implied. See the License for the
* specific language governing permissions and limitations
* under the License.
*/
package org.apache.fineract.portfolio.loanaccount.domain;
import java.util.Comparator;
import org.apache.fineract.portfolio.loanaccount.data.LoanTransactionData;
public class LoanRepaymentDataComparator implements Comparator<LoanTransactionData> {
@Override
public int compare(final LoanTransactionData o1, final LoanTransactionData o2) {
return o2.getDate().compareTo(o1.getDate());
}
}
@@ -29,10 +29,8 @@ public class LoanTermVariationsComparator implements Comparator<LoanTermVariatio
public int compare(final LoanTermVariations o1, final LoanTermVariations o2) {
int compareResult = 0;
final int comparsion = o1.getTermApplicableFrom().compareTo(o2.getTermApplicableFrom());
/**
* For Terms bearing the same effective date, we sort based on modified date (when available) and new inserted
* installment
**/
// For Terms bearing the same effective date, we sort based on modified date (when available) and new inserted
// installment
if (comparsion == 0) {
if (o2.getTermType().isDueDateVariation() || o2.getTermType().isInsertInstallment()) {
compareResult = 1;
@@ -27,6 +27,7 @@ import java.util.HashSet;
import java.util.List;
import java.util.Map;
import java.util.Set;
import org.apache.fineract.infrastructure.core.service.DateUtils;
import org.apache.fineract.infrastructure.core.service.MathUtil;
import org.apache.fineract.organisation.monetary.domain.MonetaryCurrency;
import org.apache.fineract.organisation.monetary.domain.Money;
@@ -312,7 +313,7 @@ public abstract class AbstractLoanRepaymentScheduleTransactionProcessor implemen
protected boolean isTransactionInAdvanceOfInstallment(final int installmentIndex,
final List<LoanRepaymentScheduleInstallment> installments, final LocalDate transactionDate) {
final LoanRepaymentScheduleInstallment currentInstallment = installments.get(installmentIndex);
return transactionDate.isBefore(currentInstallment.getDueDate());
return DateUtils.isBefore(transactionDate, currentInstallment.getDueDate());
}
/**
@@ -325,7 +326,7 @@ public abstract class AbstractLoanRepaymentScheduleTransactionProcessor implemen
protected boolean isTransactionALateRepaymentOnInstallment(final int installmentIndex,
final List<LoanRepaymentScheduleInstallment> installments, final LocalDate transactionDate) {
final LoanRepaymentScheduleInstallment currentInstallment = installments.get(installmentIndex);
return transactionDate.isAfter(currentInstallment.getDueDate());
return DateUtils.isAfter(transactionDate, currentInstallment.getDueDate());
}
private void recalculateChargeOffTransaction(ChangedTransactionDetail changedTransactionDetail, LoanTransaction loanTransaction,
@@ -477,7 +478,7 @@ public abstract class AbstractLoanRepaymentScheduleTransactionProcessor implemen
LocalDate pastDueDate = null;
for (final LoanRepaymentScheduleInstallment currentInstallment : installments) {
pastDueDate = currentInstallment.getDueDate();
if (!currentInstallment.isAdditional() && currentInstallment.getDueDate().isAfter(transactionDate)) {
if (!currentInstallment.isAdditional() && DateUtils.isAfter(currentInstallment.getDueDate(), transactionDate)) {
currentInstallment.addToCredits(transactionAmount.getAmount());
currentInstallment.addToPrincipal(transactionDate, transactionAmount);
if (repaidAmount.isGreaterThanZero()) {
@@ -491,7 +492,7 @@ public abstract class AbstractLoanRepaymentScheduleTransactionProcessor implemen
// If already exists an additional installment just update the due date and
// principal from the Loan chargeback / CBR transaction
} else if (currentInstallment.isAdditional()) {
if (transactionDate.isAfter(currentInstallment.getDueDate())) {
if (DateUtils.isAfter(transactionDate, currentInstallment.getDueDate())) {
currentInstallment.updateDueDate(transactionDate);
}
@@ -669,18 +670,19 @@ public abstract class AbstractLoanRepaymentScheduleTransactionProcessor implemen
if (loanCharge.getAmountOutstanding(currency).isGreaterThanZero() && !loanCharge.isDueAtDisbursement()) {
if (loanCharge.isInstalmentFee()) {
LoanInstallmentCharge unpaidLoanChargePerInstallment = loanCharge.getUnpaidInstallmentLoanCharge();
if (chargePerInstallment == null || chargePerInstallment.getRepaymentInstallment().getDueDate()
.isAfter(unpaidLoanChargePerInstallment.getRepaymentInstallment().getDueDate())) {
if (chargePerInstallment == null || DateUtils.isAfter(chargePerInstallment.getRepaymentInstallment().getDueDate(),
unpaidLoanChargePerInstallment.getRepaymentInstallment().getDueDate())) {
installemntCharge = loanCharge;
chargePerInstallment = unpaidLoanChargePerInstallment;
}
} else if (earliestUnpaidCharge == null || loanCharge.getDueLocalDate().isBefore(earliestUnpaidCharge.getDueLocalDate())) {
} else if (earliestUnpaidCharge == null
|| DateUtils.isBefore(loanCharge.getDueLocalDate(), earliestUnpaidCharge.getDueLocalDate())) {
earliestUnpaidCharge = loanCharge;
}
}
}
if (earliestUnpaidCharge == null || (chargePerInstallment != null
&& earliestUnpaidCharge.getDueLocalDate().isAfter(chargePerInstallment.getRepaymentInstallment().getDueDate()))) {
if (earliestUnpaidCharge == null || (chargePerInstallment != null && DateUtils.isAfter(earliestUnpaidCharge.getDueLocalDate(),
chargePerInstallment.getRepaymentInstallment().getDueDate()))) {
earliestUnpaidCharge = installemntCharge;
}
@@ -791,20 +793,20 @@ public abstract class AbstractLoanRepaymentScheduleTransactionProcessor implemen
if (loanCharge.isInstalmentFee()) {
LoanInstallmentCharge paidLoanChargePerInstallment = loanCharge
.getLastPaidOrPartiallyPaidInstallmentLoanCharge(currency);
if (chargePerInstallment == null
|| (paidLoanChargePerInstallment != null && chargePerInstallment.getRepaymentInstallment().getDueDate()
.isBefore(paidLoanChargePerInstallment.getRepaymentInstallment().getDueDate()))) {
if (chargePerInstallment == null || (paidLoanChargePerInstallment != null
&& DateUtils.isBefore(chargePerInstallment.getRepaymentInstallment().getDueDate(),
paidLoanChargePerInstallment.getRepaymentInstallment().getDueDate()))) {
installemntCharge = loanCharge;
chargePerInstallment = paidLoanChargePerInstallment;
}
} else if (latestPaidCharge == null || (loanCharge.isPaidOrPartiallyPaid(currency)
&& loanCharge.getDueLocalDate().isAfter(latestPaidCharge.getDueLocalDate()))) {
&& DateUtils.isAfter(loanCharge.getDueLocalDate(), latestPaidCharge.getDueLocalDate()))) {
latestPaidCharge = loanCharge;
}
}
}
if (latestPaidCharge == null || (chargePerInstallment != null
&& latestPaidCharge.getDueLocalDate().isAfter(chargePerInstallment.getRepaymentInstallment().getDueDate()))) {
&& DateUtils.isAfter(latestPaidCharge.getDueLocalDate(), chargePerInstallment.getRepaymentInstallment().getDueDate()))) {
latestPaidCharge = installemntCharge;
}
@@ -194,7 +194,7 @@ public class AdvancedPaymentScheduleTransactionProcessor extends AbstractLoanRep
switch (paymentAllocationType.getDueType()) {
case PAST_DUE -> {
currentInstallment = installments.stream().filter(LoanRepaymentScheduleInstallment::isNotFullyPaidOff)
.filter(e -> loanTransaction.getTransactionDate().isAfter(e.getDueDate()))
.filter(e -> loanTransaction.isAfter(e.getDueDate()))
.min(Comparator.comparing(LoanRepaymentScheduleInstallment::getInstallmentNumber)).orElse(null);
if (currentInstallment != null) {
LoanTransactionToRepaymentScheduleMapping loanTransactionToRepaymentScheduleMapping = getTransactionMapping(
@@ -206,7 +206,7 @@ public class AdvancedPaymentScheduleTransactionProcessor extends AbstractLoanRep
}
case DUE -> {
currentInstallment = installments.stream().filter(LoanRepaymentScheduleInstallment::isNotFullyPaidOff)
.filter(e -> loanTransaction.getTransactionDate().isEqual(e.getDueDate()))
.filter(e -> loanTransaction.isOn(e.getDueDate()))
.min(Comparator.comparing(LoanRepaymentScheduleInstallment::getInstallmentNumber)).orElse(null);
if (currentInstallment != null) {
LoanTransactionToRepaymentScheduleMapping loanTransactionToRepaymentScheduleMapping = getTransactionMapping(
@@ -222,14 +222,14 @@ public class AdvancedPaymentScheduleTransactionProcessor extends AbstractLoanRep
List<LoanRepaymentScheduleInstallment> currentInstallments = new ArrayList<>();
if (FutureInstallmentAllocationRule.REAMORTIZATION.equals(futureInstallmentAllocationRule)) {
currentInstallments = installments.stream().filter(LoanRepaymentScheduleInstallment::isNotFullyPaidOff)
.filter(e -> loanTransaction.getTransactionDate().isBefore(e.getDueDate())).toList();
.filter(e -> loanTransaction.isBefore(e.getDueDate())).toList();
} else if (FutureInstallmentAllocationRule.NEXT_INSTALLMENT.equals(futureInstallmentAllocationRule)) {
currentInstallments = installments.stream().filter(LoanRepaymentScheduleInstallment::isNotFullyPaidOff)
.filter(e -> loanTransaction.getTransactionDate().isBefore(e.getDueDate()))
.filter(e -> loanTransaction.isBefore(e.getDueDate()))
.min(Comparator.comparing(LoanRepaymentScheduleInstallment::getInstallmentNumber)).stream().toList();
} else if (FutureInstallmentAllocationRule.LAST_INSTALLMENT.equals(futureInstallmentAllocationRule)) {
currentInstallments = installments.stream().filter(LoanRepaymentScheduleInstallment::isNotFullyPaidOff)
.filter(e -> loanTransaction.getTransactionDate().isBefore(e.getDueDate()))
.filter(e -> loanTransaction.isBefore(e.getDueDate()))
.max(Comparator.comparing(LoanRepaymentScheduleInstallment::getInstallmentNumber)).stream().toList();
}
int numberOfInstallments = currentInstallments.size();
@@ -21,6 +21,7 @@ package org.apache.fineract.portfolio.loanaccount.domain.transactionprocessor.im
import java.time.LocalDate;
import java.util.List;
import java.util.Set;
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.loanaccount.domain.LoanCharge;
@@ -102,7 +103,7 @@ public class DuePenFeeIntPriInAdvancePriPenFeeIntLoanRepaymentScheduleTransactio
List<LoanCharge> orderedLoanChargesByDueDate = charges.stream().filter(LoanCharge::isActive).filter(LoanCharge::isChargePending)
.filter(loanCharge -> loanCharge.getEffectiveDueDate() == null
|| !loanCharge.getEffectiveDueDate().isAfter(transactionDate))
|| !DateUtils.isAfter(loanCharge.getEffectiveDueDate(), transactionDate))
.sorted(LoanChargeEffectiveDueDateComparator.INSTANCE).toList();
Money calculatedPenaltyCharge = Money.zero(currency);
Money calculatedFeeCharge = Money.zero(currency);
@@ -141,7 +142,7 @@ public class DuePenFeeIntPriInAdvancePriPenFeeIntLoanRepaymentScheduleTransactio
feeChargesPortion = feeChargesPortion.add(subFeePortion);
Money subInterestPortion;
if (ignoreDueDateCheck || !transactionDate.isBefore(currentInstallment.getDueDate())) {
if (ignoreDueDateCheck || !DateUtils.isBefore(transactionDate, currentInstallment.getDueDate())) {
subInterestPortion = currentInstallment.payInterestComponent(transactionDate, transactionAmountRemaining);
transactionAmountRemaining = transactionAmountRemaining.minus(subInterestPortion);
interestPortion = interestPortion.add(subInterestPortion);
@@ -21,6 +21,7 @@ package org.apache.fineract.portfolio.loanaccount.domain.transactionprocessor.im
import java.time.LocalDate;
import java.util.List;
import java.util.Set;
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.loanaccount.domain.LoanCharge;
@@ -102,7 +103,7 @@ public class DuePenIntPriFeeInAdvancePenIntPriFeeLoanRepaymentScheduleTransactio
List<LoanCharge> orderedLoanChargesByDueDate = charges.stream().filter(LoanCharge::isActive).filter(LoanCharge::isChargePending)
.filter(loanCharge -> loanCharge.getEffectiveDueDate() == null
|| !loanCharge.getEffectiveDueDate().isAfter(transactionDate))
|| !DateUtils.isAfter(loanCharge.getEffectiveDueDate(), transactionDate))
.sorted(LoanChargeEffectiveDueDateComparator.INSTANCE).toList();
Money calculatedPenaltyCharge = Money.zero(currency);
Money calculatedFeeCharge = Money.zero(currency);
@@ -129,13 +130,11 @@ public class DuePenIntPriFeeInAdvancePenIntPriFeeLoanRepaymentScheduleTransactio
penaltyChargesPortion = penaltyChargesPortion.add(subPenaltyPortion);
Money subInterestPortion;
if (ignoreDueDateCheck || !transactionDate.isBefore(currentInstallment.getDueDate())) {
if (ignoreDueDateCheck || !DateUtils.isBefore(transactionDate, currentInstallment.getDueDate())) {
subInterestPortion = currentInstallment.payInterestComponent(transactionDate, transactionAmountRemaining);
transactionAmountRemaining = transactionAmountRemaining.minus(subInterestPortion);
interestPortion = interestPortion.add(subInterestPortion);
}
if (ignoreDueDateCheck || !transactionDate.isBefore(currentInstallment.getDueDate())) {
Money subPrincipalPortion = currentInstallment.payPrincipalComponent(transactionDate, transactionAmountRemaining);
transactionAmountRemaining = transactionAmountRemaining.minus(subPrincipalPortion);
principalPortion = principalPortion.add(subPrincipalPortion);
@@ -21,6 +21,7 @@ package org.apache.fineract.portfolio.loanaccount.domain.transactionprocessor.im
import java.time.LocalDate;
import java.util.List;
import java.util.Set;
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.loanaccount.domain.LoanCharge;
@@ -85,9 +86,7 @@ public class HeavensFamilyLoanRepaymentScheduleTransactionProcessor extends Abst
final LoanRepaymentScheduleInstallment previousInstallment = installments.get(previousInstallmentIndex);
lastInstallmentDueDate = previousInstallment.getDueDate();
isInAdvance = !(transactionDate.isAfter(lastInstallmentDueDate) || transactionDate.isEqual(lastInstallmentDueDate));
return isInAdvance;
return DateUtils.isBefore(transactionDate, lastInstallmentDueDate);
}
/**
@@ -21,6 +21,7 @@ package org.apache.fineract.portfolio.loanaccount.domain.transactionprocessor.im
import java.time.LocalDate;
import java.util.List;
import java.util.Set;
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.loanaccount.domain.LoanCharge;
@@ -174,14 +175,12 @@ public class RBILoanRepaymentScheduleTransactionProcessor extends AbstractLoanRe
private LoanRepaymentScheduleInstallment nearestInstallment(final LocalDate transactionDate,
final List<LoanRepaymentScheduleInstallment> installments) {
LoanRepaymentScheduleInstallment nearest = installments.get(0);
LoanRepaymentScheduleInstallment nearest = installments.get(0); // installments must be sorted by dates
for (final LoanRepaymentScheduleInstallment installment : installments) {
if (installment.getDueDate().isBefore(transactionDate) || installment.getDueDate().isEqual(transactionDate)) {
nearest = installment;
} else if (installment.getDueDate().isAfter(transactionDate)) {
if (DateUtils.isBefore(transactionDate, installment.getDueDate())) {
break;
}
nearest = installment;
}
return nearest;
}
@@ -327,7 +327,7 @@ public class GuarantorDomainServiceImpl implements GuarantorDomainService {
if (loan.isApproved() && !loan.isDisbursed()) {
final List<SavingsAccountTransaction> transactions = new ArrayList<>();
for (final SavingsAccountTransaction transaction : savingsAccount.getTransactions()) {
if (!transaction.getTransactionDate().isAfter(loan.getApprovedOnDate())) {
if (!DateUtils.isAfter(transaction.getTransactionDate(), loan.getApprovedOnDate())) {
transactions.add(transaction);
}
}
@@ -187,7 +187,7 @@ public class GuarantorWritePlatformServiceJpaRepositoryIImpl implements Guaranto
private void validateGuarantorSavingsAccountActivationDateWithLoanSubmittedOnDate(final Loan loan,
final SavingsAccount savingsAccount) {
if (loan.getSubmittedOnDate().isBefore(savingsAccount.getActivationDate())) {
if (DateUtils.isBefore(loan.getSubmittedOnDate(), savingsAccount.getActivationDate())) {
throw new GeneralPlatformDomainRuleException(
"error.msg.guarantor.saving.account.activation.date.is.on.or.before.loan.submitted.on.date",
"Guarantor saving account activation date [" + savingsAccount.getActivationDate()
@@ -27,6 +27,7 @@ import java.util.Set;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.apache.fineract.infrastructure.configuration.domain.ConfigurationDomainService;
import org.apache.fineract.infrastructure.core.service.DateUtils;
import org.apache.fineract.infrastructure.event.business.domain.loan.LoanRescheduledDueHolidayBusinessEvent;
import org.apache.fineract.infrastructure.event.business.service.BusinessEventNotifierService;
import org.apache.fineract.organisation.holiday.domain.Holiday;
@@ -120,16 +121,15 @@ public class ApplyHolidaysToLoansTasklet implements Tasklet {
// Loop through all loanRepayments
List<LoanRepaymentScheduleInstallment> installments = loan.getRepaymentScheduleInstallments();
for (final LoanRepaymentScheduleInstallment loanRepaymentScheduleInstallment : installments) {
final LocalDate oldDueDate = loanRepaymentScheduleInstallment.getDueDate();
// update from date if it's not same as previous installment's due
// date.
if (!loanRepaymentScheduleInstallment.getFromDate().isEqual(tmpFromDate)) {
if (!DateUtils.isEqual(tmpFromDate, loanRepaymentScheduleInstallment.getFromDate())) {
loanRepaymentScheduleInstallment.updateFromDate(tmpFromDate);
}
if (oldDueDate.equals(holiday.getFromDate()) || oldDueDate.isAfter(holiday.getFromDate())) {
if (!DateUtils.isBefore(oldDueDate, holiday.getFromDate())) {
// FIXME: AA do we need to apply non-working days.
// Assuming holiday's repayment reschedule to date cannot be
// created on a non-working day.
@@ -146,7 +146,7 @@ public class ApplyHolidaysToLoansTasklet implements Tasklet {
LocalDate adjustedRescheduleToDate = null;
final LocalDate rescheduleToDate = holiday.getToDate();
for (final LoanRepaymentScheduleInstallment loanRepaymentScheduleInstallment : loan.getRepaymentScheduleInstallments()) {
if (rescheduleToDate.isEqual(loanRepaymentScheduleInstallment.getDueDate())) {
if (DateUtils.isEqual(rescheduleToDate, loanRepaymentScheduleInstallment.getDueDate())) {
adjustedRescheduleToDate = rescheduleToDate;
break;
} else {
@@ -160,9 +160,9 @@ public class ApplyHolidaysToLoansTasklet implements Tasklet {
private LocalDate doStandardMonthlyCheck(LocalDate adjustedRescheduleToDate, LocalDate rescheduleToDate,
LoanRepaymentScheduleInstallment loanRepaymentScheduleInstallment) {
// Standard Monthly Loan Holiday check
if (rescheduleToDate.isAfter(loanRepaymentScheduleInstallment.getDueDate())
&& rescheduleToDate.isBefore(loanRepaymentScheduleInstallment.getDueDate().plusDays(30))) {
adjustedRescheduleToDate = loanRepaymentScheduleInstallment.getDueDate();
LocalDate dueDate = loanRepaymentScheduleInstallment.getDueDate();
if (DateUtils.isAfter(rescheduleToDate, dueDate) && DateUtils.isBefore(rescheduleToDate, dueDate.plusDays(30))) {
adjustedRescheduleToDate = dueDate;
}
return adjustedRescheduleToDate;
}

Some files were not shown because too many files have changed in this diff Show More