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
@@ -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;
}
@@ -64,7 +64,7 @@ public class TransferFeeChargeForLoansTasklet implements Tasklet {
.retrieveInstallmentLoanCharges(chargeData.getId(), true);
PortfolioAccountData portfolioAccountData = null;
for (final LoanInstallmentChargeData installmentChargeData : chargePerInstallments) {
if (!installmentChargeData.getDueDate().isAfter(DateUtils.getBusinessLocalDate())) {
if (!DateUtils.isDateInTheFuture(installmentChargeData.getDueDate())) {
if (portfolioAccountData == null) {
portfolioAccountData = accountAssociationsReadPlatformService
.retriveLoanLinkedAssociation(chargeData.getLoanId());
@@ -79,7 +79,7 @@ public class TransferFeeChargeForLoansTasklet implements Tasklet {
transferFeeCharge(accountTransferDTO, errors);
}
}
} else if (chargeData.getDueDate() != null && !chargeData.getDueDate().isAfter(DateUtils.getBusinessLocalDate())) {
} else if (chargeData.getDueDate() != null && !DateUtils.isDateInTheFuture(chargeData.getDueDate())) {
final PortfolioAccountData portfolioAccountData = accountAssociationsReadPlatformService
.retriveLoanLinkedAssociation(chargeData.getLoanId());
final boolean isExceptionForBalanceCheck = false;
@@ -204,7 +204,7 @@ public abstract class AbstractLoanScheduleGenerator implements LoanScheduleGener
applyLoanVariationsForPartialScheduleGenerate(loanApplicationTerms, scheduleParams, interestRates,
interestRatesForInstallments);
if (!firstRepaymentdate.isAfter(scheduleParams.getActualRepaymentDate())) {
if (!DateUtils.isAfter(firstRepaymentdate, scheduleParams.getActualRepaymentDate())) {
isFirstRepayment = false;
}
}
@@ -243,7 +243,7 @@ public abstract class AbstractLoanScheduleGenerator implements LoanScheduleGener
continue;
}
if (scheduleParams.getPeriodStartDate().isAfter(scheduledDueDate)) {
if (DateUtils.isAfter(scheduleParams.getPeriodStartDate(), scheduledDueDate)) {
throw new ScheduleDateException("Due date can't be before period start date", scheduledDueDate);
}
@@ -254,8 +254,9 @@ public abstract class AbstractLoanScheduleGenerator implements LoanScheduleGener
// this block is to generate the schedule till the specified
// date(used for calculating preclosure)
boolean isCompletePeriod = true;
if (scheduleParams.getScheduleTillDate() != null && !scheduledDueDate.isBefore(scheduleParams.getScheduleTillDate())) {
if (!scheduledDueDate.isEqual(scheduleParams.getScheduleTillDate())) {
if (scheduleParams.getScheduleTillDate() != null
&& !DateUtils.isBefore(scheduledDueDate, scheduleParams.getScheduleTillDate())) {
if (!DateUtils.isEqual(scheduledDueDate, scheduleParams.getScheduleTillDate())) {
isCompletePeriod = false;
}
scheduledDueDate = scheduleParams.getScheduleTillDate();
@@ -420,7 +421,7 @@ public abstract class AbstractLoanScheduleGenerator implements LoanScheduleGener
currentDate = scheduleParams.getScheduleTillDate();
}
if (scheduleParams.applyInterestRecalculation() && scheduleParams.getLatePaymentMap().size() > 0
&& currentDate.isAfter(scheduleParams.getPeriodStartDate())) {
&& DateUtils.isAfter(currentDate, scheduleParams.getPeriodStartDate())) {
Money totalInterest = addInterestOnlyRepaymentScheduleForCurrentdate(mc, loanApplicationTerms, holidayDetailDTO, currency,
periods, currentDate, loanRepaymentScheduleTransactionProcessor, transactions, loanCharges, scheduleParams);
scheduleParams.addTotalCumulativeInterest(totalInterest);
@@ -449,7 +450,8 @@ public abstract class AbstractLoanScheduleGenerator implements LoanScheduleGener
Map<LocalDate, Money> periodCompoundingDetails = compoundingDetails.get(loanScheduleModelPeriod.periodFromDate());
if (periodCompoundingDetails != null) {
for (Map.Entry<LocalDate, Money> entry : periodCompoundingDetails.entrySet()) {
if (entry.getValue().isGreaterThanZero() && !entry.getKey().isAfter(loanScheduleModelPeriod.periodDueDate())) {
if (entry.getValue().isGreaterThanZero()
&& !DateUtils.isAfter(entry.getKey(), loanScheduleModelPeriod.periodDueDate())) {
LocalDate effectiveDate = entry.getKey();
if (loanApplicationTerms.allowCompoundingOnEod()) {
effectiveDate = effectiveDate.minusDays(1);
@@ -734,7 +736,7 @@ public abstract class AbstractLoanScheduleGenerator implements LoanScheduleGener
}
boolean updateLatePaymentMap = false;
final LocalDate transactionDate = detail.getTransactionDate();
if (transactionDate.isBefore(scheduledDueDate)) {
if (DateUtils.isBefore(transactionDate, scheduledDueDate)) {
if (scheduleParams.getLoanRepaymentScheduleTransactionProcessor() != null && scheduleParams
.getLoanRepaymentScheduleTransactionProcessor().isInterestFirstRepaymentScheduleTransactionProcessor()) {
if (detail.getTransaction().isWaiver()) {
@@ -748,8 +750,7 @@ public abstract class AbstractLoanScheduleGenerator implements LoanScheduleGener
processTransactions.clear();
currentTransactions.addAll(createCurrentTransactionList(detail));
if (!transactionDate.isEqual(scheduleParams.getPeriodStartDate()) || scheduleParams.isFirstPeriod()) {
if (!DateUtils.isEqual(transactionDate, scheduleParams.getPeriodStartDate()) || scheduleParams.isFirstPeriod()) {
int periodDays = Math.toIntExact(ChronoUnit.DAYS.between(scheduleParams.getPeriodStartDate(), transactionDate));
// calculates period start date for interest
// calculation as per the configuration
@@ -842,7 +843,7 @@ public abstract class AbstractLoanScheduleGenerator implements LoanScheduleGener
if (loanApplicationTerms.getPreClosureInterestCalculationStrategy().calculateTillRestFrequencyEnabled()) {
LocalDate applicableDate = getNextRestScheduleDate(transactionDate.minusDays(1), loanApplicationTerms,
holidayDetailDTO);
checkForOutstanding = transactionDate.isEqual(applicableDate);
checkForOutstanding = DateUtils.isEqual(transactionDate, applicableDate);
}
// reduces actual outstanding balance
@@ -878,7 +879,7 @@ public abstract class AbstractLoanScheduleGenerator implements LoanScheduleGener
} else if (scheduleParams.getLoanRepaymentScheduleTransactionProcessor() != null) {
LocalDate applicableDate = getNextRestScheduleDate(transactionDate.minusDays(1), loanApplicationTerms,
holidayDetailDTO);
if (applicableDate.isBefore(scheduledDueDate)) {
if (DateUtils.isBefore(applicableDate, scheduledDueDate)) {
List<LoanTransaction> currentTransactions = createCurrentTransactionList(detail);
Money unprocessed = scheduleParams.getLoanRepaymentScheduleTransactionProcessor()
.handleRepaymentSchedule(currentTransactions, currency, scheduleParams.getInstallments(), loanCharges);
@@ -937,7 +938,7 @@ public abstract class AbstractLoanScheduleGenerator implements LoanScheduleGener
}
}
if (arrears.isGreaterThanZero() && applicableDate.isBefore(lastRestDate)) {
if (arrears.isGreaterThanZero() && DateUtils.isBefore(applicableDate, lastRestDate)) {
handleLatePayments(loanApplicationTerms, holidayDetailDTO, currency, scheduleParams, lastRestDate, detail);
}
}
@@ -991,15 +992,15 @@ public abstract class AbstractLoanScheduleGenerator implements LoanScheduleGener
final BigDecimal chargesDueAtTimeOfDisbursement, LoanScheduleParams scheduleParams,
final Collection<LoanScheduleModelPeriod> periods, final LocalDate scheduledDueDate) {
for (Map.Entry<LocalDate, Money> disburseDetail : scheduleParams.getDisburseDetailMap().entrySet()) {
if (disburseDetail.getKey().isAfter(scheduleParams.getPeriodStartDate())
&& !disburseDetail.getKey().isAfter(scheduledDueDate)) {
if (DateUtils.isAfter(disburseDetail.getKey(), scheduleParams.getPeriodStartDate())
&& !DateUtils.isAfter(disburseDetail.getKey(), scheduledDueDate)) {
// validation check for amount not exceeds specified max
// amount as per the configuration
if (loanApplicationTerms.getMaxOutstandingBalance() != null && scheduleParams.getOutstandingBalance()
.plus(disburseDetail.getValue()).isGreaterThan(loanApplicationTerms.getMaxOutstandingBalance())) {
String errorMsg = "Outstanding balance must not exceed the amount: " + loanApplicationTerms.getMaxOutstandingBalance();
throw new MultiDisbursementOutstandingAmoutException(errorMsg,
loanApplicationTerms.getMaxOutstandingBalance().getAmount(), disburseDetail.getValue());
Money maxOutstandingBalance = loanApplicationTerms.getMaxOutstandingBalance();
if (scheduleParams.getOutstandingBalance().plus(disburseDetail.getValue()).isGreaterThan(maxOutstandingBalance)) {
String errorMsg = "Outstanding balance must not exceed the amount: " + maxOutstandingBalance;
throw new MultiDisbursementOutstandingAmoutException(errorMsg, maxOutstandingBalance.getAmount(),
disburseDetail.getValue());
}
// creates and add disbursement detail to the repayments
@@ -1045,7 +1046,7 @@ public abstract class AbstractLoanScheduleGenerator implements LoanScheduleGener
// due date changes should be applied only for that dueDate
if (loanApplicationTerms.getLoanTermVariations().hasDueDateVariation(scheduledDueDate)) {
LoanTermVariationsData loanTermVariationsData = loanApplicationTerms.getLoanTermVariations().nextDueDateVariation();
if (loanTermVariationsData.getTermVariationApplicableFrom().isEqual(modifiedScheduledDueDate)) {
if (DateUtils.isEqual(modifiedScheduledDueDate, loanTermVariationsData.getTermVariationApplicableFrom())) {
modifiedScheduledDueDate = loanTermVariationsData.getDateValue();
if (!loanTermVariationsData.isSpecificToInstallment()) {
scheduleParams.setActualRepaymentDate(modifiedScheduledDueDate);
@@ -1097,7 +1098,7 @@ public abstract class AbstractLoanScheduleGenerator implements LoanScheduleGener
loanTermVariationsData.setProcessed(true);
break;
case DELETE_INSTALLMENT:
if (loanTermVariationsData.getTermVariationApplicableFrom().isEqual(modifiedScheduledDueDate)) {
if (DateUtils.isEqual(modifiedScheduledDueDate, loanTermVariationsData.getTermVariationApplicableFrom())) {
skipPeriod = true;
loanTermVariationsData.setProcessed(true);
}
@@ -1205,7 +1206,7 @@ public abstract class AbstractLoanScheduleGenerator implements LoanScheduleGener
variationsData.add(loanTermVariationsData);
break;
case DELETE_INSTALLMENT:
if (loanTermVariationsData.getTermVariationApplicableFrom().isEqual(modifiedScheduledDueDate)) {
if (DateUtils.isEqual(modifiedScheduledDueDate, loanTermVariationsData.getTermVariationApplicableFrom())) {
skipPeriod = true;
variationsData.add(loanTermVariationsData);
}
@@ -1363,7 +1364,7 @@ public abstract class AbstractLoanScheduleGenerator implements LoanScheduleGener
Money outstanding = params.getOutstandingBalanceAsPerRest();
Money totalInterest = Money.zero(currency);
Money totalCumulativeInterest = Money.zero(currency);
double interestCalculationGraceOnRepaymentPeriodFraction = Double.valueOf(0);
double interestCalculationGraceOnRepaymentPeriodFraction = 0;
int periodNumberTemp = 1;
LocalDate lastRestDate = getNextRestScheduleDate(currentDate.minusDays(1), loanApplicationTerms, holidayDetailDTO);
Collection<LoanTermVariationsData> applicableVariations = loanApplicationTerms.getLoanTermVariations().getInterestRateChanges();
@@ -1371,10 +1372,9 @@ public abstract class AbstractLoanScheduleGenerator implements LoanScheduleGener
LocalDate additionalPeriodsStartDate = params.getPeriodStartDate();
do {
params.setActualRepaymentDate(this.scheduledDateGenerator.generateNextRepaymentDate(params.getActualRepaymentDate(),
loanApplicationTerms, isFirstRepayment));
if (params.getActualRepaymentDate().isAfter(currentDate)) {
if (DateUtils.isAfter(params.getActualRepaymentDate(), currentDate)) {
params.setActualRepaymentDate(currentDate);
}
@@ -1391,7 +1391,7 @@ public abstract class AbstractLoanScheduleGenerator implements LoanScheduleGener
LocalDate transactionDate = detail.getTransactionDate();
List<LoanTransaction> currentTransactions = createCurrentTransactionList(detail);
if (!params.getPeriodStartDate().isEqual(transactionDate)) {
if (!DateUtils.isEqual(transactionDate, params.getPeriodStartDate())) {
PrincipalInterest principalInterestForThisPeriod = calculatePrincipalInterestComponentsForPeriod(
this.paymentPeriodsInOneYearCalculator, interestCalculationGraceOnRepaymentPeriodFraction, totalInterest.zero(),
totalInterest.zero(), totalInterest.zero(), totalInterest.zero(), outstanding, loanApplicationTerms,
@@ -1447,15 +1447,13 @@ public abstract class AbstractLoanScheduleGenerator implements LoanScheduleGener
Money uncompounded = params.getUnCompoundedAmount();
Money compounded = uncompounded.zero();
for (Map.Entry<LocalDate, Money> mapEntry : params.getCompoundingMap().entrySet()) {
if (mapEntry.getKey().isAfter(params.getPeriodStartDate())) {
if (DateUtils.isAfter(mapEntry.getKey(), params.getPeriodStartDate())) {
compounded = compounded.plus(mapEntry.getValue());
}
}
if (compounded.isGreaterThanZero() && startDate.isEqual(additionalPeriodsStartDate)) {
params.setCompoundedInLastInstallment(uncompoundedFromLastInstallment);// uncompounded
// in
// last
// installment
if (compounded.isGreaterThanZero() && DateUtils.isEqual(startDate, additionalPeriodsStartDate)) {
// uncompounded in last installment
params.setCompoundedInLastInstallment(uncompoundedFromLastInstallment);
additionalPeriodsStartDate = additionalPeriodsStartDate.plusDays(1);
}
Money compoundedForThisPeriod = compounded.minus(uncompounded);
@@ -1466,14 +1464,14 @@ public abstract class AbstractLoanScheduleGenerator implements LoanScheduleGener
compoundingDate = compoundingDate.minusDays(1);
}
compoundingDate = getNextCompoundScheduleDate(compoundingDate, loanApplicationTerms, holidayDetailDTO);
if (compoundingDate.isEqual(params.getActualRepaymentDate())) {
if (DateUtils.isEqual(compoundingDate, params.getActualRepaymentDate())) {
params.getCompoundingMap().put(compoundingDate, uncompoundedForThisPeriod);
params.setUnCompoundedAmount(uncompoundedForThisPeriod.zero());
}
}
}
params.setPeriodStartDate(params.getActualRepaymentDate());
} while (params.getActualRepaymentDate().isBefore(currentDate) && !outstanding.isZero());
} while (DateUtils.isBefore(params.getActualRepaymentDate(), currentDate) && !outstanding.isZero());
if (totalInterest.isGreaterThanZero()) {
LoanScheduleModelRepaymentPeriod installment = LoanScheduleModelRepaymentPeriod.repayment(params.getInstalmentNumber(),
@@ -1503,7 +1501,7 @@ public abstract class AbstractLoanScheduleGenerator implements LoanScheduleGener
Collection<RecalculationDetail> applicableTransactions = new ArrayList<>();
if (applyInterestRecalculation && !Objects.isNull(transactions)) {
for (RecalculationDetail detail : transactions) {
if (!detail.getTransactionDate().isAfter(repaymentDate)) {
if (!DateUtils.isBefore(repaymentDate, detail.getTransactionDate())) {
applicableTransactions.add(detail);
}
}
@@ -1574,7 +1572,7 @@ public abstract class AbstractLoanScheduleGenerator implements LoanScheduleGener
List<LocalDate> removeFromprincipalPortionMap = new ArrayList<>();
Money outstandingBalance = outstandingBalanceAsPerRest;
for (Map.Entry<LocalDate, Money> principal : principalPortionMap.entrySet()) {
if (!principal.getKey().isAfter(scheduledDueDate)) {
if (!DateUtils.isAfter(principal.getKey(), scheduledDueDate)) {
if (addMapDetails) {
outstandingBalance = outstandingBalance.plus(principal.getValue());
} else {
@@ -1610,11 +1608,11 @@ public abstract class AbstractLoanScheduleGenerator implements LoanScheduleGener
Money appliedOnPrincipalVariationMap = Money.zero(currency);
Map<LocalDate, Money> temp = new HashMap<>();
for (LocalDate date : latePaymentCompoundingMap.keySet()) {
if (date.isBefore(lastRestDate)) {
if (DateUtils.isBefore(date, lastRestDate)) {
Money money = latePaymentCompoundingMap.get(date);
appliedOnPrincipalVariationMap = appliedOnPrincipalVariationMap.plus(money);
if (appliedOnPrincipalVariationMap.isLessThan(compoundedPortion)) {
if (date.isBefore(applicableDate)) {
if (DateUtils.isBefore(date, applicableDate)) {
updateMapWithAmount(principalVariationMap, money.negated(), date);
updateMapWithAmount(principalVariationMap, money, applicableDate);
}
@@ -1648,14 +1646,14 @@ public abstract class AbstractLoanScheduleGenerator implements LoanScheduleGener
Money totalCompoundingAmount = Money.zero(currency);
for (LoanRepaymentScheduleInstallment loanRepaymentScheduleInstallment : installments) {
if (loanRepaymentScheduleInstallment.isNotFullyPaidOff()
&& !loanRepaymentScheduleInstallment.getDueDate().isAfter(scheduledDueDate)
&& !DateUtils.isAfter(loanRepaymentScheduleInstallment.getDueDate(), scheduledDueDate)
&& !loanRepaymentScheduleInstallment.isRecalculatedInterestComponent()) {
LocalDate principalEffectiveDate = loanRepaymentScheduleInstallment.getDueDate();
if (applyRestFrequencyForPrincipal) {
principalEffectiveDate = getNextRestScheduleDate(loanRepaymentScheduleInstallment.getDueDate().minusDays(1),
loanApplicationTerms, holidayDetailDTO);
}
if (principalEffectiveDate.isBefore(currentDate)) {
if (DateUtils.isBefore(principalEffectiveDate, currentDate)) {
updateMapWithAmount(latePaymentMap, loanRepaymentScheduleInstallment.getPrincipalOutstanding(currency),
principalEffectiveDate);
totalCompoundingAmount = totalCompoundingAmount
@@ -1679,10 +1677,10 @@ public abstract class AbstractLoanScheduleGenerator implements LoanScheduleGener
for (LoanRepaymentScheduleInstallment loanRepaymentScheduleInstallment : params.getInstallments()) {
if (params.getCompoundingDateVariations().containsKey(loanRepaymentScheduleInstallment.getFromDate())) {
lastInstallmentIsPastDate = params.applyInterestRecalculation()
&& loanRepaymentScheduleInstallment.getDueDate().isBefore(DateUtils.getBusinessLocalDate());
&& DateUtils.isBeforeBusinessDate(loanRepaymentScheduleInstallment.getDueDate());
} else {
final boolean isPastDate = params.applyInterestRecalculation()
&& loanRepaymentScheduleInstallment.getDueDate().isBefore(DateUtils.getBusinessLocalDate());
&& DateUtils.isBeforeBusinessDate(loanRepaymentScheduleInstallment.getDueDate());
boolean periodHasCompoundingDate = false;
Money amountCharged = Money.zero(currency);
if (loanApplicationTerms.getInterestRecalculationCompoundingMethod() != null) {
@@ -1697,7 +1695,7 @@ public abstract class AbstractLoanScheduleGenerator implements LoanScheduleGener
holidayDetailDTO);
final LocalDate restDate = getNextRestScheduleDate(scheduledDueDate.minusDays(1), loanApplicationTerms,
holidayDetailDTO);
if (!compoundingEffectiveDate.isAfter(loanRepaymentScheduleInstallment.getDueDate())) {
if (!DateUtils.isAfter(compoundingEffectiveDate, loanRepaymentScheduleInstallment.getDueDate())) {
Money amountCompoundedFromLastPeriod = params.getCompoundedInLastInstallment();
if (amountCompoundedFromLastPeriod.isZero()) {
amountCompoundedFromLastPeriod = params.getUnCompoundedAmount();
@@ -1705,12 +1703,11 @@ public abstract class AbstractLoanScheduleGenerator implements LoanScheduleGener
totalCompoundedAmount = totalCompoundedAmount.minus(amountCompoundedFromLastPeriod);
periodHasCompoundingDate = true;
}
while (!compoundingEffectiveDate.isAfter(loanRepaymentScheduleInstallment.getDueDate())) {
if (compoundingEffectiveDate.isEqual(loanRepaymentScheduleInstallment.getDueDate())) {
while (!DateUtils.isAfter(compoundingEffectiveDate, loanRepaymentScheduleInstallment.getDueDate())) {
if (DateUtils.isEqual(compoundingEffectiveDate, loanRepaymentScheduleInstallment.getDueDate())) {
Money amountToBeCompounding = amountCharged.minus(totalCompoundedAmount);
updateMapWithAmount(compoundingMap, amountToBeCompounding, compoundingEffectiveDate);
totalCompoundedAmount = totalCompoundedAmount.plus(amountToBeCompounding);
} else if (compoundingMap.containsKey(compoundingEffectiveDate)) {
Money compounedAmount = compoundingMap.get(compoundingEffectiveDate);
totalCompoundedAmount = totalCompoundedAmount.plus(compounedAmount);
@@ -1738,7 +1735,7 @@ public abstract class AbstractLoanScheduleGenerator implements LoanScheduleGener
params.getCompoundingDateVariations().put(loanRepaymentScheduleInstallment.getFromDate(),
new TreeMap<>(params.getCompoundingMap()));
for (Map.Entry<LocalDate, Money> mapEntry : params.getCompoundingMap().entrySet()) {
if (!mapEntry.getKey().isAfter(loanRepaymentScheduleInstallment.getDueDate())) {
if (!DateUtils.isAfter(mapEntry.getKey(), loanRepaymentScheduleInstallment.getDueDate())) {
updateMapWithAmount(params.getPrincipalPortionMap(), mapEntry.getValue().negated(), mapEntry.getKey());
}
}
@@ -1805,7 +1802,7 @@ public abstract class AbstractLoanScheduleGenerator implements LoanScheduleGener
private void adjustCompoundedAmountWithPaidDetail(final Map<LocalDate, Money> principalPortionMap, final LocalDate lastRestDate,
final LocalDate amountApplicableDate, final LoanTransaction transaction, final LoanApplicationTerms loanApplicationTerms,
final MonetaryCurrency currency) {
if (!amountApplicableDate.isEqual(lastRestDate)) {
if (!DateUtils.isEqual(amountApplicableDate, lastRestDate)) {
Money compoundedIncome = fetchCompoundedArrears(loanApplicationTerms, currency, transaction);
updateMapWithAmount(principalPortionMap, compoundedIncome, amountApplicableDate);
updateMapWithAmount(principalPortionMap, compoundedIncome.negated(), lastRestDate);
@@ -1820,17 +1817,18 @@ public abstract class AbstractLoanScheduleGenerator implements LoanScheduleGener
LocalDate lastCompoundingDate = startDate;
LocalDate compoundingDate = startDate;
boolean addUncompounded = true;
while (compoundingDate.isBefore(endDate)) {
while (DateUtils.isBefore(compoundingDate, endDate)) {
if (loanApplicationTerms.allowCompoundingOnEod()) {
compoundingDate = compoundingDate.minusDays(1);
}
compoundingDate = getNextCompoundScheduleDate(compoundingDate, loanApplicationTerms, holidayDetailDTO);
if (compoundingDate.isBefore(endDate)) {
if (DateUtils.isBefore(compoundingDate, endDate)) {
boolean isFirst = DateUtils.isEqual(startDate, lastCompoundingDate);
Money feeChargesForInstallment = cumulativeFeeChargesDueWithin(lastCompoundingDate, compoundingDate, charges, currency,
null, loanApplicationTerms.getPrincipal(), null, false, lastCompoundingDate.isEqual(startDate));
null, loanApplicationTerms.getPrincipal(), null, false, isFirst);
Money penaltyChargesForInstallment = cumulativePenaltyChargesDueWithin(lastCompoundingDate, compoundingDate, charges,
currency, null, loanApplicationTerms.getPrincipal(), null, false, lastCompoundingDate.isEqual(startDate));
currency, null, loanApplicationTerms.getPrincipal(), null, false, isFirst);
Money compoundAmount = feeChargesForInstallment.plus(penaltyChargesForInstallment);
if (addUncompounded) {
compoundAmount = compoundAmount.plus(scheduleParams.getUnCompoundedAmount());
@@ -1904,16 +1902,15 @@ public abstract class AbstractLoanScheduleGenerator implements LoanScheduleGener
final LocalDate idealDisbursementDate, final LocalDate firstRepaymentdate,
final Boolean isInterestChargedFromDateSameAsDisbursalDateEnabled, final LocalDate expectedDisbursementDate) {
LocalDate periodStartDateApplicableForInterest = periodStartDate;
if (periodStartDate.isBefore(idealDisbursementDate) || firstRepaymentdate.isAfter(periodStartDate)) {
if (DateUtils.isBefore(periodStartDate, idealDisbursementDate) || DateUtils.isBefore(periodStartDate, firstRepaymentdate)) {
if (loanApplicationTerms.getInterestChargedFromLocalDate() != null) {
if (periodStartDate.isEqual(loanApplicationTerms.getExpectedDisbursementDate())
|| loanApplicationTerms.getInterestChargedFromLocalDate().isAfter(periodStartDate)) {
if (DateUtils.isEqual(periodStartDate, loanApplicationTerms.getExpectedDisbursementDate())
|| DateUtils.isBefore(periodStartDate, loanApplicationTerms.getInterestChargedFromLocalDate())) {
periodStartDateApplicableForInterest = loanApplicationTerms.getInterestChargedFromLocalDate();
}
} else if (loanApplicationTerms.getInterestChargedFromLocalDate() == null
&& isInterestChargedFromDateSameAsDisbursalDateEnabled) {
} else if (isInterestChargedFromDateSameAsDisbursalDateEnabled) {
periodStartDateApplicableForInterest = expectedDisbursementDate;
} else if (periodStartDate.isEqual(loanApplicationTerms.getExpectedDisbursementDate())) {
} else if (DateUtils.isEqual(periodStartDate, loanApplicationTerms.getExpectedDisbursementDate())) {
periodStartDateApplicableForInterest = idealDisbursementDate;
}
}
@@ -1969,7 +1966,7 @@ public abstract class AbstractLoanScheduleGenerator implements LoanScheduleGener
if (disbursementData.disbursementDate().equals(disbursementDate)) {
principal = principal.add(disbursementData.getPrincipal());
} else if (!excludePastUndisbursed || disbursementData.isDisbursed()
|| !disbursementData.disbursementDate().isBefore(DateUtils.getBusinessLocalDate())) {
|| !DateUtils.isBeforeBusinessDate(disbursementData.disbursementDate())) {
/*
* JW: sums up amounts by disbursal date in case of side-effect issues. Original assumed that there
* were no duplicate disbursal dates and 'put' each amount into the map keyed by date
@@ -2294,7 +2291,7 @@ public abstract class AbstractLoanScheduleGenerator implements LoanScheduleGener
// this will generate the next schedule due date and allows to
// process the installment only if recalculate from date is
// greater than due date
if (installment.getDueDate().isAfter(lastInstallmentDate)) {
if (DateUtils.isAfter(installment.getDueDate(), lastInstallmentDate)) {
if (totalCumulativePrincipal.isGreaterThanOrEqualTo(loanApplicationTerms.getTotalDisbursedAmount())) {
break;
}
@@ -2305,7 +2302,7 @@ public abstract class AbstractLoanScheduleGenerator implements LoanScheduleGener
do {
actualRepaymentDate = this.scheduledDateGenerator.generateNextRepaymentDate(actualRepaymentDate,
loanApplicationTerms, isFirstRepayment);
if (actualRepaymentDate.isAfter(rescheduleFrom) || actualRepaymentDate.isEqual(rescheduleFrom)) {
if (!DateUtils.isBefore(actualRepaymentDate, rescheduleFrom)) {
actualRepaymentDate = lastInstallmentDate;
}
isFirstRepayment = false;
@@ -2324,14 +2321,14 @@ public abstract class AbstractLoanScheduleGenerator implements LoanScheduleGener
}
}
if (hasDueDateVariation && !lastInstallmentDate.isEqual(installment.getDueDate())
&& !installment.getDueDate().equals(modifiedLastInstDate)) {
if (hasDueDateVariation && !DateUtils.isEqual(lastInstallmentDate, installment.getDueDate())
&& !DateUtils.isEqual(modifiedLastInstDate, installment.getDueDate())) {
lastInstallmentDate = prevLastInstDate;
actualRepaymentDate = lastInstallmentDate;
if (modifiedLastInstDate != null) {
loanApplicationTerms.getLoanTermVariations().previousDueDateVariation();
}
} else if (installment.getDueDate().equals(modifiedLastInstDate)) {
} else if (DateUtils.isEqual(modifiedLastInstDate, installment.getDueDate())) {
actualRepaymentDate = modifiedLastInstDate;
lastInstallmentDate = actualRepaymentDate;
dueDateVariationsDataList.add(variation1);
@@ -2356,8 +2353,8 @@ public abstract class AbstractLoanScheduleGenerator implements LoanScheduleGener
}
for (Map.Entry<LocalDate, Money> disburseDetail : disburseDetailMap.entrySet()) {
if (disburseDetail.getKey().isAfter(installment.getFromDate())
&& !disburseDetail.getKey().isAfter(installment.getDueDate())) {
if (DateUtils.isAfter(disburseDetail.getKey(), installment.getFromDate())
&& !DateUtils.isAfter(disburseDetail.getKey(), installment.getDueDate())) {
// creates and add disbursement detail to the repayments
// period
final LoanScheduleModelDisbursementPeriod disbursementPeriod = LoanScheduleModelDisbursementPeriod
@@ -2429,7 +2426,7 @@ public abstract class AbstractLoanScheduleGenerator implements LoanScheduleGener
// recalculatedInterestComponent installment shouldn't be
// considered while calculating fixed EMI amounts
int period = periodNumber;
if (!lastInstallmentDate.isEqual(installment.getDueDate())) {
if (!DateUtils.isEqual(lastInstallmentDate, installment.getDueDate())) {
period--;
}
reducePrincipal = fetchEarlyPaidAmount(installment.getPrincipal(currency), principalPortionCalculated, reducePrincipal,
@@ -2513,7 +2510,7 @@ public abstract class AbstractLoanScheduleGenerator implements LoanScheduleGener
int lastInterestAvilablePeriod = 0;
int processedPeriod = 0;
for (LoanRepaymentScheduleInstallment installment : repaymentScheduleInstallments) {
if (installment.getDueDate().isBefore(rescheduleFrom)) {
if (DateUtils.isBefore(installment.getDueDate(), rescheduleFrom)) {
newRepaymentScheduleInstallments.add(installment);
if (installment.getInterestCharged(currency).isGreaterThanZero()) {
lastInterestAvilablePeriod = installment.getInstallmentNumber();
@@ -2614,7 +2611,7 @@ public abstract class AbstractLoanScheduleGenerator implements LoanScheduleGener
}
compoundingDateVariations.put(installment.getFromDate(), compoundingMap);
if (totalCompounded.isGreaterThanZero()) {
final boolean isPastDate = installment.getDueDate().isBefore(DateUtils.getBusinessLocalDate());
final boolean isPastDate = DateUtils.isBeforeBusinessDate(installment.getDueDate());
final LocalDate restDate = getNextRestScheduleDate(installment.getDueDate().minusDays(1), loanApplicationTerms,
holidayDetailDTO);
if (isPastDate) {
@@ -26,6 +26,7 @@ import java.util.Collection;
import java.util.HashMap;
import java.util.Map;
import java.util.TreeMap;
import org.apache.fineract.infrastructure.core.service.DateUtils;
import org.apache.fineract.organisation.monetary.domain.Money;
import org.apache.fineract.portfolio.loanaccount.data.LoanTermVariationsData;
import org.apache.fineract.portfolio.loanproduct.domain.AmortizationMethod;
@@ -89,7 +90,7 @@ public class DecliningBalanceInterestLoanScheduleGenerator extends AbstractLoanS
for (Map.Entry<LocalDate, Money> principal : principalVariation.entrySet()) {
if (!principal.getKey().isAfter(periodEndDate)) {
if (!DateUtils.isAfter(principal.getKey(), periodEndDate)) {
int interestForDays = Math.toIntExact(ChronoUnit.DAYS.between(interestStartDate, principal.getKey()));
if (interestForDays > 0) {
final PrincipalInterest result = loanApplicationTerms.calculateTotalInterestForPeriod(calculator,
@@ -21,6 +21,7 @@ package org.apache.fineract.portfolio.loanaccount.loanschedule.domain;
import java.time.LocalDate;
import java.time.temporal.ChronoUnit;
import net.fortuna.ical4j.model.Recur;
import org.apache.fineract.infrastructure.core.service.DateUtils;
import org.apache.fineract.organisation.holiday.domain.Holiday;
import org.apache.fineract.organisation.holiday.service.HolidayUtil;
import org.apache.fineract.organisation.workingdays.data.AdjustedDateDetailsDTO;
@@ -92,7 +93,7 @@ public class DefaultScheduledDateGenerator implements ScheduledDateGenerator {
seedDate = currentCalendar.getStartDateLocalDate();
reccuringString = currentCalendar.getRecurrence();
} else {
seedDate = calendarHistory.getStartDateLocalDate();
seedDate = calendarHistory.getStartDate();
reccuringString = calendarHistory.getRecurrence();
}
@@ -177,7 +178,7 @@ public class DefaultScheduledDateGenerator implements ScheduledDateGenerator {
holidayDetailDTO.getHolidays())) != null) {
if (applicableHolidayForNewAdjustedDate.getReScheduleType().isResheduleToNextRepaymentDate()) {
LocalDate nextRepaymentPeriodDueDate = adjustedDateDetailsDTO.getChangedActualRepaymentDate();
while (!nextRepaymentPeriodDueDate.isAfter(adjustedDateDetailsDTO.getChangedScheduleDate())) {
while (!DateUtils.isAfter(nextRepaymentPeriodDueDate, adjustedDateDetailsDTO.getChangedScheduleDate())) {
nextRepaymentPeriodDueDate = generateNextRepaymentDate(nextRepaymentPeriodDueDate, loanApplicationTerms,
isFirstRepayment);
}
@@ -208,14 +209,13 @@ public class DefaultScheduledDateGenerator implements ScheduledDateGenerator {
.getRepaymentRescheduleType(holidayDetailDTO.getWorkingDays());
if (repaymentRescheduleType.isMoveToNextRepaymentDay()) {
while (WorkingDaysUtil.isNonWorkingDay(holidayDetailDTO.getWorkingDays(),
adjustedDateDetailsDTO.getNextRepaymentPeriodDueDate())
|| adjustedDateDetailsDTO.getChangedScheduleDate()
.isAfter(adjustedDateDetailsDTO.getNextRepaymentPeriodDueDate())) {
final LocalDate nextRepaymentPeriodDueDate = generateNextRepaymentDate(
adjustedDateDetailsDTO.getNextRepaymentPeriodDueDate(), loanApplicationTerms, isFirstRepayment);
adjustedDateDetailsDTO.setNextRepaymentPeriodDueDate(nextRepaymentPeriodDueDate);
LocalDate nextRepaymentPeriodDueDate = adjustedDateDetailsDTO.getNextRepaymentPeriodDueDate();
while (WorkingDaysUtil.isNonWorkingDay(holidayDetailDTO.getWorkingDays(), nextRepaymentPeriodDueDate)
|| DateUtils.isAfter(adjustedDateDetailsDTO.getChangedScheduleDate(), nextRepaymentPeriodDueDate)) {
nextRepaymentPeriodDueDate = generateNextRepaymentDate(nextRepaymentPeriodDueDate, loanApplicationTerms,
isFirstRepayment);
}
adjustedDateDetailsDTO.setNextRepaymentPeriodDueDate(nextRepaymentPeriodDueDate);
}
WorkingDaysUtil.updateWorkingDayIfRepaymentDateIsNonWorkingDay(adjustedDateDetailsDTO, holidayDetailDTO.getWorkingDays());
}
@@ -260,7 +260,7 @@ public class DefaultScheduledDateGenerator implements ScheduledDateGenerator {
isScheduledDate = (weekDiff % repaidEvery) == 0;
if (isScheduledDate) {
LocalDate modifiedDate = startDate.plusWeeks(weekDiff);
isScheduledDate = modifiedDate.isEqual(date);
isScheduledDate = DateUtils.isEqual(modifiedDate, date);
}
break;
case MONTHS:
@@ -268,7 +268,7 @@ public class DefaultScheduledDateGenerator implements ScheduledDateGenerator {
isScheduledDate = (monthDiff % repaidEvery) == 0;
if (isScheduledDate) {
LocalDate modifiedDate = startDate.plusMonths(monthDiff);
isScheduledDate = modifiedDate.isEqual(date);
isScheduledDate = DateUtils.isEqual(modifiedDate, date);
}
break;
case YEARS:
@@ -276,7 +276,7 @@ public class DefaultScheduledDateGenerator implements ScheduledDateGenerator {
isScheduledDate = (yearDiff % repaidEvery) == 0;
if (isScheduledDate) {
LocalDate modifiedDate = startDate.plusYears(yearDiff);
isScheduledDate = modifiedDate.isEqual(date);
isScheduledDate = DateUtils.isEqual(modifiedDate, date);
}
break;
case INVALID:
@@ -332,7 +332,7 @@ public class DefaultScheduledDateGenerator implements ScheduledDateGenerator {
LocalDate generatedDate = loanApplicationTerms.getExpectedDisbursementDate();
boolean isFirstRepayment = true;
while (!generatedDate.isAfter(lastRepaymentDate)) {
while (!DateUtils.isAfter(generatedDate, lastRepaymentDate)) {
generatedDate = generateNextRepaymentDate(generatedDate, loanApplicationTerms, isFirstRepayment);
isFirstRepayment = false;
}
@@ -351,7 +351,7 @@ public class DefaultScheduledDateGenerator implements ScheduledDateGenerator {
isFirstRepayment = false;
}
LocalDate adjustedDate = generatedDate;
while (!adjustedDate.isAfter(lastRepaymentDate)) {
while (!DateUtils.isAfter(adjustedDate, lastRepaymentDate)) {
generatedDate = generateNextRepaymentDate(generatedDate, loanApplicationTerms, isFirstRepayment);
adjustedDate = adjustRepaymentDate(generatedDate, loanApplicationTerms, holidayDetailDTO).getChangedScheduleDate();
isFirstRepayment = false;
@@ -431,7 +431,7 @@ public class LoanScheduleAssembler {
LoanTermVariationsData loanTermVariation = new LoanTermVariationsData(
LoanEnumerations.loanVariationType(LoanTermVariationType.INTEREST_RATE), periodData.getFromDateAsLocalDate(),
periodData.getInterestRate(), dateValue, isSpecificToInstallment);
if (!interestRateStartDate.isBefore(periodData.getFromDateAsLocalDate())) {
if (!DateUtils.isBefore(interestRateStartDate, periodData.getFromDateAsLocalDate())) {
interestRateStartDate = periodData.getFromDateAsLocalDate();
annualNominalInterestRate = periodData.getInterestRate();
}
@@ -753,7 +753,7 @@ public class LoanScheduleAssembler {
LocalDate lastDate = loan.getExpectedDisbursedOnLocalDate();
for (LoanRepaymentScheduleInstallment installment : installments) {
dueDates.add(installment.getDueDate());
if (lastDate.isBefore(installment.getDueDate())) {
if (DateUtils.isBefore(lastDate, installment.getDueDate())) {
lastDate = installment.getDueDate();
}
if (graceOnPrincipal.equals(installment.getInstallmentNumber())) {
@@ -781,14 +781,14 @@ public class LoanScheduleAssembler {
} else {
dueDates.add(termVariations.fetchTermApplicaDate());
}
if (!graceApplicable.isBefore(termVariations.fetchTermApplicaDate())) {
if (!DateUtils.isBefore(graceApplicable, termVariations.fetchTermApplicaDate())) {
baseDataValidator.reset().failWithCodeNoParameterAddedToErrorCode(
"variable.schedule.insert.not.allowed.before.grace.period", "Loan schedule insert request invalid");
}
if (termVariations.fetchTermApplicaDate().isAfter(lastDate)) {
if (DateUtils.isAfter(termVariations.fetchTermApplicaDate(), lastDate)) {
baseDataValidator.reset().failWithCodeNoParameterAddedToErrorCode(
"variable.schedule.insert.not.allowed.after.last.period.date", "Loan schedule insert request invalid");
} else if (termVariations.fetchTermApplicaDate().isBefore(loan.getExpectedDisbursedOnLocalDate())) {
} else if (DateUtils.isBefore(termVariations.fetchTermApplicaDate(), loan.getExpectedDisbursedOnLocalDate())) {
baseDataValidator.reset().failWithCodeNoParameterAddedToErrorCode(
"variable.schedule.insert.not.allowed.before.disbursement.date", "Loan schedule insert request invalid");
}
@@ -800,14 +800,13 @@ public class LoanScheduleAssembler {
baseDataValidator.reset().failWithCodeNoParameterAddedToErrorCode("variable.schedule.remove.date.invalid",
"Loan schedule remove request invalid");
}
if (termVariations.fetchTermApplicaDate().isEqual(lastDate)) {
if (DateUtils.isEqual(lastDate, termVariations.fetchTermApplicaDate())) {
baseDataValidator.reset().failWithCodeNoParameterAddedToErrorCode(
"variable.schedule.delete.not.allowed.for.last.period.date", "Loan schedule remove request invalid");
}
break;
case DUE_DATE:
if (dueDates.contains(termVariations.fetchTermApplicaDate())) {
if (overlappings.contains(termVariations.fetchTermApplicaDate())) {
overlappings.remove(termVariations.fetchTermApplicaDate());
} else {
@@ -822,17 +821,17 @@ public class LoanScheduleAssembler {
} else {
dueDates.add(termVariations.fetchDateValue());
}
if (termVariations.fetchDateValue().isBefore(loan.getExpectedDisbursedOnLocalDate())) {
if (DateUtils.isBefore(termVariations.fetchDateValue(), loan.getExpectedDisbursedOnLocalDate())) {
baseDataValidator.reset().failWithCodeNoParameterAddedToErrorCode(
"variable.schedule.insert.not.allowed.before.disbursement.date", "Loan schedule insert request invalid");
}
if (termVariations.fetchTermApplicaDate().isEqual(lastDate)) {
if (DateUtils.isEqual(lastDate, termVariations.fetchTermApplicaDate())) {
lastDate = termVariations.fetchDateValue();
}
break;
case PRINCIPAL_AMOUNT:
case EMI_AMOUNT:
if (!graceApplicable.isBefore(termVariations.fetchTermApplicaDate())) {
if (!DateUtils.isBefore(graceApplicable, termVariations.fetchTermApplicaDate())) {
baseDataValidator.reset().failWithCodeNoParameterAddedToErrorCode(
"variable.schedule.amount.update.not.allowed.before.grace.period", "Loan schedule modify request invalid");
}
@@ -840,7 +839,7 @@ public class LoanScheduleAssembler {
baseDataValidator.reset().failWithCodeNoParameterAddedToErrorCode(
"variable.schedule.amount.update.from.date.invalid", "Loan schedule modify request invalid");
}
if (termVariations.fetchTermApplicaDate().isEqual(lastDate)) {
if (DateUtils.isEqual(termVariations.fetchTermApplicaDate(), lastDate)) {
baseDataValidator.reset().failWithCodeNoParameterAddedToErrorCode(
"variable.schedule.amount.update.not.allowed.for.last.period", "Loan schedule modify request invalid");
}
@@ -941,7 +940,7 @@ public class LoanScheduleAssembler {
}
if (dueDateVariations.containsKey(loanTermVariations.fetchTermApplicaDate())) {
LoanTermVariations existingVariation = dueDateVariations.get(loanTermVariations.fetchTermApplicaDate());
if (existingVariation.fetchTermApplicaDate().isEqual(loanTermVariations.fetchDateValue())) {
if (DateUtils.isEqual(existingVariation.fetchTermApplicaDate(), loanTermVariations.fetchDateValue())) {
variations.remove(existingVariation);
} else {
existingVariation.setTermApplicableFrom(loanTermVariations.getDateValue());
@@ -1086,21 +1085,16 @@ public class LoanScheduleAssembler {
final LocalDate expectedDisbursementDate, final PeriodFrequencyType repaymentPeriodFrequencyType,
final Integer minimumDaysBetweenDisbursalAndFirstRepayment, final Calendar calendar, final LocalDate submittedOnDate,
final RepaymentStartDateType repaymentStartDateType) {
LocalDate derivedFirstRepayment = null;
final LocalDate dateBasedOnMinimumDaysBetweenDisbursalAndFirstRepayment = RepaymentStartDateType.DISBURSEMENT_DATE.equals(
repaymentStartDateType) ? expectedDisbursementDate.plusDays(minimumDaysBetweenDisbursalAndFirstRepayment) : submittedOnDate;
if (calendar != null) {
final LocalDate refernceDateForCalculatingFirstRepaymentDate = expectedDisbursementDate;
derivedFirstRepayment = deriveFirstRepaymentDateForLoans(repaymentEvery, expectedDisbursementDate,
refernceDateForCalculatingFirstRepaymentDate, repaymentPeriodFrequencyType,
minimumDaysBetweenDisbursalAndFirstRepayment, calendar, submittedOnDate, repaymentStartDateType);
} /*** Individual or group account, or JLG not linked to a meeting ***/
else {
derivedFirstRepayment = deriveFirstRepaymentDateForLoans(repaymentEvery, expectedDisbursementDate, expectedDisbursementDate,
repaymentPeriodFrequencyType, minimumDaysBetweenDisbursalAndFirstRepayment, calendar, submittedOnDate,
repaymentStartDateType);
} else { // Individual or group account, or JLG not linked to a meeting
LocalDate dateBasedOnRepaymentFrequency;
// Derive the first repayment date as greater date among
// (disbursement date + plus frequency) or
@@ -1121,16 +1115,15 @@ public class LoanScheduleAssembler {
? expectedDisbursementDate.plusMonths(repaymentEvery)
: submittedOnDate.plusMonths(repaymentEvery);
} /** yearly loan **/
else {
} else { // yearly loan
dateBasedOnRepaymentFrequency = RepaymentStartDateType.DISBURSEMENT_DATE.equals(repaymentStartDateType)
? expectedDisbursementDate.plusYears(repaymentEvery)
: submittedOnDate.plusYears(repaymentEvery);
}
derivedFirstRepayment = dateBasedOnRepaymentFrequency.isAfter(dateBasedOnMinimumDaysBetweenDisbursalAndFirstRepayment)
? dateBasedOnRepaymentFrequency
: dateBasedOnMinimumDaysBetweenDisbursalAndFirstRepayment;
derivedFirstRepayment = DateUtils.isAfter(dateBasedOnRepaymentFrequency,
dateBasedOnMinimumDaysBetweenDisbursalAndFirstRepayment) ? dateBasedOnRepaymentFrequency
: dateBasedOnMinimumDaysBetweenDisbursalAndFirstRepayment;
}
return derivedFirstRepayment;
@@ -1148,7 +1141,7 @@ public class LoanScheduleAssembler {
final LocalDate minimumFirstRepaymentDate = RepaymentStartDateType.DISBURSEMENT_DATE.equals(repaymentStartDateType)
? expectedDisbursementDate.plusDays(minimumDaysBetweenDisbursalAndFirstRepayment)
: submittedOnDate;
return minimumFirstRepaymentDate.isBefore(derivedFirstRepayment) ? derivedFirstRepayment
return DateUtils.isBefore(minimumFirstRepaymentDate, derivedFirstRepayment) ? derivedFirstRepayment
: deriveFirstRepaymentDateForLoans(repaymentEvery, expectedDisbursementDate, derivedFirstRepayment,
repaymentPeriodFrequencyType, minimumDaysBetweenDisbursalAndFirstRepayment, calendar, submittedOnDate,
repaymentStartDateType);
@@ -1156,9 +1149,8 @@ public class LoanScheduleAssembler {
private void validateMinimumDaysBetweenDisbursalAndFirstRepayment(final LocalDate disbursalDate, final LocalDate firstRepaymentDate,
final Integer minimumDaysBetweenDisbursalAndFirstRepayment) {
final LocalDate minimumFirstRepaymentDate = disbursalDate.plusDays(minimumDaysBetweenDisbursalAndFirstRepayment);
if (firstRepaymentDate.isBefore(minimumFirstRepaymentDate)) {
if (DateUtils.isBefore(firstRepaymentDate, minimumFirstRepaymentDate)) {
throw new MinDaysBetweenDisbursalAndFirstRepaymentViolationException(disbursalDate, firstRepaymentDate,
minimumDaysBetweenDisbursalAndFirstRepayment);
}
@@ -168,7 +168,7 @@ public class LoanScheduleCalculationPlatformServiceImpl implements LoanScheduleC
List<LoanRepaymentScheduleInstallment> installments = loan.getRepaymentScheduleInstallments();
for (final LoanRepaymentScheduleInstallment currentInstallment : installments) {
if (currentInstallment.isNotFullyPaidOff()) {
if (!currentInstallment.getDueDate().isAfter(today)) {
if (!DateUtils.isAfter(currentInstallment.getDueDate(), today)) {
totalPrincipal = totalPrincipal.plus(currentInstallment.getPrincipalOutstanding(currency));
}
}
@@ -190,7 +190,7 @@ public class LoanScheduleCalculationPlatformServiceImpl implements LoanScheduleC
LoanScheduleData scheduleDate = model.toData();
Collection<LoanSchedulePeriodData> periodDatas = scheduleDate.getPeriods();
for (LoanSchedulePeriodData periodData : periodDatas) {
if ((periodData.getDueDate().isEqual(today) || periodData.getDueDate().isAfter(today)) && isNewPaymentRequired) {
if (isNewPaymentRequired && !DateUtils.isBefore(periodData.getDueDate(), today)) {
LoanSchedulePeriodData loanSchedulePeriodData = LoanSchedulePeriodData.repaymentOnlyPeriod(periodData.getPeriod(),
periodData.getFromDate(), periodData.getDueDate(), totalPrincipal.getAmount(),
periodData.getPrincipalLoanBalanceOutstanding(), interestDue.getAmount(),
@@ -199,7 +199,7 @@ public class LoanScheduleCalculationPlatformServiceImpl implements LoanScheduleC
totalPrincipal.plus(interestDue).getAmount());
futureInstallments.add(loanSchedulePeriodData);
isNewPaymentRequired = false;
} else if (periodData.getDueDate().isAfter(today)) {
} else if (DateUtils.isAfter(periodData.getDueDate(), today)) {
futureInstallments.add(periodData);
}
@@ -239,7 +239,7 @@ public class LoanScheduleCalculationPlatformServiceImpl implements LoanScheduleC
for (LoanRepaymentScheduleInstallment installment : installments) {
if (loanDisbursementDetails != null
&& !loanDisbursementDetails.expectedDisbursementDateAsLocalDate().isAfter(installment.getDueDate())) {
&& !DateUtils.isAfter(loanDisbursementDetails.expectedDisbursementDateAsLocalDate(), installment.getDueDate())) {
outstanding = outstanding.plus(loanDisbursementDetails.principal());
principal = principal.plus(loanDisbursementDetails.principal());
if (disbursementItr.hasNext()) {
@@ -73,7 +73,7 @@ public class LoanScheduleHistoryWritePlatformServiceImpl implements LoanSchedule
final BigDecimal penaltyCharges = repaymentScheduleInstallment.getPenaltyChargesCharged(currency).getAmount();
Map<String, Object> oldDates = null;
OffsetDateTime createdOnDate = DateUtils.getOffsetDateTimeOfTenantWithMostPrecision();
OffsetDateTime createdOnDate = DateUtils.getAuditOffsetDateTime();
LocalDateTime oldCreatedOnDate = null;
LocalDateTime oldLastModifiedOnDate = null;
if (repaymentScheduleInstallment.getCreatedDate().isPresent()) {
@@ -89,7 +89,7 @@ public class LoanScheduleHistoryWritePlatformServiceImpl implements LoanSchedule
final Long lastModifiedByUser = repaymentScheduleInstallment.getLastModifiedBy()
.orElse(platformSecurityContext.authenticatedUser().getId());
OffsetDateTime lastModifiedOnDate = DateUtils.getOffsetDateTimeOfTenantWithMostPrecision();
OffsetDateTime lastModifiedOnDate = DateUtils.getAuditOffsetDateTime();
if (repaymentScheduleInstallment.getLastModifiedDate().isPresent()) {
lastModifiedOnDate = repaymentScheduleInstallment.getLastModifiedDate().get();
} else if (repaymentScheduleInstallment.getId() != null && oldDates == null) {
@@ -38,6 +38,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.loanaccount.domain.Loan;
import org.apache.fineract.portfolio.loanaccount.domain.LoanCharge;
import org.apache.fineract.portfolio.loanaccount.domain.LoanRepaymentScheduleInstallment;
@@ -105,7 +106,7 @@ public class LoanRescheduleRequestDataValidator {
jsonElement);
dataValidatorBuilder.reset().parameter(RescheduleLoansApiConstants.submittedOnDateParamName).value(submittedOnDate).notNull();
if (submittedOnDate != null && loan.getDisbursementDate().isAfter(submittedOnDate)) {
if (submittedOnDate != null && DateUtils.isAfter(loan.getDisbursementDate(), submittedOnDate)) {
dataValidatorBuilder.reset().parameter(RescheduleLoansApiConstants.submittedOnDateParamName)
.failWithCode("before.loan.disbursement.date", "Submission date cannot be before the loan disbursement date");
}
@@ -161,7 +162,7 @@ public class LoanRescheduleRequestDataValidator {
final LocalDate adjustedDueDate = this.fromJsonHelper.extractLocalDateNamed(RescheduleLoansApiConstants.adjustedDueDateParamName,
jsonElement);
if (adjustedDueDate != null && rescheduleFromDate != null && adjustedDueDate.isBefore(rescheduleFromDate)) {
if (adjustedDueDate != null && DateUtils.isBefore(adjustedDueDate, rescheduleFromDate)) {
dataValidatorBuilder.reset().parameter(RescheduleLoansApiConstants.rescheduleFromDateParamName).failWithCode(
"adjustedDueDate.before.rescheduleFromDate", "Adjusted due date cannot be before the reschedule from date");
}
@@ -212,7 +213,7 @@ public class LoanRescheduleRequestDataValidator {
LocalDate rescheduleFromDate = installment.getFromDate();
Collection<LoanCharge> charges = loan.getLoanCharges();
for (LoanCharge loanCharge : charges) {
if (loanCharge.isOverdueInstallmentCharge() && loanCharge.getDueLocalDate().isAfter(rescheduleFromDate)) {
if (loanCharge.isOverdueInstallmentCharge() && DateUtils.isAfter(loanCharge.getDueLocalDate(), rescheduleFromDate)) {
dataValidatorBuilder.failWithCodeNoParameterAddedToErrorCode("not.allowed.due.to.overdue.charges");
break;
}
@@ -247,7 +248,7 @@ public class LoanRescheduleRequestDataValidator {
jsonElement);
dataValidatorBuilder.reset().parameter(RescheduleLoansApiConstants.approvedOnDateParam).value(approvedOnDate).notNull();
if (approvedOnDate != null && loanRescheduleRequest.getSubmittedOnDate().isAfter(approvedOnDate)) {
if (approvedOnDate != null && DateUtils.isAfter(loanRescheduleRequest.getSubmittedOnDate(), approvedOnDate)) {
dataValidatorBuilder.reset().parameter(RescheduleLoansApiConstants.approvedOnDateParam).failWithCode("before.submission.date",
"Approval date cannot be before the request submission date.");
}
@@ -319,7 +320,7 @@ public class LoanRescheduleRequestDataValidator {
jsonElement);
dataValidatorBuilder.reset().parameter(RescheduleLoansApiConstants.rejectedOnDateParam).value(rejectedOnDate).notNull();
if (rejectedOnDate != null && loanRescheduleRequest.getSubmittedOnDate().isAfter(rejectedOnDate)) {
if (rejectedOnDate != null && DateUtils.isAfter(loanRescheduleRequest.getSubmittedOnDate(), rejectedOnDate)) {
dataValidatorBuilder.reset().parameter(RescheduleLoansApiConstants.rejectedOnDateParam).failWithCode("before.submission.date",
"Rejection date cannot be before the request submission date.");
}
@@ -24,6 +24,7 @@ import java.time.LocalDate;
import java.util.ArrayList;
import java.util.List;
import java.util.Set;
import org.apache.fineract.infrastructure.core.service.DateUtils;
import org.apache.fineract.organisation.monetary.domain.MoneyHelper;
import org.apache.fineract.portfolio.loanaccount.data.LoanTermVariationsData;
import org.apache.fineract.portfolio.loanaccount.data.ScheduleGeneratorDTO;
@@ -113,10 +114,10 @@ public class LoanReschedulePreviewPlatformServiceImpl implements LoanRescheduleP
}
for (LoanTermVariationsData loanTermVariation : loanApplicationTerms.getLoanTermVariations().getDueDateVariation()) {
if (rescheduleFromDate.isBefore(loanTermVariation.getTermVariationApplicableFrom())) {
if (DateUtils.isBefore(rescheduleFromDate, loanTermVariation.getTermVariationApplicableFrom())) {
LocalDate applicableDate = DEFAULT_SCHEDULED_DATE_GENERATOR.generateNextRepaymentDate(rescheduleFromDate,
loanApplicationTerms, false);
if (loanTermVariation.getTermVariationApplicableFrom().equals(applicableDate)) {
if (DateUtils.isEqual(loanTermVariation.getTermVariationApplicableFrom(), applicableDate)) {
LocalDate adjustedDate = DEFAULT_SCHEDULED_DATE_GENERATOR.generateNextRepaymentDate(adjustedApplicableDate,
loanApplicationTerms, false);
loanTermVariation.setApplicableFromDate(adjustedDate);
@@ -272,12 +272,12 @@ public class LoanRescheduleRequestWritePlatformServiceImpl implements LoanResche
final Integer termType = LoanTermVariationType.EMI_AMOUNT.getValue();
List<LoanRepaymentScheduleInstallment> installments = loan.getRepaymentScheduleInstallments();
for (LoanRepaymentScheduleInstallment installment : installments) {
if (installment.getDueDate().isEqual(rescheduleFromLocDate) || installment.getDueDate().isEqual(endDateLocDate)
|| (installment.getDueDate().isAfter(rescheduleFromLocDate) && installment.getDueDate().isBefore(endDateLocDate))) {
if (!DateUtils.isBefore(installment.getDueDate(), rescheduleFromLocDate)
&& !DateUtils.isAfter(installment.getDueDate(), endDateLocDate)) {
createLoanTermVariations(loanRescheduleRequest, termType, loan, installment.getDueDate(), installment.getDueDate(),
loanRescheduleRequestToTermVariationMappings, isActive, true, emi, parent);
}
if (installment.getDueDate().isAfter(endDateLocDate)) {
if (DateUtils.isAfter(installment.getDueDate(), endDateLocDate)) {
break;
}
}
@@ -394,8 +394,8 @@ public class LoanRescheduleRequestWritePlatformServiceImpl implements LoanResche
activeLoanTermVariation.markAsInactive();
rescheduleFromDate = activeLoanTermVariation.fetchTermApplicaDate();
dueDateVariationInCurrentRequest.setTermApplicableFrom(rescheduleFromDate);
} else if (!activeLoanTermVariation.fetchTermApplicaDate().isBefore(fromScheduleDate)) {
while (currentScheduleDate.isBefore(activeLoanTermVariation.fetchTermApplicaDate())) {
} else if (!DateUtils.isBefore(activeLoanTermVariation.fetchTermApplicaDate(), fromScheduleDate)) {
while (DateUtils.isBefore(currentScheduleDate, activeLoanTermVariation.fetchTermApplicaDate())) {
currentScheduleDate = DEFAULT_SCHEDULED_DATE_GENERATOR.generateNextRepaymentDate(currentScheduleDate,
loanApplicationTerms, false);
modifiedScheduleDate = DEFAULT_SCHEDULED_DATE_GENERATOR.generateNextRepaymentDate(modifiedScheduleDate,
@@ -33,6 +33,7 @@ import org.apache.fineract.infrastructure.core.data.ApiParameterError;
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.loanaccount.api.LoanApiConstants;
import org.apache.fineract.portfolio.loanproduct.LoanProductConstants;
import org.springframework.beans.factory.annotation.Autowired;
@@ -166,8 +167,7 @@ public final class CalculateLoanScheduleQueryFromApiJsonHelper {
private void validateRepaymentsStartingFromDateIsAfterDisbursementDate(final List<ApiParameterError> dataValidationErrors,
final LocalDate expectedDisbursementDate, final LocalDate repaymentsStartingFromDate) {
if (expectedDisbursementDate != null && repaymentsStartingFromDate != null
&& expectedDisbursementDate.isAfter(repaymentsStartingFromDate)) {
if (repaymentsStartingFromDate != null && DateUtils.isAfter(expectedDisbursementDate, repaymentsStartingFromDate)) {
final ApiParameterError error = ApiParameterError.parameterError(
"validation.msg.loan.expectedDisbursementDate.cannot.be.after.first.repayment.date",
"The parameter expectedDisbursementDate has a date which falls after the date for repaymentsStartingFromDate.",
@@ -41,6 +41,7 @@ import org.apache.fineract.infrastructure.core.exception.InvalidJsonException;
import org.apache.fineract.infrastructure.core.exception.PlatformApiDataValidationException;
import org.apache.fineract.infrastructure.core.exception.UnsupportedParameterException;
import org.apache.fineract.infrastructure.core.serialization.FromJsonHelper;
import org.apache.fineract.infrastructure.core.service.DateUtils;
import org.apache.fineract.portfolio.accountdetails.domain.AccountType;
import org.apache.fineract.portfolio.calendar.service.CalendarUtils;
import org.apache.fineract.portfolio.collateralmanagement.domain.ClientCollateralManagement;
@@ -1182,7 +1183,7 @@ public final class LoanApplicationCommandFromApiJsonHelper {
if (jsonObject2.has(LoanApiConstants.expectedDisbursementDateParameterName)) {
LocalDate date2 = this.fromApiJsonHelper.extractLocalDateNamed(
LoanApiConstants.expectedDisbursementDateParameterName, jsonObject2, dateFormat, locale);
if (date1.isAfter(date2)) {
if (DateUtils.isAfter(date1, date2)) {
baseDataValidator.reset().parameter(LoanApiConstants.disbursementDataParameterName)
.failWithCode(LoanApiConstants.DISBURSEMENT_DATES_NOT_IN_ORDER);
}
@@ -1196,7 +1197,6 @@ public final class LoanApplicationCommandFromApiJsonHelper {
public void validateLoanMultiDisbursementDate(final JsonElement element, final DataValidatorBuilder baseDataValidator,
LocalDate expectedDisbursement, BigDecimal totalPrincipal) {
this.validateDisbursementsAreDatewiseOrdered(element, baseDataValidator);
final JsonObject topLevelJsonElement = element.getAsJsonObject();
@@ -1228,7 +1228,8 @@ public final class LoanApplicationCommandFromApiJsonHelper {
if (i == 0 && expectedDisbursementDate != null && !expectedDisbursement.equals(expectedDisbursementDate)) {
baseDataValidator.reset().parameter(LoanApiConstants.expectedDisbursementDateParameterName)
.failWithCode(LoanApiConstants.DISBURSEMENT_DATE_START_WITH_ERROR);
} else if (i > 0 && expectedDisbursementDate != null && expectedDisbursementDate.isBefore(expectedDisbursement)) {
} else if (i > 0 && expectedDisbursementDate != null
&& DateUtils.isBefore(expectedDisbursementDate, expectedDisbursement)) {
baseDataValidator.reset().parameter(LoanApiConstants.disbursementDataParameterName)
.failWithCode(LoanApiConstants.DISBURSEMENT_DATE_BEFORE_ERROR);
}
@@ -35,6 +35,7 @@ import org.apache.fineract.accounting.journalentry.service.JournalEntryWritePlat
import org.apache.fineract.infrastructure.configuration.domain.ConfigurationDomainService;
import org.apache.fineract.infrastructure.core.service.DateUtils;
import org.apache.fineract.infrastructure.core.service.ExternalIdFactory;
import org.apache.fineract.infrastructure.core.service.MathUtil;
import org.apache.fineract.infrastructure.core.service.database.DatabaseSpecificSQLGenerator;
import org.apache.fineract.infrastructure.event.business.domain.loan.transaction.LoanAccrualTransactionCreatedBusinessEvent;
import org.apache.fineract.infrastructure.event.business.service.BusinessEventNotifierService;
@@ -114,12 +115,12 @@ public class LoanAccrualWritePlatformServiceImpl implements LoanAccrualWritePlat
loanWaiverTransactionData = this.loanReadPlatformService.retrieveWaiverLoanTransactions(accrualData.getLoanId());
}
if (accrualData.getDueDateAsLocaldate().isAfter(tillDate)) {
if (DateUtils.isAfter(accrualData.getDueDateAsLocaldate(), tillDate)) {
if (accruedTill == null || firstTime) {
accruedTill = accrualData.getAccruedTill();
firstTime = false;
}
if (accruedTill == null || accruedTill.isBefore(tillDate)) {
if (accruedTill == null || DateUtils.isBefore(accruedTill, tillDate)) {
updateCharges(chargeData, accrualData, accrualData.getFromDateAsLocaldate(), tillDate);
updateInterestIncome(accrualData, loanWaiverTransactionData, loanWaiverScheduleData, tillDate);
addAccrualTillSpecificDate(tillDate, accrualData);
@@ -135,9 +136,8 @@ public class LoanAccrualWritePlatformServiceImpl implements LoanAccrualWritePlat
private void addAccrualTillSpecificDate(final LocalDate tillDate, final LoanScheduleAccrualData accrualData) {
LocalDate interestStartDate = accrualData.getFromDateAsLocaldate();
if (accrualData.getInterestCalculatedFrom() != null
&& accrualData.getFromDateAsLocaldate().isBefore(accrualData.getInterestCalculatedFrom())) {
if (accrualData.getInterestCalculatedFrom().isBefore(accrualData.getDueDateAsLocaldate())) {
if (DateUtils.isBefore(accrualData.getFromDateAsLocaldate(), accrualData.getInterestCalculatedFrom())) {
if (DateUtils.isBefore(accrualData.getInterestCalculatedFrom(), accrualData.getDueDateAsLocaldate())) {
interestStartDate = accrualData.getInterestCalculatedFrom();
} else {
interestStartDate = accrualData.getDueDateAsLocaldate();
@@ -146,8 +146,8 @@ public class LoanAccrualWritePlatformServiceImpl implements LoanAccrualWritePlat
int totalNumberOfDays = Math.toIntExact(ChronoUnit.DAYS.between(interestStartDate, accrualData.getDueDateAsLocaldate()));
LocalDate startDate = accrualData.getFromDateAsLocaldate();
if (accrualData.getInterestCalculatedFrom() != null && startDate.isBefore(accrualData.getInterestCalculatedFrom())) {
if (accrualData.getInterestCalculatedFrom().isBefore(tillDate)) {
if (DateUtils.isBefore(startDate, accrualData.getInterestCalculatedFrom())) {
if (DateUtils.isBefore(accrualData.getInterestCalculatedFrom(), tillDate)) {
startDate = accrualData.getInterestCalculatedFrom();
} else {
startDate = tillDate;
@@ -291,7 +291,7 @@ public class LoanAccrualWritePlatformServiceImpl implements LoanAccrualWritePlat
scheduleAccrualData.getRepaymentScheduleId());
String updateLoan = "UPDATE m_loan SET accrued_till=?, last_modified_by=?, last_modified_on_utc=? WHERE id=?";
this.jdbcTemplate.update(updateLoan, accruedTill, user.getId(), DateUtils.getOffsetDateTimeOfTenantWithMostPrecision(),
this.jdbcTemplate.update(updateLoan, accruedTill, user.getId(), DateUtils.getAuditOffsetDateTime(),
scheduleAccrualData.getLoanId());
businessEventNotifierService.notifyPostBusinessEvent(new LoanAccrualTransactionCreatedBusinessEvent(loanTransaction));
@@ -380,9 +380,10 @@ public class LoanAccrualWritePlatformServiceImpl implements LoanAccrualWritePlat
LocalDate scheduleEndDate = accrualData.getDueDateAsLocaldate();
for (LoanChargeData loanCharge : chargesData) {
BigDecimal chargeAmount = BigDecimal.ZERO;
if (((accrualData.getInstallmentNumber() == 1 && loanCharge.getSubmittedOnDate().isEqual(startDate)
&& loanCharge.getDueDate().isEqual(startDate)) || loanCharge.getDueDate().isAfter(startDate))
&& !loanCharge.getSubmittedOnDate().isAfter(endDate) && !loanCharge.getDueDate().isAfter(scheduleEndDate)) {
if (((accrualData.getInstallmentNumber() == 1 && DateUtils.isEqual(startDate, loanCharge.getSubmittedOnDate())
&& DateUtils.isEqual(startDate, loanCharge.getDueDate())) || DateUtils.isBefore(startDate, loanCharge.getDueDate()))
&& !DateUtils.isBefore(endDate, loanCharge.getSubmittedOnDate())
&& !DateUtils.isBefore(scheduleEndDate, loanCharge.getDueDate())) {
chargeAmount = loanCharge.getAmount();
if (loanCharge.getAmountUnrecognized() != null) {
chargeAmount = chargeAmount.subtract(loanCharge.getAmountUnrecognized());
@@ -424,7 +425,7 @@ public class LoanAccrualWritePlatformServiceImpl implements LoanAccrualWritePlat
for (LoanChargeData loanCharge : chargesData) {
BigDecimal chargeAmount = BigDecimal.ZERO;
if (loanCharge.getDueDate() == null) {
if (loanCharge.isInstallmentFee() && accrualData.getDueDateAsLocaldate().isEqual(endDate)) {
if (loanCharge.isInstallmentFee() && DateUtils.isEqual(endDate, accrualData.getDueDateAsLocaldate())) {
Collection<LoanInstallmentChargeData> installmentData = loanCharge.getInstallmentChargeData();
for (LoanInstallmentChargeData installmentChargeData : installmentData) {
@@ -452,8 +453,8 @@ public class LoanAccrualWritePlatformServiceImpl implements LoanAccrualWritePlat
}
}
}
} else if (((accrualData.getInstallmentNumber() == 1 && loanCharge.getDueDate().isEqual(startDate))
|| loanCharge.getDueDate().isAfter(startDate)) && !loanCharge.getDueDate().isAfter(endDate)) {
} else if (((accrualData.getInstallmentNumber() == 1 && DateUtils.isEqual(loanCharge.getDueDate(), startDate))
|| DateUtils.isAfter(loanCharge.getDueDate(), startDate)) && !DateUtils.isAfter(loanCharge.getDueDate(), endDate)) {
chargeAmount = loanCharge.getAmount();
if (loanCharge.getAmountUnrecognized() != null) {
chargeAmount = chargeAmount.subtract(loanCharge.getAmountUnrecognized());
@@ -501,22 +502,23 @@ public class LoanAccrualWritePlatformServiceImpl implements LoanAccrualWritePlat
Collection<LoanTransactionData> loanTransactionDatas = new ArrayList<>();
for (LoanTransactionData loanTransactionData : loanWaiverTransactions) {
if (!loanTransactionData.getDate().isAfter(accrualData.getFromDateAsLocaldate())
|| (loanTransactionData.getDate().isAfter(accrualData.getFromDateAsLocaldate())
&& !loanTransactionData.getDate().isAfter(accrualData.getDueDateAsLocaldate())
&& !loanTransactionData.getDate().isAfter(tillDate))) {
LocalDate transactionDate = loanTransactionData.getDate();
if (!DateUtils.isAfter(transactionDate, accrualData.getFromDateAsLocaldate())
|| (DateUtils.isAfter(transactionDate, accrualData.getFromDateAsLocaldate())
&& !DateUtils.isAfter(transactionDate, accrualData.getDueDateAsLocaldate())
&& !DateUtils.isAfter(transactionDate, tillDate))) {
loanTransactionDatas.add(loanTransactionData);
}
}
Iterator<LoanTransactionData> iterator = loanTransactionDatas.iterator();
for (LoanSchedulePeriodData loanSchedulePeriodData : loanSchedulePeriodDataList) {
if (recognized.compareTo(BigDecimal.ZERO) <= 0 && unrecognized.compareTo(BigDecimal.ZERO) <= 0 && iterator.hasNext()) {
if (MathUtil.isLessThanOrEqualZero(recognized) && MathUtil.isLessThanOrEqualZero(unrecognized) && iterator.hasNext()) {
LoanTransactionData loanTransactionData = iterator.next();
recognized = recognized.add(loanTransactionData.getInterestPortion());
unrecognized = unrecognized.add(loanTransactionData.getUnrecognizedIncomePortion());
}
if (loanSchedulePeriodData.getDueDate().isBefore(accrualData.getDueDateAsLocaldate())) {
if (DateUtils.isBefore(loanSchedulePeriodData.getDueDate(), accrualData.getDueDateAsLocaldate())) {
remainingAmt = remainingAmt.add(loanSchedulePeriodData.getInterestWaived());
if (recognized.compareTo(remainingAmt) > 0) {
recognized = recognized.subtract(remainingAmt);
@@ -53,6 +53,7 @@ import org.apache.fineract.infrastructure.core.exception.GeneralPlatformDomainRu
import org.apache.fineract.infrastructure.core.exception.PlatformApiDataValidationException;
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.ExternalIdFactory;
import org.apache.fineract.infrastructure.dataqueries.data.EntityTables;
import org.apache.fineract.infrastructure.dataqueries.data.StatusEnum;
@@ -287,7 +288,7 @@ public class LoanApplicationWritePlatformServiceJpaRepositoryImpl implements Loa
"Topup on loan with multi-tranche disbursal and without interest recalculation is not supported.");
}
final LocalDate disbursalDateOfLoanToClose = loanToClose.getDisbursementDate();
if (!newLoanApplication.getSubmittedOnDate().isAfter(disbursalDateOfLoanToClose)) {
if (!DateUtils.isAfter(newLoanApplication.getSubmittedOnDate(), disbursalDateOfLoanToClose)) {
throw new GeneralPlatformDomainRuleException(
"error.msg.loan.submitted.date.should.be.after.topup.loan.disbursal.date",
"Submitted date of this loan application " + newLoanApplication.getSubmittedOnDate()
@@ -298,7 +299,7 @@ public class LoanApplicationWritePlatformServiceJpaRepositoryImpl implements Loa
"loanIdToClose is invalid, Currency code is different.");
}
final LocalDate lastUserTransactionOnLoanToClose = loanToClose.getLastUserTransactionDate();
if (newLoanApplication.getDisbursementDate().isBefore(lastUserTransactionOnLoanToClose)) {
if (DateUtils.isBefore(newLoanApplication.getDisbursementDate(), lastUserTransactionOnLoanToClose)) {
throw new GeneralPlatformDomainRuleException(
"error.msg.loan.disbursal.date.should.be.after.last.transaction.date.of.loan.to.be.closed",
"Disbursal date of this loan application " + newLoanApplication.getDisbursementDate()
@@ -867,7 +868,7 @@ public class LoanApplicationWritePlatformServiceJpaRepositoryImpl implements Loa
"Topup on loan with multi-tranche disbursal and without interest recalculation is not supported.");
}
final LocalDate disbursalDateOfLoanToClose = loanToClose.getDisbursementDate();
if (!existingLoanApplication.getSubmittedOnDate().isAfter(disbursalDateOfLoanToClose)) {
if (!DateUtils.isAfter(existingLoanApplication.getSubmittedOnDate(), disbursalDateOfLoanToClose)) {
throw new GeneralPlatformDomainRuleException(
"error.msg.loan.submitted.date.should.be.after.topup.loan.disbursal.date",
"Submitted date of this loan application " + existingLoanApplication.getSubmittedOnDate()
@@ -878,7 +879,7 @@ public class LoanApplicationWritePlatformServiceJpaRepositoryImpl implements Loa
"loanIdToClose is invalid, Currency code is different.");
}
final LocalDate lastUserTransactionOnLoanToClose = loanToClose.getLastUserTransactionDate();
if (existingLoanApplication.getDisbursementDate().isBefore(lastUserTransactionOnLoanToClose)) {
if (DateUtils.isBefore(existingLoanApplication.getDisbursementDate(), lastUserTransactionOnLoanToClose)) {
throw new GeneralPlatformDomainRuleException(
"error.msg.loan.disbursal.date.should.be.after.last.transaction.date.of.loan.to.be.closed",
"Disbursal date of this loan application " + existingLoanApplication.getDisbursementDate()
@@ -1380,7 +1381,7 @@ public class LoanApplicationWritePlatformServiceJpaRepositoryImpl implements Loa
}
final LocalDate lastUserTransactionOnLoanToClose = loanToClose.getLastUserTransactionDate();
if (loan.getDisbursementDate().isBefore(lastUserTransactionOnLoanToClose)) {
if (DateUtils.isBefore(loan.getDisbursementDate(), lastUserTransactionOnLoanToClose)) {
throw new GeneralPlatformDomainRuleException(
"error.msg.loan.disbursal.date.should.be.after.last.transaction.date.of.loan.to.be.closed",
"Disbursal date of this loan application " + loan.getDisbursementDate()
@@ -1634,19 +1635,19 @@ public class LoanApplicationWritePlatformServiceJpaRepositoryImpl implements Loa
final LocalDate submittedOnDate = loan.getSubmittedOnDate();
String defaultUserMessage = "";
if (startDate != null && submittedOnDate.isBefore(startDate)) {
if (DateUtils.isBefore(submittedOnDate, startDate)) {
defaultUserMessage = "submittedOnDate cannot be before the loan product startDate.";
throw new LoanApplicationDateException("submitted.on.date.cannot.be.before.the.loan.product.start.date", defaultUserMessage,
submittedOnDate.toString(), startDate.toString());
}
if (closeDate != null && submittedOnDate.isAfter(closeDate)) {
if (closeDate != null && DateUtils.isAfter(submittedOnDate, closeDate)) {
defaultUserMessage = "submittedOnDate cannot be after the loan product closeDate.";
throw new LoanApplicationDateException("submitted.on.date.cannot.be.after.the.loan.product.close.date", defaultUserMessage,
submittedOnDate.toString(), closeDate.toString());
}
if (expectedFirstRepaymentOnDate != null && submittedOnDate.isAfter(expectedFirstRepaymentOnDate)) {
if (expectedFirstRepaymentOnDate != null && DateUtils.isAfter(submittedOnDate, expectedFirstRepaymentOnDate)) {
defaultUserMessage = "submittedOnDate cannot be after the loans expectedFirstRepaymentOnDate.";
throw new LoanApplicationDateException("submitted.on.date.cannot.be.after.the.loan.expected.first.repayment.date",
defaultUserMessage, submittedOnDate.toString(), expectedFirstRepaymentOnDate.toString());
@@ -32,6 +32,7 @@ import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.apache.fineract.infrastructure.core.domain.JdbcSupport;
import org.apache.fineract.infrastructure.core.service.DateUtils;
import org.apache.fineract.infrastructure.core.service.MathUtil;
import org.apache.fineract.infrastructure.core.service.database.DatabaseSpecificSQLGenerator;
import org.apache.fineract.infrastructure.event.business.BusinessEventListener;
import org.apache.fineract.infrastructure.event.business.domain.loan.LoanAdjustTransactionBusinessEvent;
@@ -145,12 +146,12 @@ public class LoanArrearsAgingServiceImpl implements LoanArrearsAgingService {
LocalDate businessDate = DateUtils.getBusinessLocalDate();
LocalDate overDueSince = businessDate;
for (LoanRepaymentScheduleInstallment installment : installments) {
if (installment.getDueDate().isBefore(businessDate)) {
if (DateUtils.isBefore(installment.getDueDate(), businessDate)) {
principalOverdue = principalOverdue.add(installment.getPrincipalOutstanding(loan.getCurrency()).getAmount());
interestOverdue = interestOverdue.add(installment.getInterestOutstanding(loan.getCurrency()).getAmount());
feeOverdue = feeOverdue.add(installment.getFeeChargesOutstanding(loan.getCurrency()).getAmount());
penaltyOverdue = penaltyOverdue.add(installment.getPenaltyChargesOutstanding(loan.getCurrency()).getAmount());
if (installment.isNotFullyPaidOff() && overDueSince.isAfter(installment.getDueDate())) {
if (installment.isNotFullyPaidOff() && DateUtils.isAfter(overDueSince, installment.getDueDate())) {
overDueSince = installment.getDueDate();
}
}
@@ -208,8 +209,8 @@ public class LoanArrearsAgingServiceImpl implements LoanArrearsAgingService {
.add(loanSchedulePeriodData.getFeeChargesDue().subtract(loanSchedulePeriodData.getFeeChargesPaid()));
penaltyOverdue = penaltyOverdue
.add(loanSchedulePeriodData.getPenaltyChargesDue().subtract(loanSchedulePeriodData.getPenaltyChargesPaid()));
if (overDueSince.isAfter(loanSchedulePeriodData.getDueDate()) && loanSchedulePeriodData.getPrincipalDue()
.subtract(loanSchedulePeriodData.getPrincipalPaid()).compareTo(BigDecimal.ZERO) > 0) {
if (DateUtils.isAfter(overDueSince, loanSchedulePeriodData.getDueDate()) && MathUtil
.isGreaterThan(loanSchedulePeriodData.getPrincipalDue(), loanSchedulePeriodData.getPrincipalPaid())) {
overDueSince = loanSchedulePeriodData.getDueDate();
}
}
@@ -65,8 +65,7 @@ public class LoanCalculateRepaymentPastDueService {
List<LoanRepaymentScheduleInstallment> loanRepayments = loan.getRepaymentScheduleInstallments();
LocalDate currentBusinessDate = DateUtils.getBusinessLocalDate();
return loanRepayments.stream()
.filter((repayment) -> (!repayment.isObligationsMet()
&& (repayment.getDueDate().isBefore(currentBusinessDate) || repayment.getDueDate().isEqual(currentBusinessDate))))
.filter(repayment -> (!repayment.isObligationsMet() && !DateUtils.isAfter(repayment.getDueDate(), currentBusinessDate)))
.collect(Collectors.toList());
}
}
@@ -33,6 +33,7 @@ import lombok.RequiredArgsConstructor;
import org.apache.fineract.infrastructure.core.api.JsonCommand;
import org.apache.fineract.infrastructure.core.domain.ExternalId;
import org.apache.fineract.infrastructure.core.serialization.FromJsonHelper;
import org.apache.fineract.infrastructure.core.service.DateUtils;
import org.apache.fineract.infrastructure.core.service.ExternalIdFactory;
import org.apache.fineract.portfolio.charge.domain.Charge;
import org.apache.fineract.portfolio.charge.domain.ChargeCalculationType;
@@ -301,7 +302,7 @@ public class LoanChargeAssembler {
if (chargeDefinition.getChargeTimeType().equals(ChargeTimeType.SPECIFIED_DUE_DATE.getValue()) && loan.isMultiDisburmentLoan()) {
amountPercentageAppliedTo = BigDecimal.ZERO;
for (final LoanDisbursementDetails loanDisbursementDetails : loan.getDisbursementDetails()) {
if (!loanDisbursementDetails.expectedDisbursementDate().isAfter(dueDate)) {
if (!DateUtils.isAfter(loanDisbursementDetails.expectedDisbursementDate(), dueDate)) {
amountPercentageAppliedTo = amountPercentageAppliedTo.add(loanDisbursementDetails.principal());
}
}
@@ -164,13 +164,12 @@ public class LoanChargeWritePlatformServiceImpl implements LoanChargeWritePlatfo
private final LoanAccrualTransactionBusinessEventService loanAccrualTransactionBusinessEventService;
private static boolean isPartOfThisInstallment(LoanCharge loanCharge, LoanRepaymentScheduleInstallment e) {
return e.getFromDate().isBefore(loanCharge.getDueDate()) && !loanCharge.getDueDate().isAfter(e.getDueDate());
return DateUtils.isAfter(loanCharge.getDueDate(), e.getFromDate()) && !DateUtils.isAfter(loanCharge.getDueDate(), e.getDueDate());
}
@Transactional
@Override
public CommandProcessingResult addLoanCharge(final Long loanId, final JsonCommand command) {
this.loanChargeApiJsonValidator.validateAddLoanCharge(command.json());
Loan loan = this.loanAssembler.assembleFrom(loanId);
@@ -213,7 +212,7 @@ public class LoanChargeWritePlatformServiceImpl implements LoanChargeWritePlatfo
validateAddLoanCharge(loan, chargeDefinition, loanCharge);
addCharge(loan, chargeDefinition, loanCharge);
isAppliedOnBackDate = true;
if (recalculateFrom.isAfter(disbursementDetail.expectedDisbursementDateAsLocalDate())) {
if (DateUtils.isAfter(recalculateFrom, disbursementDetail.expectedDisbursementDateAsLocalDate())) {
recalculateFrom = disbursementDetail.expectedDisbursementDateAsLocalDate();
}
needToGenerateNewExternalId = true;
@@ -231,7 +230,7 @@ public class LoanChargeWritePlatformServiceImpl implements LoanChargeWritePlatfo
validateAddLoanCharge(loan, chargeDefinition, loanCharge);
isAppliedOnBackDate = addCharge(loan, chargeDefinition, loanCharge);
if (loanCharge.getDueLocalDate() == null || recalculateFrom.isAfter(loanCharge.getDueLocalDate())) {
if (loanCharge.getDueLocalDate() == null || DateUtils.isAfter(recalculateFrom, loanCharge.getDueLocalDate())) {
isAppliedOnBackDate = true;
recalculateFrom = loanCharge.getDueLocalDate();
}
@@ -366,8 +365,7 @@ public class LoanChargeWritePlatformServiceImpl implements LoanChargeWritePlatfo
throw new LoanChargeWaiveCannotBeReversedException(
LoanChargeWaiveCannotBeReversedException.LoanChargeWaiveCannotUndoReason.LOAN_INACTIVE, loanCharge.getId());
}
if (loan.isChargedOff() && (loanTransaction.getTransactionDate().isBefore(loan.getChargedOffOnDate())
|| loanTransaction.getTransactionDate().isEqual(loan.getChargedOffOnDate()))) {
if (loan.isChargedOff() && !DateUtils.isAfter(loanTransaction.getTransactionDate(), loan.getChargedOffOnDate())) {
throw new GeneralPlatformDomainRuleException("error.msg.transaction.date.cannot.be.earlier.than.charge.off.date",
"Undo Loan transaction: " + loanTransaction.getId()
+ " is not allowed before or on the date when the loan got charged-off",
@@ -743,17 +741,17 @@ public class LoanChargeWritePlatformServiceImpl implements LoanChargeWritePlatfo
overdueInstallment.getPeriodNumber(), command);
loan = overdueDTO.getLoan();
runInterestRecalculation = runInterestRecalculation || overdueDTO.isRunInterestRecalculation();
if (recalculateFrom.isAfter(overdueDTO.getRecalculateFrom())) {
if (DateUtils.isAfter(recalculateFrom, overdueDTO.getRecalculateFrom())) {
recalculateFrom = overdueDTO.getRecalculateFrom();
}
if (lastChargeDate == null || overdueDTO.getLastChargeAppliedDate().isAfter(lastChargeDate)) {
if (lastChargeDate == null || DateUtils.isAfter(overdueDTO.getLastChargeAppliedDate(), lastChargeDate)) {
lastChargeDate = overdueDTO.getLastChargeAppliedDate();
}
}
if (loan != null) {
boolean reprocessRequired = true;
LocalDate recalculatedTill = loan.fetchInterestRecalculateFromDate();
if (recalculateFrom.isAfter(recalculatedTill)) {
if (DateUtils.isAfter(recalculateFrom, recalculatedTill)) {
recalculateFrom = recalculatedTill;
}
@@ -946,12 +944,11 @@ public class LoanChargeWritePlatformServiceImpl implements LoanChargeWritePlatfo
throw new LoanChargeCannotBeAddedException("loanCharge", "overdue.charge", defaultUserMessage, null,
chargeDefinition.getName());
} else if (loanCharge.getDueLocalDate() != null
&& loanCharge.getDueLocalDate().isBefore(loan.getLastUserTransactionForChargeCalc())) {
&& DateUtils.isBefore(loanCharge.getDueLocalDate(), loan.getLastUserTransactionForChargeCalc())) {
final String defaultUserMessage = "charge with date before last transaction date can not be added to loan.";
throw new LoanChargeCannotBeAddedException("loanCharge", "date.is.before.last.transaction.date", defaultUserMessage, null,
chargeDefinition.getName());
} else if (loan.repaymentScheduleDetail().isInterestRecalculationEnabled()) {
if (loanCharge.isInstalmentFee() && loan.getStatus().isActive()) {
final String defaultUserMessage = "installment charge addition not allowed after disbursement";
throw new LoanChargeCannotBeAddedException("loanCharge", "installment.charge", defaultUserMessage, null,
@@ -986,7 +983,7 @@ public class LoanChargeWritePlatformServiceImpl implements LoanChargeWritePlatfo
if (!loan.isInterestBearing() && loanCharge.isSpecifiedDueDate()) {
LoanRepaymentScheduleInstallment latestRepaymentScheduleInstalment = loan.getRepaymentScheduleInstallments()
.get(loan.getLoanRepaymentScheduleInstallmentsSize() - 1);
if (loanCharge.getDueDate().isAfter(latestRepaymentScheduleInstalment.getDueDate())) {
if (DateUtils.isAfter(loanCharge.getDueDate(), latestRepaymentScheduleInstalment.getDueDate())) {
if (latestRepaymentScheduleInstalment.isAdditional()) {
latestRepaymentScheduleInstalment.updateDueDate(loanCharge.getDueDate());
} else {
@@ -1003,15 +1000,13 @@ public class LoanChargeWritePlatformServiceImpl implements LoanChargeWritePlatfo
loanCharge = this.loanChargeRepository.saveAndFlush(loanCharge);
/**
* we want to apply charge transactions only for those loans charges that are applied when a loan is active and
* the loan product uses Upfront Accruals
**/
// we want to apply charge transactions only for those loans charges that are applied when a loan is active and
// the loan product uses Upfront Accruals
if (loan.getStatus().isActive() && loan.isNoneOrCashOrUpfrontAccrualAccountingEnabledOnLoanProduct()) {
final LoanTransaction applyLoanChargeTransaction = loan.handleChargeAppliedTransaction(loanCharge, null);
this.loanTransactionRepository.saveAndFlush(applyLoanChargeTransaction);
}
return loanCharge.getDueLocalDate() == null || DateUtils.getBusinessLocalDate().isAfter(loanCharge.getDueLocalDate());
return DateUtils.isBeforeBusinessDate(loanCharge.getDueLocalDate());
}
private LoanOverdueDTO applyChargeToOverdueLoanInstallment(final Loan loan, final Long loanChargeId, final Integer periodNumber,
@@ -1037,7 +1032,7 @@ public class LoanChargeWritePlatformServiceImpl implements LoanChargeWritePlatfo
if (feeFrequency == null) {
scheduleDates.put(frequencyNumber++, startDate.minusDays(diff));
} else {
while (!startDate.isAfter(DateUtils.getBusinessLocalDate())) {
while (!DateUtils.isDateInTheFuture(startDate)) {
scheduleDates.put(frequencyNumber++, startDate.minusDays(diff));
startDate = scheduledDateGenerator.getRepaymentPeriodDate(PeriodFrequencyType.fromInt(feeFrequency),
@@ -1070,10 +1065,10 @@ public class LoanChargeWritePlatformServiceImpl implements LoanChargeWritePlatfo
boolean isAppliedOnBackDate = addCharge(loan, chargeDefinition, loanCharge);
runInterestRecalculation = runInterestRecalculation || isAppliedOnBackDate;
if (entry.getValue().isBefore(recalculateFrom)) {
if (DateUtils.isBefore(entry.getValue(), recalculateFrom)) {
recalculateFrom = entry.getValue();
}
if (entry.getValue().isAfter(lastChargeAppliedDate)) {
if (DateUtils.isAfter(entry.getValue(), lastChargeAppliedDate)) {
lastChargeAppliedDate = entry.getValue();
}
}
@@ -1088,7 +1083,7 @@ public class LoanChargeWritePlatformServiceImpl implements LoanChargeWritePlatfo
if (lastChargeDate != null) {
List<LoanRepaymentScheduleInstallment> installments = loan.getRepaymentScheduleInstallments();
LoanRepaymentScheduleInstallment lastInstallment = loan.fetchRepaymentScheduleInstallment(installments.size());
if (lastChargeDate.isAfter(lastInstallment.getDueDate())) {
if (DateUtils.isAfter(lastChargeDate, lastInstallment.getDueDate())) {
if (lastInstallment.isRecalculatedInterestComponent()) {
installments.remove(lastInstallment);
lastInstallment = loan.fetchRepaymentScheduleInstallment(installments.size());
@@ -1223,8 +1223,7 @@ public class LoanReadPlatformServiceImpl implements LoanReadPlatformService, Loa
this.outstandingLoanPrincipalBalance = this.outstandingLoanPrincipalBalance.add(data.getPrincipal());
disbursementPeriodIds.add(data.getId());
} else if (data.isDueForDisbursement(fromDate, dueDate) && !disbursementPeriodIds.contains(data.getId())) {
if (!excludePastUndisbursed || data.isDisbursed()
|| !data.disbursementDate().isBefore(DateUtils.getBusinessLocalDate())) {
if (!excludePastUndisbursed || data.isDisbursed() || !DateUtils.isBeforeBusinessDate(data.disbursementDate())) {
principal = principal.add(data.getPrincipal());
LoanSchedulePeriodData periodData;
if (data.getChargeAmount() == null) {
@@ -2385,12 +2384,14 @@ public class LoanReadPlatformServiceImpl implements LoanReadPlatformService, Loa
final Collection<InterestRatePeriodData> intRates = this.floatingRatesReadPlatformService
.retrieveInterestRatePeriods(loanData.getLoanProductId());
for (final InterestRatePeriodData rate : intRates) {
if (loanData.getTimeline() != null && rate.getFromDate().compareTo(loanData.getTimeline().getDisbursementDate()) > 0
&& loanData.isFloatingInterestRate()) {
if (loanData.getTimeline() == null) {
continue;
}
boolean isAfterDisbursement = DateUtils.isAfter(rate.getFromDate(), loanData.getTimeline().getDisbursementDate());
if (isAfterDisbursement && loanData.isFloatingInterestRate()) {
updateInterestRatePeriodData(rate, loanData);
intRatePeriodData.add(rate);
} else if (loanData.getTimeline() != null
&& rate.getFromDate().compareTo(loanData.getTimeline().getDisbursementDate()) <= 0) {
} else if (!isAfterDisbursement) {
updateInterestRatePeriodData(rate, loanData);
intRatePeriodData.add(rate);
break;
@@ -2416,7 +2417,7 @@ public class LoanReadPlatformServiceImpl implements LoanReadPlatformService, Loa
}
rate.setEffectiveInterestRate(effectiveInterestRate);
if (loan.getTimeline() != null && rate.getFromDate().compareTo(loan.getTimeline().getDisbursementDate()) < 0) {
if (loan.getTimeline() != null && DateUtils.isBefore(rate.getFromDate(), loan.getTimeline().getDisbursementDate())) {
rate.setFromDate(loan.getTimeline().getDisbursementDate());
}
}
@@ -281,7 +281,7 @@ public class LoanUtilService {
isSkipRepaymentOnFirstMonth = isLoanRepaymentsSyncWithMeeting(loan.group(), historyList.get(0).getCalendar());
}
calculatedRepaymentsStartingFromDate = CalendarUtils.getNextRepaymentMeetingDate(historyList.get(0).getRecurrence(),
historyList.get(0).getStartDateLocalDate(), actualDisbursementDate, repayEvery, frequency, workingDays,
historyList.get(0).getStartDate(), actualDisbursementDate, repayEvery, frequency, workingDays,
isSkipRepaymentOnFirstMonth, numberOfDays);
}
}
@@ -291,7 +291,7 @@ public class LoanWritePlatformServiceJpaRepositoryImpl implements LoanWritePlatf
final LocalDate actualDisbursementDate = command.localDateValueOfParameterNamed("actualDisbursementDate");
if (loan.isChargedOff() && actualDisbursementDate.isBefore(loan.getChargedOffOnDate())) {
if (loan.isChargedOff() && DateUtils.isBefore(actualDisbursementDate, loan.getChargedOffOnDate())) {
throw new GeneralPlatformDomainRuleException("error.msg.transaction.date.cannot.be.earlier.than.charge.off.date", "Loan: "
+ loanId
+ " backdated transaction is not allowed. Transaction date cannot be earlier than the charge-off date of the loan",
@@ -405,7 +405,7 @@ public class LoanWritePlatformServiceJpaRepositoryImpl implements LoanWritePlatf
"Loan to be closed with this topup is not active.");
}
final LocalDate lastUserTransactionOnLoanToClose = loanToClose.getLastUserTransactionDate();
if (loan.getDisbursementDate().isBefore(lastUserTransactionOnLoanToClose)) {
if (DateUtils.isBefore(loan.getDisbursementDate(), lastUserTransactionOnLoanToClose)) {
throw new GeneralPlatformDomainRuleException(
"error.msg.loan.disbursal.date.should.be.after.last.transaction.date.of.loan.to.be.closed",
"Disbursal date of this loan application " + loan.getDisbursementDate()
@@ -1131,7 +1131,7 @@ public class LoanWritePlatformServiceJpaRepositoryImpl implements LoanWritePlatf
LocalDate recalculateFrom = null;
if (loan.repaymentScheduleDetail().isInterestRecalculationEnabled()) {
recalculateFrom = transactionToAdjust.getTransactionDate().isAfter(transactionDate) ? transactionDate
recalculateFrom = DateUtils.isAfter(transactionToAdjust.getTransactionDate(), transactionDate) ? transactionDate
: transactionToAdjust.getTransactionDate();
}
@@ -1149,11 +1149,11 @@ public class LoanWritePlatformServiceJpaRepositoryImpl implements LoanWritePlatf
this.loanTransactionRepository.saveAndFlush(newTransactionDetail);
}
/***
/*
* TODO Vishwas Batch save is giving me a HibernateOptimisticLockingFailureException, looping and saving for the
* time being, not a major issue for now as this loop is entered only in edge cases (when a adjustment is made
* before the latest payment recorded against the loan)
***/
*/
if (changedTransactionDetail != null) {
for (final Map.Entry<Long, LoanTransaction> mapEntry : changedTransactionDetail.getNewTransactionMappings().entrySet()) {
loanAccountDomainService.saveLoanTransactionWithDataIntegrityViolationChecks(mapEntry.getValue());
@@ -1446,7 +1446,7 @@ public class LoanWritePlatformServiceJpaRepositoryImpl implements LoanWritePlatf
}
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: "
+ loanId
+ " backdated transaction is not allowed. Transaction date cannot be earlier than the charge-off date of the loan",
@@ -1512,7 +1512,7 @@ public class LoanWritePlatformServiceJpaRepositoryImpl implements LoanWritePlatf
final Loan loan = this.loanAssembler.assembleFrom(loanId);
checkClientOrGroupActive(loan);
LocalDate transactionDate = command.localDateValueOfParameterNamed("transactionDate");
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: "
+ loanId
+ " backdated transaction is not allowed. Transaction date cannot be earlier than the charge-off date of the loan",
@@ -2598,8 +2598,7 @@ public class LoanWritePlatformServiceJpaRepositoryImpl implements LoanWritePlatf
private void checkIfLoanIsPaidInAdvance(final Long loanId, final BigDecimal transactionAmount) {
BigDecimal overpaid = this.loanReadPlatformService.retrieveTotalPaidInAdvance(loanId).getPaidInAdvance();
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;
}
@@ -2685,7 +2684,7 @@ public class LoanWritePlatformServiceJpaRepositoryImpl implements LoanWritePlatf
String noteText = this.fromApiJsonHelper.extractStringNamed(LoanApiConstants.noteParamName, element);
LoanRescheduleRequest loanRescheduleRequest = null;
for (LoanDisbursementDetails loanDisbursementDetails : loan.getDisbursementDetails()) {
if (!loanDisbursementDetails.expectedDisbursementDateAsLocalDate().isAfter(transactionDate)
if (!DateUtils.isAfter(loanDisbursementDetails.expectedDisbursementDateAsLocalDate(), transactionDate)
&& loanDisbursementDetails.actualDisbursementDate() == null) {
final String defaultUserMessage = "The loan with undisbursed tranche before foreclosure cannot be foreclosed.";
throw new LoanForeclosureException("loan.with.undisbursed.tranche.before.foreclosure.cannot.be.foreclosured",
@@ -2732,12 +2731,12 @@ public class LoanWritePlatformServiceJpaRepositoryImpl implements LoanWritePlatf
throw new GeneralPlatformDomainRuleException("error.msg.loan.is.already.charged.off",
"Loan: " + loanId + " is already charged-off", loanId);
}
if (transactionDate.isBefore(loan.getLastUserTransactionDate())) {
if (DateUtils.isBefore(transactionDate, loan.getLastUserTransactionDate())) {
throw new GeneralPlatformDomainRuleException("error.msg.loan.charge.off.is.before.than.the.last.user.transaction",
"Loan: " + loanId + " charge-off cannot be executed. User transaction was found after the charge-off transaction date!",
loanId);
}
if (transactionDate.isAfter(DateUtils.getBusinessLocalDate())) {
if (DateUtils.isDateInTheFuture(transactionDate)) {
final String errorMessage = "The transaction date cannot be in the future.";
throw new GeneralPlatformDomainRuleException("error.msg.loan.transaction.cannot.be.a.future.date", errorMessage,
transactionDate);
@@ -2848,27 +2847,23 @@ public class LoanWritePlatformServiceJpaRepositoryImpl implements LoanWritePlatf
final String errorMessage = "tranches.should.be.disbursed.more.than.one.to.undo.last.disbursal";
throw new LoanMultiDisbursementException(errorMessage);
}
}
private void syncExpectedDateWithActualDisbursementDate(final Loan loan, LocalDate actualDisbursementDate) {
if (!loan.getExpectedDisbursedOnLocalDate().equals(actualDisbursementDate)) {
throw new DateMismatchException(actualDisbursementDate, loan.getExpectedDisbursedOnLocalDate());
}
}
private void validateTransactionsForTransfer(final Loan loan, final LocalDate transferDate) {
for (LoanTransaction transaction : loan.getLoanTransactions()) {
if ((transaction.getTransactionDate().isEqual(transferDate) && transaction.getSubmittedOnDate().isEqual(transferDate))
|| transaction.getTransactionDate().isAfter(transferDate)) {
if ((DateUtils.isEqual(transferDate, transaction.getTransactionDate())
&& DateUtils.isEqual(transferDate, transaction.getSubmittedOnDate()))
|| DateUtils.isBefore(transferDate, transaction.getTransactionDate())) {
throw new GeneralPlatformDomainRuleException(TransferApiConstants.transferClientLoanException,
TransferApiConstants.transferClientLoanExceptionMessage, transaction.getCreatedDateTime().toLocalDate(),
transferDate);
}
}
}
}
@@ -369,7 +369,7 @@ public class LoanProductReadPlatformServiceImpl implements LoanProductReadPlatfo
final boolean enableInstallmentLevelDelinquency = rs.getBoolean("enableInstallmentLevelDelinquency");
String status = "";
if (closeDate != null && closeDate.isBefore(DateUtils.getBusinessLocalDate())) {
if (closeDate != null && DateUtils.isBeforeBusinessDate(closeDate)) {
status = "loanProduct.inActive";
} else {
status = "loanProduct.active";
@@ -33,6 +33,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.domain.FineractEntityAccessType;
import org.apache.fineract.infrastructure.entityaccess.service.FineractEntityAccessUtil;
import org.apache.fineract.infrastructure.event.business.domain.loan.product.LoanProductCreateBusinessEvent;
@@ -369,10 +370,8 @@ public class LoanProductWritePlatformServiceJpaRepositoryImpl implements LoanPro
final LocalDate startDate = command.localDateValueOfParameterNamed("startDate");
final LocalDate closeDate = command.localDateValueOfParameterNamed("closeDate");
if (startDate != null && closeDate != null) {
if (closeDate.isBefore(startDate)) {
throw new LoanProductDateException(startDate.toString(), closeDate.toString());
}
if (closeDate != null && DateUtils.isBefore(closeDate, startDate)) {
throw new LoanProductDateException(startDate.toString(), closeDate.toString());
}
}
@@ -167,7 +167,7 @@ public class Meeting extends AbstractPersistableCustom {
}
public boolean isMeetingDateBefore(final LocalDate newStartDate) {
return this.meetingDate != null && newStartDate != null && getMeetingDateLocalDate().isBefore(newStartDate) ? true : false;
return this.meetingDate != null && DateUtils.isBefore(getMeetingDateLocalDate(), newStartDate);
}
private static boolean isValidMeetingDate(final CalendarInstance calendarInstance, final LocalDate meetingDate,
@@ -181,7 +181,7 @@ public class Meeting extends AbstractPersistableCustom {
}
private boolean isMeetingDateAfter(final LocalDate date) {
return getMeetingDateLocalDate().isAfter(date);
return DateUtils.isAfter(getMeetingDateLocalDate(), date);
}
public Collection<ClientAttendance> getClientsAttendance() {
@@ -36,18 +36,18 @@ public class SearchConditions {
this.searchQuery = searchQueryParam;
this.searchResource = searchResource;
this.exactMatch = exactMatch;
this.clientSearch = (null == searchResource
|| searchResource.toLowerCase().contains(SearchSupportedResources.CLIENTS.name().toLowerCase())) ? true : false;
this.groupSearch = (null == searchResource
|| searchResource.toLowerCase().contains(SearchSupportedResources.GROUPS.name().toLowerCase())) ? true : false;
this.loanSeach = (null == searchResource
|| searchResource.toLowerCase().contains(SearchSupportedResources.LOANS.name().toLowerCase())) ? true : false;
this.savingSeach = (null == searchResource
|| searchResource.toLowerCase().contains(SearchSupportedResources.SAVINGS.name().toLowerCase())) ? true : false;
this.shareSeach = (null == searchResource
|| searchResource.toLowerCase().contains(SearchSupportedResources.SHARES.name().toLowerCase())) ? true : false;
this.clientIdentifierSearch = (null == searchResource
|| searchResource.toLowerCase().contains(SearchSupportedResources.CLIENTIDENTIFIERS.name().toLowerCase())) ? true : false;
this.clientSearch = null == searchResource
|| searchResource.toLowerCase().contains(SearchSupportedResources.CLIENTS.name().toLowerCase());
this.groupSearch = null == searchResource
|| searchResource.toLowerCase().contains(SearchSupportedResources.GROUPS.name().toLowerCase());
this.loanSeach = null == searchResource
|| searchResource.toLowerCase().contains(SearchSupportedResources.LOANS.name().toLowerCase());
this.savingSeach = null == searchResource
|| searchResource.toLowerCase().contains(SearchSupportedResources.SAVINGS.name().toLowerCase());
this.shareSeach = null == searchResource
|| searchResource.toLowerCase().contains(SearchSupportedResources.SHARES.name().toLowerCase());
this.clientIdentifierSearch = null == searchResource
|| searchResource.toLowerCase().contains(SearchSupportedResources.CLIENTIDENTIFIERS.name().toLowerCase());
}
public SearchConditions(final String searchQueryParam, final String searchResource, final Boolean clientSearch,
@@ -54,10 +54,8 @@ public class AccountEntityServiceForSavingsImpl implements AccountEntityService
@Override
public void validateSelfUserAccountMapping(Long accountId) {
if (!this.appuserSavingsMapperReadService.isSavingsMappedToUser(accountId, this.context.getAuthenticatedUserIfPresent().getId())) {
if (!this.appuserSavingsMapperReadService.isSavingsMappedToUser(accountId, this.context.authenticatedUser().getId())) {
throw new SavingsAccountNotFoundException(accountId);
}
}
@@ -53,9 +53,8 @@ public class AccountEntityServiceForShareAccountsImpl implements AccountEntitySe
@Override
public void validateSelfUserAccountMapping(Long accountId) {
if (!this.appUserShareAccountsMapperReadPlatformService.isShareAccountsMappedToUser(accountId,
this.context.getAuthenticatedUserIfPresent().getId())) {
this.context.authenticatedUser().getId())) {
throw new ShareAccountNotFoundException(accountId);
}
}
@@ -36,6 +36,7 @@ import java.util.HashSet;
import java.util.Set;
import org.apache.commons.lang3.StringUtils;
import org.apache.fineract.infrastructure.core.domain.AbstractPersistableCustom;
import org.apache.fineract.infrastructure.core.service.DateUtils;
import org.apache.fineract.infrastructure.security.service.RandomPasswordGenerator;
import org.apache.fineract.organisation.monetary.domain.MonetaryCurrency;
import org.apache.fineract.portfolio.client.domain.Client;
@@ -209,7 +210,7 @@ public class ShareAccount extends AbstractPersistableCustom {
public boolean setSubmittedDate(final LocalDate submittedDate) {
boolean toReturn = false;
if (this.submittedDate.compareTo(submittedDate) == 0 ? Boolean.FALSE : Boolean.TRUE) {
if (!DateUtils.isEqual(submittedDate, this.submittedDate)) {
this.submittedDate = submittedDate;
toReturn = true;
}
@@ -218,7 +219,7 @@ public class ShareAccount extends AbstractPersistableCustom {
public boolean setApprovedDate(final LocalDate approvedDate) {
boolean toReturn = false;
if (this.approvedDate.compareTo(approvedDate) == 0 ? Boolean.FALSE : Boolean.TRUE) {
if (!DateUtils.isEqual(approvedDate, this.approvedDate)) {
this.approvedDate = approvedDate;
toReturn = true;
}
@@ -514,11 +515,11 @@ public class ShareAccount extends AbstractPersistableCustom {
public ShareAccountTransaction getShareAccountTransaction(final ShareAccountTransaction transaction) {
ShareAccountTransaction returnTrans = null;
for (ShareAccountTransaction tran : this.shareAccountTransactions) {
if (tran.getPurchasedDate().compareTo(transaction.getPurchasedDate()) == 0 ? Boolean.TRUE
: Boolean.FALSE && tran.getTotalShares().equals(transaction.getTotalShares())
&& tran.getPurchasePrice().compareTo(transaction.getPurchasePrice()) == 0 ? Boolean.TRUE
: Boolean.FALSE && tran.getTransactionStatus().equals(transaction.getTransactionStatus())
&& tran.getTransactionType().equals(transaction.getTransactionType())) {
if (DateUtils.isEqual(tran.getPurchasedDate(), transaction.getPurchasedDate())
&& tran.getTotalShares().equals(transaction.getTotalShares())
&& tran.getPurchasePrice().compareTo(transaction.getPurchasePrice()) == 0
&& tran.getTransactionStatus().equals(transaction.getTransactionStatus())
&& tran.getTransactionType().equals(transaction.getTransactionType())) {
returnTrans = tran;
break;
}
@@ -469,7 +469,7 @@ public class ShareAccountDataSerializer {
}
LocalDate approvedDate = this.fromApiJsonHelper.extractLocalDateNamed(ShareAccountApiConstants.approveddate_paramname, element);
final LocalDate submittalDate = account.getSubmittedDate();
if (approvedDate != null && approvedDate.isBefore(submittalDate)) {
if (approvedDate != null && DateUtils.isBefore(approvedDate, submittalDate)) {
final DateTimeFormatter formatter = DateTimeFormatter.ofPattern(jsonCommand.dateFormat())
.withLocale(jsonCommand.extractLocale());
final String submittalDateAsString = formatter.format(submittalDate);
@@ -610,7 +610,7 @@ public class ShareAccountDataSerializer {
LocalDate activatedDate = this.fromApiJsonHelper.extractLocalDateNamed(ShareAccountApiConstants.activatedate_paramname, element);
baseDataValidator.reset().parameter(ShareAccountApiConstants.activatedate_paramname).value(activatedDate).notNull();
final LocalDate approvedDate = account.getApprovedDate();
if (activatedDate != null && activatedDate.isBefore(approvedDate)) {
if (activatedDate != null && DateUtils.isBefore(activatedDate, approvedDate)) {
final DateTimeFormatter formatter = DateTimeFormatter.ofPattern(jsonCommand.dateFormat())
.withLocale(jsonCommand.extractLocale());
final String submittalDateAsString = formatter.format(approvedDate);
@@ -710,7 +710,7 @@ public class ShareAccountDataSerializer {
for (ShareAccountTransaction transaction : transactions) {
if (!transaction.isChargeTransaction()) {
LocalDate transactionDate = transaction.getPurchasedDate();
if (requestedDate.isBefore(transactionDate)) {
if (DateUtils.isBefore(requestedDate, transactionDate)) {
isTransactionBeforeExistingTransactions = true;
break;
}
@@ -867,7 +867,7 @@ public class ShareAccountDataSerializer {
for (ShareAccountTransaction transaction : transactions) {
if (!transaction.isChargeTransaction() && transaction.isActive()) {
LocalDate transactionDate = transaction.getPurchasedDate();
if (requestedDate.isBefore(transactionDate)) {
if (DateUtils.isBefore(requestedDate, transactionDate)) {
isTransactionBeforeExistingTransactions = true;
break;
}
@@ -908,8 +908,8 @@ public class ShareAccountDataSerializer {
if (lockinPeriod == null && periodType == null) {
return;
}
Long totalSharesCanBeRedeemed = Long.valueOf(0);
Long totalSharesPurchasedBeforeRedeem = Long.valueOf(0);
Long totalSharesCanBeRedeemed = 0L;
Long totalSharesPurchasedBeforeRedeem = 0L;
boolean isPurchaseTransactionExist = false;
Set<ShareAccountTransaction> transactions = account.getShareAccountTransactions();
@@ -917,7 +917,7 @@ public class ShareAccountDataSerializer {
if (transaction.isActive() && !transaction.isChargeTransaction()) {
LocalDate purchaseDate = transaction.getPurchasedDate();
LocalDate lockinDate = deriveLockinPeriodDuration(lockinPeriod, periodType, purchaseDate);
if (!lockinDate.isAfter(redeemDate)) {
if (!DateUtils.isAfter(lockinDate, redeemDate)) {
if (transaction.isPurchasTransaction()) {
totalSharesCanBeRedeemed += transaction.getTotalShares();
} else if (transaction.isRedeemTransaction()) {
@@ -925,7 +925,7 @@ public class ShareAccountDataSerializer {
}
}
if (!purchaseDate.isAfter(redeemDate)) {
if (!DateUtils.isAfter(purchaseDate, redeemDate)) {
isPurchaseTransactionExist = true;
if (transaction.isPurchasTransaction()) {
totalSharesPurchasedBeforeRedeem += transaction.getTotalShares();
@@ -1022,7 +1022,7 @@ public class ShareAccountDataSerializer {
for (ShareAccountTransaction transaction : transactions) {
if (!transaction.isChargeTransaction()) {
LocalDate transactionDate = transaction.getPurchasedDate();
if (closedDate.isBefore(transactionDate)) {
if (DateUtils.isBefore(closedDate, transactionDate)) {
isTransactionBeforeExistingTransactions = true;
break;
}
@@ -140,8 +140,8 @@ public class ShareAccountReadPlatformServiceImpl implements ShareAccountReadPlat
if (marketDataSet != null && !marketDataSet.isEmpty()) {
LocalDate currentDate = DateUtils.getBusinessLocalDate();
for (ShareProductMarketPriceData data : marketDataSet) {
LocalDate futureDate = data.getFromDate();
if (currentDate.isAfter(futureDate)) {
LocalDate fromDate = data.getFromDate();
if (DateUtils.isBefore(fromDate, currentDate)) {
marketValue = data.getShareValue();
}
}
@@ -128,7 +128,7 @@ public class ShareAccountWritePlatformServiceJpaRepositoryImpl implements ShareA
private Map<String, Object> populateJournalEntries(final ShareAccount account, final Set<ShareAccountTransaction> transactions) {
final Map<String, Object> accountingBridgeData = new HashMap<>();
Boolean cashBasedAccounting = account.getShareProduct().getAccountingType() == 2 ? Boolean.TRUE : Boolean.FALSE;
Boolean cashBasedAccounting = account.getShareProduct().getAccountingType() == 2;
accountingBridgeData.put("cashBasedAccountingEnabled", cashBasedAccounting);
accountingBridgeData.put("accrualBasedAccountingEnabled", Boolean.FALSE);
accountingBridgeData.put("shareAccountId", account.getId());
@@ -237,7 +237,7 @@ public class ShareProduct extends AbstractAuditableCustom {
public boolean setUnitPrice(BigDecimal unitPrice) {
boolean returnValue = false;
if (this.unitPrice.compareTo(unitPrice) == 0 ? Boolean.FALSE : Boolean.TRUE) {
if (this.unitPrice.compareTo(unitPrice) != 0) {
this.unitPrice = unitPrice;
returnValue = true;
}
@@ -353,7 +353,7 @@ public class ShareProduct extends AbstractAuditableCustom {
public boolean setshareCapitalValue(BigDecimal shareCapitalValue) {
boolean updated = false;
if (this.shareCapital == null || this.shareCapital.compareTo(shareCapitalValue) == 0 ? Boolean.FALSE : Boolean.TRUE) {
if (this.shareCapital == null || this.shareCapital.compareTo(shareCapitalValue) != 0) {
this.shareCapital = shareCapitalValue;
updated = true;
}
@@ -395,8 +395,8 @@ public class ShareProduct extends AbstractAuditableCustom {
BigDecimal marketValue = this.unitPrice;
if (this.marketPrice != null && !this.marketPrice.isEmpty()) {
for (ShareProductMarketPrice data : this.marketPrice) {
LocalDate futureDate = data.getStartDate();
if (currentDate.compareTo(futureDate) == 0 ? Boolean.TRUE : Boolean.FALSE || currentDate.isAfter(futureDate)) {
LocalDate startDate = data.getStartDate();
if (!DateUtils.isAfter(startDate, currentDate)) {
marketValue = data.getPrice();
}
}
@@ -406,7 +406,7 @@ public class ShareProduct extends AbstractAuditableCustom {
public void addSubscribedShares(final Long subscribedShares) {
if (this.totalSubscribedShares == null) {
this.totalSubscribedShares = Long.valueOf(0);
this.totalSubscribedShares = 0L;
}
this.totalSubscribedShares += subscribedShares;
}
@@ -24,6 +24,7 @@ import java.time.temporal.ChronoUnit;
import java.util.Collection;
import java.util.HashMap;
import java.util.Map;
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.products.service.ShareProductReadPlatformService;
@@ -106,7 +107,7 @@ public class ShareProductDividendAssembler {
if (status.isApproved() && !type.isChargePayment()) {
LocalDate shareStartDate = purchasedSharesData.getPurchasedDate();
if (shareStartDate.isBefore(lastDividendPostDate)) {
if (DateUtils.isBefore(shareStartDate, lastDividendPostDate)) {
shareStartDate = lastDividendPostDate;
}
int numberOfPurchseDays = Math.toIntExact(ChronoUnit.DAYS.between(shareStartDate, postingDate));
@@ -282,7 +282,7 @@ public class TaxValidator {
for (TaxGroupMappings mapping : groupMappings) {
if (mapping.getId() != null) {
TaxGroupMappings existing = taxGroup.findOneBy(mapping);
if (existing.endDate() != null && mapping.endDate() != null && !existing.endDate().isEqual(mapping.endDate())) {
if (existing.endDate() != null && mapping.endDate() != null && !DateUtils.isEqual(existing.endDate(), mapping.endDate())) {
baseDataValidator.reset().parameter(TaxApiConstants.endDateParamName)
.failWithCode("can.not.modify.end.date.once.updated");
} else {
@@ -335,7 +335,7 @@ public class TaxValidator {
if (groupMappingsOne.getTaxComponent().equals(groupMappings.getTaxComponent())) {
if (groupMappingsOne.endDate() == null && groupMappings.endDate() == null) {
baseDataValidator.reset().parameter(COMPONENT).failWithCode(DATES_ARE_OVERLAPPING);
} else if (groupMappingsOne.startDate().isAfter(groupMappings.startDate())) {
} else if (DateUtils.isAfter(groupMappingsOne.startDate(), groupMappings.startDate())) {
baseDataValidator.reset().parameter(COMPONENT_START_DATE).value(groupMappingsOne.startDate())
.validateDateAfter(groupMappings.endDate());
} else {
@@ -81,7 +81,7 @@ public class PurgeProcessedCommandsTaskletTest {
// then
verify(repository, times(1)).deleteOlderEventsWithStatus(Mockito.any(), Mockito.any());
verify(repository).deleteOlderEventsWithStatus(Mockito.any(), dateCriteriaCaptor.capture());
OffsetDateTime expectedDateForPurgeCriteriaTest = DateUtils.getOffsetDateTimeOfTenant().minusDays(2);
OffsetDateTime expectedDateForPurgeCriteriaTest = DateUtils.getAuditOffsetDateTime().minusDays(2);
OffsetDateTime actualDateForPurgeCriteria = dateCriteriaCaptor.getValue();
assertTrue(expectedDateForPurgeCriteriaTest.toEpochSecond() - actualDateForPurgeCriteria.toEpochSecond() <= 1);
assertEquals(RepeatStatus.FINISHED, resultStatus);
@@ -26,10 +26,13 @@ import static org.mockito.Mockito.when;
import java.math.BigDecimal;
import java.time.LocalDate;
import java.time.OffsetDateTime;
import java.util.Arrays;
import java.util.Collection;
import java.util.Collections;
import java.util.List;
import org.apache.fineract.infrastructure.core.domain.ExternalId;
import org.apache.fineract.infrastructure.core.service.DateUtils;
import org.apache.fineract.portfolio.charge.domain.Charge;
import org.apache.fineract.portfolio.charge.domain.ChargeCalculationType;
import org.apache.fineract.portfolio.charge.domain.ChargePaymentMode;
@@ -170,6 +173,68 @@ public class LoanTest {
assertEquals(loanTransaction2, userTransaction);
}
/**
* Tests {@link Loan#getLastUserTransaction()} where there are user transactions
*/
@Test
public void testTransactionComparator() {
final Loan loan = new Loan();
LocalDate today = LocalDate.of(2023, 10, 12);
OffsetDateTime now = DateUtils.getAuditOffsetDateTime();
LoanTransaction lt1 = new LoanTransaction();
ReflectionTestUtils.setField(lt1, "id", 1L);
ReflectionTestUtils.setField(lt1, "typeOf", LoanTransactionType.DISBURSEMENT.getValue());
ReflectionTestUtils.setField(lt1, "dateOf", today);
ReflectionTestUtils.setField(lt1, "createdDate", now);
LoanTransaction lt2 = new LoanTransaction();
ReflectionTestUtils.setField(lt2, "id", 2L);
ReflectionTestUtils.setField(lt2, "typeOf", LoanTransactionType.WITHDRAW_TRANSFER.getValue());
ReflectionTestUtils.setField(lt2, "dateOf", today);
ReflectionTestUtils.setField(lt2, "createdDate", now);
LoanTransaction lt3 = new LoanTransaction();
ReflectionTestUtils.setField(lt3, "id", 3L);
ReflectionTestUtils.setField(lt3, "typeOf", LoanTransactionType.REPAYMENT.getValue());
ReflectionTestUtils.setField(lt3, "dateOf", today);
ReflectionTestUtils.setField(lt3, "createdDate", now);
ReflectionTestUtils.setField(lt3, "reversed", true);
LoanTransaction lt4 = new LoanTransaction();
ReflectionTestUtils.setField(lt4, "id", 4L);
ReflectionTestUtils.setField(lt4, "typeOf", LoanTransactionType.WAIVE_INTEREST.getValue());
ReflectionTestUtils.setField(lt4, "dateOf", today);
ReflectionTestUtils.setField(lt4, "createdDate", now);
LoanTransaction lt5 = new LoanTransaction();
ReflectionTestUtils.setField(lt5, "id", 5L);
ReflectionTestUtils.setField(lt5, "typeOf", LoanTransactionType.INCOME_POSTING.getValue());
ReflectionTestUtils.setField(lt5, "dateOf", today);
ReflectionTestUtils.setField(lt5, "createdDate", now);
LoanTransaction lt6 = new LoanTransaction();
ReflectionTestUtils.setField(lt6, "typeOf", LoanTransactionType.WITHDRAW_TRANSFER.getValue());
ReflectionTestUtils.setField(lt6, "dateOf", today.minusDays(2));
LoanTransaction lt7 = new LoanTransaction();
ReflectionTestUtils.setField(lt7, "id", 7L);
ReflectionTestUtils.setField(lt7, "typeOf", LoanTransactionType.WITHDRAW_TRANSFER.getValue());
ReflectionTestUtils.setField(lt7, "dateOf", today.minusDays(2));
LoanTransaction lt8 = new LoanTransaction();
ReflectionTestUtils.setField(lt8, "id", 8L);
ReflectionTestUtils.setField(lt8, "typeOf", LoanTransactionType.WITHDRAW_TRANSFER.getValue());
ReflectionTestUtils.setField(lt8, "dateOf", today.minusDays(2));
ReflectionTestUtils.setField(lt8, "createdDate", now.minusMinutes(2));
List<LoanTransaction> transactions = Arrays.asList(lt1, lt2, lt3, lt4, lt5, lt6, lt7, lt8);
transactions.sort(LoanTransactionComparator.INSTANCE);
assertEquals(8L, transactions.get(0).getId());
assertEquals(7L, transactions.get(1).getId());
assertNull(transactions.get(2).getId());
assertEquals(today.minusDays(2), transactions.get(2).getTransactionDate());
assertEquals(5L, transactions.get(3).getId());
assertEquals(4L, transactions.get(4).getId());
assertEquals(1L, transactions.get(5).getId());
assertEquals(2L, transactions.get(6).getId());
assertEquals(3L, transactions.get(7).getId());
}
/**
* Builds a new loan charge.
*