Business date - part 2 (#2384)

Business date - part 2
This commit is contained in:
Adam Saghy
2022-06-29 15:56:31 +02:00
committed by GitHub
parent 63a3f56dd1
commit 632a08a5ce
147 changed files with 1059 additions and 917 deletions
@@ -69,7 +69,7 @@ public final class AccrualAccountingDataValidator {
.resource(PERIODIC_ACCRUAL_ACCOUNTING_RESOURCE_NAME);
final LocalDate date = this.fromApiJsonHelper.extractLocalDateNamed(accrueTillParamName, element);
baseDataValidator.reset().parameter(accrueTillParamName).value(date).notNull().validateDateBefore(DateUtils.getLocalDateOfTenant());
baseDataValidator.reset().parameter(accrueTillParamName).value(date).notNull().validateDateBefore(DateUtils.getBusinessLocalDate());
throwExceptionIfValidationWarningsExist(dataValidationErrors);
@@ -67,7 +67,7 @@ public class GLClosureWritePlatformServiceJpaRepositoryImpl implements GLClosure
final Office office = this.officeRepositoryWrapper.findOneWithNotFoundDetection(officeId);
// TODO: Get Tenant specific date
// ensure closure date is not in the future
final Date todaysDate = new Date();
final Date todaysDate = DateUtils.getBusinessDate();
final Date closureDate = command.dateValueOfParameterNamed(GLClosureJsonInputParams.CLOSING_DATE.getValue());
if (closureDate.after(todaysDate)) {
throw new GLClosureInvalidException(GlClosureInvalidReason.FUTURE_DATE, closureDate);
@@ -427,7 +427,7 @@ public class JournalEntryReadPlatformServiceImpl implements JournalEntryReadPlat
}
}
final LocalDate transactionDate = DateUtils.getLocalDateOfTenant();
final LocalDate transactionDate = DateUtils.getBusinessLocalDate();
final OfficeOpeningBalancesData officeOpeningBalancesData = OfficeOpeningBalancesData.createNew(officeId, officeData.name(),
transactionDate, contraAccount, assetAccountOpeningBalances, liabityAccountOpeningBalances, incomeAccountOpeningBalances,
@@ -72,6 +72,7 @@ import org.apache.fineract.infrastructure.core.data.DataValidatorBuilder;
import org.apache.fineract.infrastructure.core.exception.GeneralPlatformDomainRuleException;
import org.apache.fineract.infrastructure.core.exception.PlatformApiDataValidationException;
import org.apache.fineract.infrastructure.core.exception.PlatformDataIntegrityException;
import org.apache.fineract.infrastructure.core.service.DateUtils;
import org.apache.fineract.infrastructure.security.service.PlatformSecurityContext;
import org.apache.fineract.organisation.office.domain.Office;
import org.apache.fineract.organisation.office.domain.OfficeRepositoryWrapper;
@@ -562,7 +563,7 @@ public class JournalEntryWritePlatformServiceJpaRepositoryImpl implements Journa
final LocalDate entryLocalDate = command.getTransactionDate();
final Date transactionDate = Date.from(entryLocalDate.atStartOfDay(ZoneId.systemDefault()).toInstant());
// shouldn't be in the future
final Date todaysDate = new Date();
final Date todaysDate = DateUtils.getBusinessDate();
if (transactionDate.after(todaysDate)) {
throw new JournalEntryInvalidException(GlJournalEntryInvalidReason.FUTURE_DATE, transactionDate, null, null);
}
@@ -65,7 +65,7 @@ public class ProvisioningEntriesDefinitionJsonDeserializer implements Provisioni
baseDataValidator.reset().parameter(JSON_DATEFORMAT_PARAM).value(dateformat).notBlank();
LocalDate localDate = this.fromApiJsonHelper.extractLocalDateNamed(JSON_DATE_PARAM, element);
baseDataValidator.reset().parameter(JSON_DATE_PARAM).value(localDate).notBlank();
baseDataValidator.reset().parameter(JSON_DATE_PARAM).value(localDate).validateDateBeforeOrEqual(DateUtils.getLocalDateOfTenant());
baseDataValidator.reset().parameter(JSON_DATE_PARAM).value(localDate).validateDateBeforeOrEqual(DateUtils.getBusinessLocalDate());
if (this.fromApiJsonHelper.parameterExists(JSON_CREATEJOURNALENTRIES_PARAM, element)) {
Boolean bool = this.fromApiJsonHelper.extractBooleanNamed(JSON_CREATEJOURNALENTRIES_PARAM, element);
baseDataValidator.reset().parameter(JSON_CREATEJOURNALENTRIES_PARAM).value(bool).validateForBooleanValue();
@@ -135,7 +135,7 @@ public class ProvisioningEntriesWritePlatformServiceJpaRepositoryImpl implements
@Override
@CronTarget(jobName = JobName.GENERATE_LOANLOSS_PROVISIONING)
public void generateLoanLossProvisioningAmount() {
Date currentDate = Date.from(DateUtils.getLocalDateOfTenant().atStartOfDay(ZoneId.systemDefault()).toInstant());
Date currentDate = DateUtils.getBusinessDate();
boolean addJournalEntries = true;
try {
Collection<ProvisioningCriteriaData> criteriaCollection = this.provisioningCriteriaReadPlatformService
@@ -22,33 +22,27 @@ import java.time.LocalDate;
import java.time.ZonedDateTime;
import java.time.temporal.ChronoUnit;
import java.util.Collection;
import java.util.Date;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.apache.fineract.adhocquery.data.AdHocData;
import org.apache.fineract.adhocquery.domain.ReportRunFrequency;
import org.apache.fineract.infrastructure.core.service.DateUtils;
import org.apache.fineract.infrastructure.core.service.ThreadLocalContextUtil;
import org.apache.fineract.infrastructure.core.service.database.DatabaseSpecificSQLGenerator;
import org.apache.fineract.infrastructure.jobs.annotation.CronTarget;
import org.apache.fineract.infrastructure.jobs.service.JobName;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.jdbc.core.JdbcTemplate;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
@Service(value = "adHocScheduledJobRunnerService")
@RequiredArgsConstructor
@Slf4j
public class AdHocScheduledJobRunnerServiceImpl implements AdHocScheduledJobRunnerService {
private static final Logger LOG = LoggerFactory.getLogger(AdHocScheduledJobRunnerServiceImpl.class);
private final AdHocReadPlatformService adHocReadPlatformService;
private final JdbcTemplate jdbcTemplate;
@Autowired
public AdHocScheduledJobRunnerServiceImpl(final JdbcTemplate jdbcTemplate, final AdHocReadPlatformService adHocReadPlatformService) {
this.jdbcTemplate = jdbcTemplate;
this.adHocReadPlatformService = adHocReadPlatformService;
}
private final DatabaseSpecificSQLGenerator sqlGenerator;
@Transactional
@Override
@@ -99,18 +93,19 @@ public class AdHocScheduledJobRunnerServiceImpl implements AdHocScheduledJobRunn
.append(adhoc.getQuery());
if (insertSqlBuilder.length() > 0) {
final int result = this.jdbcTemplate.update(insertSqlBuilder.toString());
LOG.info("{}: Records affected by generateClientSchedule: {}", ThreadLocalContextUtil.getTenant().getName(),
log.info("{}: Records affected by generateClientSchedule: {}", ThreadLocalContextUtil.getTenant().getName(),
result);
this.jdbcTemplate.update("UPDATE m_adhoc SET last_run=? WHERE id=?", new Date(), adhoc.getId());
this.jdbcTemplate.update("UPDATE m_adhoc SET last_run=? WHERE id=?", DateUtils.getLocalDateTimeOfTenant(),
adhoc.getId());
}
} else {
LOG.info("{}: Skipping execution of {}, scheduled for execution on {}",
log.info("{}: Skipping execution of {}, scheduled for execution on {}",
new Object[] { ThreadLocalContextUtil.getTenant().getName(), adhoc.getName(), next });
}
});
} else {
LOG.info("{}: Nothing to update by generateClientSchedule", ThreadLocalContextUtil.getTenant().getName());
log.info("{}: Nothing to update by generateClientSchedule", ThreadLocalContextUtil.getTenant().getName());
}
}
@@ -222,15 +222,15 @@ public class SynchronousCommandProcessingService implements CommandProcessingSer
private void publishEvent(final String entityName, final String actionName, JsonCommand command, final Object result) {
Gson gson = new Gson();
try {
final String authToken = ThreadLocalContextUtil.getAuthToken();
final String tenantIdentifier = ThreadLocalContextUtil.getTenant().getTenantIdentifier();
final AppUser appUser = this.context.authenticatedUser(CommandWrapper.wrap(actionName, entityName, null, null));
final HookEventSource hookEventSource = new HookEventSource(entityName, actionName);
// TODO: Add support for publishing array events
if (command.json() != null && command.json().startsWith("{")) {
Type type = new TypeToken<Map<String, Object>>() {}.getType();
Type type = new TypeToken<Map<String, Object>>() {
}.getType();
Map<String, Object> myMap = gson.fromJson(command.json(), type);
Map<String, Object> reqmap = new HashMap<>();
@@ -264,7 +264,8 @@ public class SynchronousCommandProcessingService implements CommandProcessingSer
final String serializedResult = this.toApiResultJsonSerializer.serialize(reqmap);
final HookEvent applicationEvent = new HookEvent(hookEventSource, serializedResult, tenantIdentifier, appUser, authToken);
final HookEvent applicationEvent = new HookEvent(hookEventSource, serializedResult, appUser,
ThreadLocalContextUtil.getContext());
applicationContext.publishEvent(applicationEvent);
}
@@ -18,12 +18,11 @@
*/
package org.apache.fineract.infrastructure.bulkimport.data;
import org.apache.fineract.infrastructure.core.domain.FineractContext;
import org.apache.fineract.infrastructure.core.domain.FineractEvent;
import org.apache.poi.ss.usermodel.Workbook;
import org.springframework.context.ApplicationEvent;
public final class BulkImportEvent extends ApplicationEvent {
private final String tenantIdentifier;
public final class BulkImportEvent extends FineractEvent {
private final Workbook workbook;
@@ -33,23 +32,18 @@ public final class BulkImportEvent extends ApplicationEvent {
private final String dateFormat;
private BulkImportEvent(final String tenantIdentifier, final Workbook workbook, final Long importId, final String locale,
final String dateFormat) {
super(BulkImportEvent.class);
this.tenantIdentifier = tenantIdentifier;
private BulkImportEvent(final Object source, final Workbook workbook, final Long importId, final String locale, final String dateFormat,
FineractContext context) {
super(source, context);
this.workbook = workbook;
this.importId = importId;
this.locale = locale;
this.dateFormat = dateFormat;
}
public static BulkImportEvent instance(final String tenantIdentifier, final Workbook workbook, final Long importId, final String locale,
final String dateFormat) {
return new BulkImportEvent(tenantIdentifier, workbook, importId, locale, dateFormat);
}
public String getTenantIdentifier() {
return tenantIdentifier;
public static BulkImportEvent instance(final Object source, final Workbook workbook, final Long importId, final String locale,
final String dateFormat, FineractContext context) {
return new BulkImportEvent(source, workbook, importId, locale, dateFormat, context);
}
public Workbook getWorkbook() {
@@ -21,7 +21,6 @@ package org.apache.fineract.infrastructure.bulkimport.importhandler.chartofaccou
import com.google.gson.GsonBuilder;
import java.math.BigDecimal;
import java.time.LocalDate;
import java.time.ZoneId;
import java.util.ArrayList;
import java.util.List;
import org.apache.fineract.accounting.glaccount.data.GLAccountData;
@@ -47,6 +46,7 @@ import org.apache.fineract.infrastructure.codes.data.CodeValueData;
import org.apache.fineract.infrastructure.core.data.CommandProcessingResult;
import org.apache.fineract.infrastructure.core.data.EnumOptionData;
import org.apache.fineract.infrastructure.core.serialization.GoogleGsonSerializerHelper;
import org.apache.fineract.infrastructure.core.service.DateUtils;
import org.apache.fineract.organisation.monetary.data.CurrencyData;
import org.apache.poi.ss.usermodel.Cell;
import org.apache.poi.ss.usermodel.IndexedColors;
@@ -234,10 +234,7 @@ public class ChartOfAccountsImportHandler implements ImportHandler {
// for opening balance
private JournalEntryData readAddJournalEntries(Row row, String locale, String dateFormat) {
LocalDate transactionDateCheck = LocalDate.now(ZoneId.systemDefault());
if (transactionDateCheck != null) {
transactionDate = transactionDateCheck;
}
transactionDate = DateUtils.getBusinessLocalDate();
String officeName = ImportHandlerUtils.readAsString(ChartOfAcountsConstants.OFFICE_COL, row);
Long officeId = ImportHandlerUtils.readAsLong(ChartOfAcountsConstants.OFFICE_COL_ID, row);
@@ -99,7 +99,7 @@ public class SharedProductsSheetPopulator extends AbstractWorkbookPopulator {
BigDecimal marketValue = shareProductData.getUnitPrice();
Collection<ShareProductMarketPriceData> marketDataSet = shareProductData.getMarketPrice();
if (marketDataSet != null && !marketDataSet.isEmpty()) {
Date currentDate = DateUtils.getDateOfTenant();
Date currentDate = DateUtils.getBusinessDate();
for (ShareProductMarketPriceData data : marketDataSet) {
Date futureDate = data.getStartDate();
if (currentDate.after(futureDate)) {
@@ -30,7 +30,6 @@ import org.apache.fineract.infrastructure.bulkimport.data.GlobalEntityType;
import org.apache.fineract.infrastructure.bulkimport.domain.ImportDocument;
import org.apache.fineract.infrastructure.bulkimport.domain.ImportDocumentRepository;
import org.apache.fineract.infrastructure.bulkimport.importhandler.ImportHandler;
import org.apache.fineract.infrastructure.core.domain.FineractPlatformTenant;
import org.apache.fineract.infrastructure.core.exception.GeneralPlatformDomainRuleException;
import org.apache.fineract.infrastructure.core.service.DateUtils;
import org.apache.fineract.infrastructure.core.service.ThreadLocalContextUtil;
@@ -66,10 +65,7 @@ public class BulkImportEventListener implements ApplicationListener<BulkImportEv
@Override
public void onApplicationEvent(final BulkImportEvent event) {
final String tenantIdentifier = event.getTenantIdentifier();
final FineractPlatformTenant tenant = this.tenantDetailsService.loadTenantById(tenantIdentifier);
ThreadLocalContextUtil.setTenant(tenant);
ThreadLocalContextUtil.init(event.getContext());
ImportHandler importHandler = null;
final ImportDocument importDocument = this.importRepository.findById(event.getImportId()).orElse(null);
final GlobalEntityType entityType = GlobalEntityType.fromInt(importDocument.getEntityType());
@@ -251,7 +251,7 @@ public class BulkImportWorkbookPopulatorServiceImpl implements BulkImportWorkboo
}
private Response buildResponse(final Workbook workbook, final String entity) {
String filename = entity + DateUtils.getLocalDateOfTenant().toString() + ".xls";
String filename = entity + DateUtils.getBusinessLocalDate().toString() + ".xls";
final ByteArrayOutputStream baos = new ByteArrayOutputStream();
try {
workbook.write(baos);
@@ -195,8 +195,8 @@ public class BulkImportWorkbookServiceImpl implements BulkImportWorkbookService
final ImportDocument importDocument = ImportDocument.instance(document, DateUtils.getLocalDateTimeOfTenant(), entityType.getValue(),
this.securityContext.authenticatedUser(), ImportHandlerUtils.getNumberOfRows(workbook.getSheetAt(0), primaryColumn));
this.importDocumentRepository.saveAndFlush(importDocument);
BulkImportEvent event = BulkImportEvent.instance(ThreadLocalContextUtil.getTenant().getTenantIdentifier(), workbook,
importDocument.getId(), locale, dateFormat);
BulkImportEvent event = BulkImportEvent.instance(this, workbook, importDocument.getId(), locale, dateFormat,
ThreadLocalContextUtil.getContext());
applicationContext.publishEvent(event);
return importDocument.getId();
}
@@ -18,12 +18,17 @@
*/
package org.apache.fineract.infrastructure.businessdate.service;
import java.time.LocalDate;
import java.util.HashMap;
import java.util.List;
import org.apache.fineract.infrastructure.businessdate.data.BusinessDateData;
import org.apache.fineract.infrastructure.businessdate.domain.BusinessDateType;
public interface BusinessDateReadPlatformService {
List<BusinessDateData> findAll();
BusinessDateData findByType(String type);
HashMap<BusinessDateType, LocalDate> getBusinessDates();
}
@@ -18,6 +18,9 @@
*/
package org.apache.fineract.infrastructure.businessdate.service;
import java.time.LocalDate;
import java.time.ZoneId;
import java.util.HashMap;
import java.util.List;
import java.util.Optional;
import lombok.RequiredArgsConstructor;
@@ -28,6 +31,8 @@ import org.apache.fineract.infrastructure.businessdate.domain.BusinessDateReposi
import org.apache.fineract.infrastructure.businessdate.domain.BusinessDateType;
import org.apache.fineract.infrastructure.businessdate.exception.BusinessDateNotFoundException;
import org.apache.fineract.infrastructure.businessdate.mapper.BusinessDateMapper;
import org.apache.fineract.infrastructure.configuration.domain.ConfigurationDomainService;
import org.apache.fineract.infrastructure.core.service.DateUtils;
import org.springframework.stereotype.Service;
@Slf4j
@@ -37,6 +42,7 @@ public class BusinessDateReadPlatformServiceImpl implements BusinessDateReadPlat
private final BusinessDateRepository repository;
private final BusinessDateMapper mapper;
private final ConfigurationDomainService configurationDomainService;
@Override
public List<BusinessDateData> findAll() {
@@ -60,4 +66,20 @@ public class BusinessDateReadPlatformServiceImpl implements BusinessDateReadPlat
}
return mapper.map(businessDate.get());
}
@Override
public HashMap<BusinessDateType, LocalDate> getBusinessDates() {
HashMap<BusinessDateType, LocalDate> businessDateMap = new HashMap<>();
ZoneId zone = DateUtils.getDateTimeZoneOfTenant();
LocalDate tenantDate = LocalDate.now(zone);
businessDateMap.put(BusinessDateType.BUSINESS_DATE, tenantDate);
if (configurationDomainService.isBusinessDateEnabled()) {
final List<BusinessDateData> businessDateDataList = this.findAll();
for (BusinessDateData businessDateData : businessDateDataList) {
businessDateMap.put(BusinessDateType.valueOf(businessDateData.getType()), businessDateData.getDate());
}
}
return businessDateMap;
}
}
@@ -95,6 +95,7 @@ public class BusinessDateWritePlatformServiceImpl implements BusinessDateWritePl
List<Throwable> exceptions = new ArrayList<>();
Map<String, Object> changes = new HashMap<>();
Optional<BusinessDate> businessDateEntity = repository.findByType(businessDateType);
LocalDate businessDate = businessDateEntity.map(BusinessDate::getDate).orElse(DateUtils.getLocalDateOfTenant());
businessDate = businessDate.plusDays(1);
try {
@@ -185,7 +185,7 @@ public class EmailCampaign extends AbstractPersistableCustom {
} else {
emailAttachmentFileFormat = ScheduledEmailAttachmentFileFormat.instance(2);
}
LocalDate submittedOnDate = LocalDate.now(DateUtils.getDateTimeZoneOfTenant());
LocalDate submittedOnDate = DateUtils.getBusinessLocalDate();
if (command.hasParameter(EmailCampaignValidator.submittedOnDateParamName)) {
submittedOnDate = command.localDateValueOfParameterNamed(EmailCampaignValidator.submittedOnDateParamName);
}
@@ -474,7 +474,7 @@ public class EmailCampaign extends AbstractPersistableCustom {
}
private boolean isDateInTheFuture(final LocalDate localDate) {
return localDate.isAfter(DateUtils.getLocalDateOfTenant());
return localDate.isAfter(DateUtils.getBusinessLocalDate());
}
public Report getBusinessRuleId() {
@@ -18,8 +18,6 @@
*/
package org.apache.fineract.infrastructure.campaigns.email.domain;
import java.time.LocalDate;
import java.time.ZoneId;
import java.util.Date;
import java.util.LinkedHashMap;
import java.util.Map;
@@ -109,8 +107,7 @@ public class EmailMessage extends AbstractPersistableCustom {
this.emailSubject = emailSubject;
this.message = message;
this.campaignName = campaignName;
this.submittedOnDate = Date
.from(LocalDate.now(DateUtils.getDateTimeZoneOfTenant()).atStartOfDay(ZoneId.systemDefault()).toInstant());
this.submittedOnDate = DateUtils.getBusinessDate();
}
public Map<String, Object> update(final JsonCommand command) {
@@ -170,7 +170,7 @@ public class SmsCampaign extends AbstractPersistableCustom {
final String paramValue = command.jsonFragment(SmsCampaignValidator.paramValue);
final String message = command.stringValueOfParameterNamed(SmsCampaignValidator.message);
LocalDate submittedOnDate = LocalDate.now(DateUtils.getDateTimeZoneOfTenant());
LocalDate submittedOnDate = DateUtils.getBusinessLocalDate();
if (command.hasParameter(SmsCampaignValidator.submittedOnDateParamName)) {
submittedOnDate = command.localDateValueOfParameterNamed(SmsCampaignValidator.submittedOnDateParamName);
}
@@ -484,7 +484,7 @@ public class SmsCampaign extends AbstractPersistableCustom {
}
private boolean isDateInTheFuture(final LocalDate localDate) {
return localDate.isAfter(DateUtils.getLocalDateOfTenant());
return localDate.isAfter(DateUtils.getBusinessLocalDate());
}
public Report getBusinessRuleId() {
@@ -0,0 +1,51 @@
/**
* 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.core.api;
import com.google.gson.JsonArray;
import com.google.gson.JsonElement;
import com.google.gson.JsonPrimitive;
import com.google.gson.JsonSerializationContext;
import com.google.gson.JsonSerializer;
import java.lang.reflect.Type;
import java.time.LocalDateTime;
import java.time.temporal.ChronoField;
/**
* Serializer for Java Local Date Time {@link LocalDateTime} that returns the date in array format to match previous
* Jackson functionality.
*/
public class LocalDateTimeAdapter implements JsonSerializer<LocalDateTime> {
@Override
@SuppressWarnings("unused")
public JsonElement serialize(final LocalDateTime src, final Type typeOfSrc, final JsonSerializationContext context) {
JsonArray array = null;
if (src != null) {
array = new JsonArray();
array.add(new JsonPrimitive(src.get(ChronoField.YEAR_OF_ERA)));
array.add(new JsonPrimitive(src.getMonthValue()));
array.add(new JsonPrimitive(src.getDayOfMonth()));
array.add(new JsonPrimitive(src.getHour()));
array.add(new JsonPrimitive(src.getMinute()));
array.add(new JsonPrimitive(src.getSecond()));
}
return array;
}
}
@@ -1092,7 +1092,7 @@ public class DataValidatorBuilder {
final StringBuilder validationErrorCode = new StringBuilder("validation.msg.").append(this.resource).append(".")
.append(this.parameter).append(".is.greater.than.date");
final StringBuilder defaultEnglishMessage = new StringBuilder("The parameter `").append(this.parameter)
.append("` must be less than or equal to the provided date").append(date);
.append("` must be less than or equal to the provided date: ").append(date);
final ApiParameterError error = ApiParameterError.parameterError(validationErrorCode.toString(),
defaultEnglishMessage.toString(), this.parameter, dateVal, date);
this.dataValidationErrors.add(error);
@@ -0,0 +1,34 @@
/**
* 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.core.domain;
import lombok.AllArgsConstructor;
import lombok.Getter;
import org.apache.fineract.infrastructure.businessdate.domain.BusinessDateType;
@Getter
@AllArgsConstructor
public enum ActionContext {
DEFAULT(0, "Default context", BusinessDateType.BUSINESS_DATE), COB(1, "Close of Business context", BusinessDateType.COB_DATE);
private final int order;
private final String description;
private final BusinessDateType businessDateType;
}
@@ -0,0 +1,24 @@
/**
* 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.core.domain;
public interface ContextHolder {
FineractContext getContext();
}
@@ -0,0 +1,37 @@
/**
* 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.core.domain;
import java.io.Serializable;
import java.time.LocalDate;
import java.util.HashMap;
import lombok.AllArgsConstructor;
import lombok.Getter;
import org.apache.fineract.infrastructure.businessdate.domain.BusinessDateType;
@AllArgsConstructor
@Getter
public class FineractContext implements Serializable {
private final String contextHolder;
private final FineractPlatformTenant tenantContext;
private final String authTokenContext;
private final HashMap<BusinessDateType, LocalDate> businessDateContext;
private final ActionContext actionContext;
}
@@ -0,0 +1,37 @@
/**
* 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.core.domain;
import java.io.Serializable;
import org.springframework.context.ApplicationEvent;
public abstract class FineractEvent extends ApplicationEvent implements ContextHolder, Serializable {
private final FineractContext context;
public FineractEvent(Object source, FineractContext context) {
super(source);
this.context = context;
}
@Override
public FineractContext getContext() {
return context;
}
}
@@ -18,7 +18,9 @@
*/
package org.apache.fineract.infrastructure.core.domain;
public class FineractPlatformTenant {
import java.io.Serializable;
public class FineractPlatformTenant implements Serializable {
private final Long id;
private final String tenantIdentifier;
@@ -18,6 +18,7 @@
*/
package org.apache.fineract.infrastructure.core.domain;
import java.io.Serializable;
import java.sql.Connection;
import javax.sql.DataSource;
import org.apache.commons.lang3.StringUtils;
@@ -25,7 +26,7 @@ import org.apache.commons.lang3.StringUtils;
/**
* Holds Tenant's DB server connection connection details.
*/
public class FineractPlatformTenantConnection {
public class FineractPlatformTenantConnection implements Serializable {
private final Long connectionId;
private final String schemaServer;
@@ -25,6 +25,7 @@ import java.sql.ResultSet;
import java.sql.SQLException;
import java.sql.Timestamp;
import java.time.LocalDate;
import java.time.LocalDateTime;
import java.time.LocalTime;
import java.time.ZonedDateTime;
import java.util.Date;
@@ -48,11 +49,11 @@ public final class JdbcSupport {
return dateTime;
}
public static ZonedDateTime getLocalDateTime(final ResultSet rs, final String columnName) throws SQLException {
ZonedDateTime dateTime = null;
public static LocalDateTime getLocalDateTime(final ResultSet rs, final String columnName) throws SQLException {
LocalDateTime dateTime = null;
final Timestamp dateValue = rs.getTimestamp(columnName);
if (dateValue != null) {
dateTime = ZonedDateTime.ofInstant(new Date(dateValue.getTime()).toInstant(), getDateTimeZoneOfTenant());
dateTime = LocalDateTime.ofInstant(new Date(dateValue.getTime()).toInstant(), getDateTimeZoneOfTenant());
}
return dateTime;
}
@@ -22,6 +22,7 @@ import com.google.gson.ExclusionStrategy;
import com.google.gson.Gson;
import com.google.gson.GsonBuilder;
import java.time.LocalDate;
import java.time.LocalDateTime;
import java.time.LocalTime;
import java.time.MonthDay;
import java.time.ZonedDateTime;
@@ -32,6 +33,7 @@ import org.apache.fineract.infrastructure.core.api.DateAdapter;
import org.apache.fineract.infrastructure.core.api.JodaDateTimeAdapter;
import org.apache.fineract.infrastructure.core.api.JodaMonthDayAdapter;
import org.apache.fineract.infrastructure.core.api.LocalDateAdapter;
import org.apache.fineract.infrastructure.core.api.LocalDateTimeAdapter;
import org.apache.fineract.infrastructure.core.api.LocalTimeAdapter;
import org.apache.fineract.infrastructure.core.api.ParameterListExclusionStrategy;
import org.apache.fineract.infrastructure.core.api.ParameterListInclusionStrategy;
@@ -112,5 +114,6 @@ public final class GoogleGsonSerializerHelper {
builder.registerTypeAdapter(LocalTime.class, new LocalTimeAdapter());
builder.registerTypeAdapter(ZonedDateTime.class, new JodaDateTimeAdapter());
builder.registerTypeAdapter(MonthDay.class, new JodaMonthDayAdapter());
builder.registerTypeAdapter(LocalDateTime.class, new LocalDateTimeAdapter());
}
}
@@ -18,10 +18,6 @@
*/
package org.apache.fineract.infrastructure.core.serialization;
import static java.time.temporal.ChronoField.DAY_OF_MONTH;
import static java.time.temporal.ChronoField.MONTH_OF_YEAR;
import static java.time.temporal.ChronoField.YEAR_OF_ERA;
import com.google.gson.JsonArray;
import com.google.gson.JsonElement;
import com.google.gson.JsonObject;
@@ -46,7 +42,6 @@ import java.util.Set;
import org.apache.commons.lang3.StringUtils;
import org.apache.fineract.infrastructure.core.data.ApiParameterError;
import org.apache.fineract.infrastructure.core.exception.PlatformApiDataValidationException;
import org.apache.fineract.infrastructure.core.service.DateUtils;
import org.springframework.format.number.NumberStyleFormatter;
/**
@@ -301,19 +296,14 @@ public class JsonParserHelper {
final JsonObject object = element.getAsJsonObject();
if (object.has(parameterName) && object.get(parameterName).isJsonArray()) {
parametersPassedInCommand.add(parameterName);
final JsonArray dateArray = object.get(parameterName).getAsJsonArray();
final int year = dateArray.get(0).getAsInt();
final int month = dateArray.get(1).getAsInt();
final int day = dateArray.get(2).getAsInt();
final Integer year = dateArray.get(0).getAsInt();
final Integer month = dateArray.get(1).getAsInt();
final Integer day = dateArray.get(2).getAsInt();
value = LocalDate.now(DateUtils.getDateTimeZoneOfTenant()).with(YEAR_OF_ERA, year).with(MONTH_OF_YEAR, month)
.with(DAY_OF_MONTH, day);
value = LocalDate.of(year, month, day);
}
}
return value;
}
@@ -26,6 +26,7 @@ import java.time.LocalDateTime;
import java.time.ZoneId;
import java.time.ZonedDateTime;
import java.time.format.DateTimeFormatter;
import java.time.format.DateTimeFormatterBuilder;
import java.time.temporal.ChronoUnit;
import java.util.ArrayList;
import java.util.Calendar;
@@ -38,8 +39,12 @@ import org.apache.fineract.infrastructure.core.exception.PlatformApiDataValidati
public final class DateUtils {
public static final String DEFAULT_DATETIME_FORMAT = "yyyy-MM-dd HH:mm:ss";
public static final DateTimeFormatter DEFAULT_DATETIME_FORMATER = DateTimeFormatter.ofPattern(DEFAULT_DATETIME_FORMAT);
public static final String DEFAULT_DATE_FORMAT = "yyyy-MM-dd";
public static final String DEFAULT_DATETIME_FORMAT = DEFAULT_DATE_FORMAT + " HH:mm:ss";
public static final DateTimeFormatter DEFAULT_DATETIME_FORMATER = new DateTimeFormatterBuilder().appendPattern(DEFAULT_DATETIME_FORMAT)
.toFormatter();
public static final DateTimeFormatter DEFAULT_DATE_FORMATER = new DateTimeFormatterBuilder().appendPattern(DEFAULT_DATE_FORMAT)
.toFormatter();
private DateUtils() {
@@ -51,11 +56,7 @@ public final class DateUtils {
public static ZoneId getDateTimeZoneOfTenant() {
final FineractPlatformTenant tenant = ThreadLocalContextUtil.getTenant();
ZoneId zone = ZoneId.systemDefault();
if (tenant != null) {
zone = ZoneId.of(tenant.getTimezoneId());
}
return zone;
return ZoneId.of(tenant.getTimezoneId());
}
public static TimeZone getTimeZoneOfTenant() {
@@ -71,7 +72,7 @@ public final class DateUtils {
return convertLocalDateToDate(getLocalDateOfTenant());
}
public static Date convertLocalDateToDate(LocalDate localDate) {
private static Date convertLocalDateToDate(LocalDate localDate) {
return createDate(localDate.getYear(), localDate.getMonthValue(), localDate.getDayOfMonth());
}
@@ -92,14 +93,9 @@ public final class DateUtils {
return LocalDate.now(zone);
}
public static LocalDate getLocalDateOfTenant(final ZoneId zone) {
return LocalDate.now(zone);
}
public static LocalDateTime getLocalDateTimeOfTenant() {
final ZoneId zone = getDateTimeZoneOfTenant();
LocalDateTime today = LocalDateTime.now(zone).truncatedTo(ChronoUnit.SECONDS);
return today;
return LocalDateTime.now(zone).truncatedTo(ChronoUnit.SECONDS);
}
public static Date parseDate(final String stringDate, final String pattern, final ZoneId zoneId) {
@@ -128,7 +124,8 @@ public final class DateUtils {
} catch (final IllegalArgumentException e) {
final List<ApiParameterError> dataValidationErrors = new ArrayList<>();
final ApiParameterError error = ApiParameterError.parameterError("validation.msg.invalid.date.pattern",
"The parameter date (" + stringDate + ") is invalid w.r.t. pattern " + pattern, "date", stringDate, pattern);
"The parameter `date` (value: " + stringDate + ") is invalid w.r.t. pattern `" + pattern + "`", "date", stringDate,
pattern);
dataValidationErrors.add(error);
throw new PlatformApiDataValidationException("validation.msg.validation.errors.exist", "Validation errors exist.",
dataValidationErrors, e);
@@ -142,11 +139,19 @@ public final class DateUtils {
public static String formatToSqlDate(final Date date) {
final DateFormat df = new SimpleDateFormat("yyyy-MM-dd");
df.setTimeZone(getTimeZoneOfTenant());
final String formattedSqlDate = df.format(date);
return formattedSqlDate;
return df.format(date);
}
public static boolean isDateInTheFuture(final LocalDate localDate) {
return localDate.isAfter(getLocalDateOfTenant());
}
public static LocalDate getBusinessLocalDate() {
return ThreadLocalContextUtil.getBusinessDate();
}
public static Date getBusinessDate() {
return Date.from(ThreadLocalContextUtil.getBusinessDate().atStartOfDay(ZoneId.systemDefault()).toInstant());
}
}
@@ -18,6 +18,11 @@
*/
package org.apache.fineract.infrastructure.core.service;
import java.time.LocalDate;
import java.util.HashMap;
import org.apache.fineract.infrastructure.businessdate.domain.BusinessDateType;
import org.apache.fineract.infrastructure.core.domain.ActionContext;
import org.apache.fineract.infrastructure.core.domain.FineractContext;
import org.apache.fineract.infrastructure.core.domain.FineractPlatformTenant;
import org.springframework.util.Assert;
@@ -26,29 +31,25 @@ import org.springframework.util.Assert;
*/
public final class ThreadLocalContextUtil {
private ThreadLocalContextUtil() {
}
public static final String CONTEXT_TENANTS = "tenants";
private static final ThreadLocal<String> contextHolder = new ThreadLocal<>();
private static final ThreadLocal<FineractPlatformTenant> tenantcontext = new ThreadLocal<>();
private static final ThreadLocal<FineractPlatformTenant> tenantContext = new ThreadLocal<>();
private static final ThreadLocal<String> authTokenContext = new ThreadLocal<>();
private static final ThreadLocal<HashMap<BusinessDateType, LocalDate>> businessDateContext = new ThreadLocal<>();
private static final ThreadLocal<ActionContext> actionContext = new ThreadLocal<>();
public static void setTenant(final FineractPlatformTenant tenant) {
Assert.notNull(tenant, "tenant cannot be null");
tenantcontext.set(tenant);
}
private ThreadLocalContextUtil() {}
public static FineractPlatformTenant getTenant() {
return tenantcontext.get();
return tenantContext.get();
}
public static void setTenant(final FineractPlatformTenant tenant) {
tenantContext.set(tenant);
}
public static void clearTenant() {
tenantcontext.remove();
tenantContext.remove();
}
public static String getDataSourceContext() {
@@ -63,12 +64,56 @@ public final class ThreadLocalContextUtil {
contextHolder.remove();
}
public static void setAuthToken(final String authToken) {
authTokenContext.set(authToken);
}
public static String getAuthToken() {
return authTokenContext.get();
}
public static void setAuthToken(final String authToken) {
authTokenContext.set(authToken);
}
// Map is not serializable, but Hashmap is
public static HashMap<BusinessDateType, LocalDate> getBusinessDates() {
Assert.notNull(businessDateContext.get(), "Business dates cannot be null!");
return businessDateContext.get();
}
public static void setBusinessDates(HashMap<BusinessDateType, LocalDate> dates) {
Assert.notNull(dates, "Business dates cannot be null!");
businessDateContext.set(dates);
}
public static LocalDate getBusinessDateByType(BusinessDateType businessDateType) {
Assert.notNull(businessDateType, "Business date type cannot be null!");
LocalDate localDate = getBusinessDates().get(businessDateType);
Assert.notNull(localDate, String.format("Business date with type `%s` is not initialised!", businessDateType));
return localDate;
}
public static LocalDate getBusinessDate() {
BusinessDateType businessDateType = getActionContext().getBusinessDateType();
return getBusinessDateByType(businessDateType);
}
public static ActionContext getActionContext() {
return actionContext.get() == null ? ActionContext.DEFAULT : actionContext.get();
}
public static void setActionContext(ActionContext context) {
Assert.notNull(context, "context cannot be null");
actionContext.set(context);
}
public static FineractContext getContext() {
return new FineractContext(getDataSourceContext(), getTenant(), getAuthToken(), getBusinessDates(), getActionContext());
}
public static void init(final FineractContext fineractContext) {
Assert.notNull(fineractContext, "FineractContext cannot be null during synchronisation!");
setDataSourceContext(fineractContext.getContextHolder());
setTenant(fineractContext.getTenantContext());
setAuthToken(fineractContext.getAuthTokenContext());
setBusinessDates(fineractContext.getBusinessDateContext());
setActionContext(fineractContext.getActionContext());
}
}
@@ -20,6 +20,7 @@ package org.apache.fineract.infrastructure.core.service.database;
import static java.lang.String.format;
import org.apache.fineract.infrastructure.core.service.DateUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;
@@ -87,26 +88,36 @@ public class DatabaseSpecificSQLGenerator {
return format("SELECT COUNT(*) FROM (%s) AS temp", sql);
}
public String currentDate() {
public String currentBusinessDate() {
if (databaseTypeResolver.isMySQL()) {
return "CURDATE()";
return format("DATE('%s')", DateUtils.getBusinessLocalDate().format(DateUtils.DEFAULT_DATE_FORMATER));
} else if (databaseTypeResolver.isPostgreSQL()) {
return "CURRENT_DATE";
return format("DATE '%s'", DateUtils.getBusinessLocalDate().format(DateUtils.DEFAULT_DATE_FORMATER));
} else {
throw new IllegalStateException("Database type is not supported for current date " + databaseTypeResolver.databaseType());
}
}
public String currentDateTime() {
public String currentTenantDate() {
if (databaseTypeResolver.isMySQL()) {
return "CURRENT_TIMESTAMP()";
return format("DATE('%s')", DateUtils.getLocalDateOfTenant().format(DateUtils.DEFAULT_DATE_FORMATER));
} else if (databaseTypeResolver.isPostgreSQL()) {
return "CURRENT_TIMESTAMP";
return format("DATE '%s'", DateUtils.getLocalDateOfTenant().format(DateUtils.DEFAULT_DATE_FORMATER));
} else {
throw new IllegalStateException("Database type is not supported for current date " + databaseTypeResolver.databaseType());
}
}
public String currentTenantDateTime() {
if (databaseTypeResolver.isMySQL()) {
return format("TIMESTAMP('%s')", DateUtils.getLocalDateTimeOfTenant().format(DateUtils.DEFAULT_DATETIME_FORMATER));
} else if (databaseTypeResolver.isPostgreSQL()) {
return format("TIMESTAMP '%s'", DateUtils.getLocalDateTimeOfTenant().format(DateUtils.DEFAULT_DATETIME_FORMATER));
} else {
throw new IllegalStateException("Database type is not supported for current date time" + databaseTypeResolver.databaseType());
}
}
public String subDate(String date, String multiplier, String unit) {
if (databaseTypeResolver.isMySQL()) {
return format("DATE_SUB(%s, INTERVAL %s %s)", date, multiplier, unit);
@@ -79,7 +79,6 @@ import org.slf4j.LoggerFactory;
import org.springframework.dao.DataAccessException;
import org.springframework.dao.DataIntegrityViolationException;
import org.springframework.dao.EmptyResultDataAccessException;
import org.springframework.jdbc.BadSqlGrammarException;
import org.springframework.jdbc.core.JdbcTemplate;
import org.springframework.jdbc.core.namedparam.NamedParameterJdbcTemplate;
import org.springframework.jdbc.support.GeneratedKeyHolder;
@@ -671,29 +670,15 @@ public class ReadWriteNonCoreDataServiceImpl implements ReadWriteNonCoreDataServ
registerDatatable(datatableName, apptableName, entitySubType);
registerColumnCodeMapping(codeMappings);
} catch (final JpaSystemException | DataIntegrityViolationException e) {
} catch (final PersistenceException | DataAccessException e) {
final Throwable realCause = e.getCause();
final List<ApiParameterError> dataValidationErrors = new ArrayList<>();
final DataValidatorBuilder baseDataValidator = new DataValidatorBuilder(dataValidationErrors).resource("datatable");
if (realCause.getMessage().toLowerCase().contains("duplicate column name")) {
baseDataValidator.reset().parameter("name").failWithCode("duplicate.column.name");
} else if (realCause.getMessage().contains("Table") && realCause.getMessage().contains("already exists")) {
baseDataValidator.reset().parameter("datatableName").value(datatableName).failWithCode("datatable.already.exists");
} else if (realCause.getMessage().contains("Column") && realCause.getMessage().contains("big")) {
baseDataValidator.reset().parameter("column").failWithCode("length.too.big");
} else if (realCause.getMessage().contains("Row") && realCause.getMessage().contains("large")) {
baseDataValidator.reset().parameter("row").failWithCode("size.too.large");
}
throwExceptionIfValidationWarningsExist(dataValidationErrors);
} catch (final PersistenceException | BadSqlGrammarException ee) {
Throwable realCause = ExceptionUtils.getRootCause(ee.getCause());
final List<ApiParameterError> dataValidationErrors = new ArrayList<>();
final DataValidatorBuilder baseDataValidator = new DataValidatorBuilder(dataValidationErrors).resource("datatable");
if (realCause.getMessage().toLowerCase().contains("duplicate column name")) {
baseDataValidator.reset().parameter("name").failWithCode("duplicate.column.name");
} else if (realCause.getMessage().contains("Table") && realCause.getMessage().contains("already exists")) {
} else if ((realCause.getMessage().contains("Table") || realCause.getMessage().contains("relation"))
&& realCause.getMessage().contains("already exists")) {
baseDataValidator.reset().parameter("datatableName").value(datatableName).failWithCode("datatable.already.exists");
} else if (realCause.getMessage().contains("Column") && realCause.getMessage().contains("big")) {
baseDataValidator.reset().parameter("column").failWithCode("length.too.big");
@@ -1132,7 +1117,8 @@ public class ReadWriteNonCoreDataServiceImpl implements ReadWriteNonCoreDataServ
final DataValidatorBuilder baseDataValidator = new DataValidatorBuilder(dataValidationErrors).resource("datatable");
if (realCause.getMessage().toLowerCase().contains("duplicate column name")) {
baseDataValidator.reset().parameter("name").failWithCode("duplicate.column.name");
} else if (realCause.getMessage().contains("Table") && realCause.getMessage().contains("already exists")) {
} else if ((realCause.getMessage().contains("Table") || realCause.getMessage().contains("relation"))
&& realCause.getMessage().contains("already exists")) {
baseDataValidator.reset().parameter("datatableName").value(datatableName).failWithCode("datatable.already.exists");
} else if (realCause.getMessage().contains("Column") && realCause.getMessage().contains("big")) {
baseDataValidator.reset().parameter("column").failWithCode("length.too.big");
@@ -1569,7 +1555,7 @@ public class ReadWriteNonCoreDataServiceImpl implements ReadWriteNonCoreDataServ
|| key.equalsIgnoreCase(DataTableApiConstant.UPDATEDAT_FIELD_NAME)) {
columnName = sqlGenerator.escape(key);
insertColumns += ", " + columnName;
selectColumns += "," + sqlGenerator.currentDateTime() + " as " + columnName;
selectColumns += "," + sqlGenerator.currentTenantDateTime() + " as " + columnName;
}
}
}
@@ -1675,7 +1661,7 @@ public class ReadWriteNonCoreDataServiceImpl implements ReadWriteNonCoreDataServ
sql += sqlGenerator.escape(key) + " = " + pValueWrite;
} else {
if (key.equalsIgnoreCase(DataTableApiConstant.UPDATEDAT_FIELD_NAME)) {
sql += ", " + sqlGenerator.escape(key) + " = " + sqlGenerator.currentDateTime();
sql += ", " + sqlGenerator.escape(key) + " = " + sqlGenerator.currentTenantDateTime();
}
}
}
@@ -18,47 +18,21 @@
*/
package org.apache.fineract.infrastructure.hooks.event;
import lombok.Getter;
import org.apache.fineract.infrastructure.core.domain.FineractContext;
import org.apache.fineract.infrastructure.core.domain.FineractEvent;
import org.apache.fineract.useradministration.domain.AppUser;
import org.springframework.context.ApplicationEvent;
public class HookEvent extends ApplicationEvent {
@Getter
public class HookEvent extends FineractEvent {
private final String payload;
private final String tenantIdentifier;
private final AppUser appUser;
private final String authToken;
public HookEvent(final HookEventSource source, final String payload, final String tenantIdentifier, final AppUser appUser,
final String authToken) {
super(source);
public HookEvent(final HookEventSource source, final String payload, final AppUser appUser, FineractContext fineractContext) {
super(source, fineractContext);
this.payload = payload;
this.tenantIdentifier = tenantIdentifier;
this.appUser = appUser;
this.authToken = authToken;
}
public String getPayload() {
return this.payload;
}
@Override
public HookEventSource getSource() {
return (HookEventSource) super.source;
}
public String getTenantIdentifier() {
return this.tenantIdentifier;
}
public AppUser getAppUser() {
return this.appUser;
}
public String getAuthToken() {
return this.authToken;
}
}
@@ -21,7 +21,7 @@ package org.apache.fineract.infrastructure.hooks.listener;
import java.util.List;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.apache.fineract.infrastructure.core.domain.FineractPlatformTenant;
import org.apache.fineract.infrastructure.core.domain.FineractContext;
import org.apache.fineract.infrastructure.core.service.ThreadLocalContextUtil;
import org.apache.fineract.infrastructure.hooks.domain.Hook;
import org.apache.fineract.infrastructure.hooks.event.HookEvent;
@@ -29,7 +29,6 @@ import org.apache.fineract.infrastructure.hooks.event.HookEventSource;
import org.apache.fineract.infrastructure.hooks.processor.HookProcessor;
import org.apache.fineract.infrastructure.hooks.processor.HookProcessorProvider;
import org.apache.fineract.infrastructure.hooks.service.HookReadPlatformService;
import org.apache.fineract.infrastructure.security.service.TenantDetailsService;
import org.apache.fineract.useradministration.domain.AppUser;
import org.springframework.stereotype.Service;
@@ -40,18 +39,15 @@ public class FineractHookListener implements HookListener {
private final HookProcessorProvider hookProcessorProvider;
private final HookReadPlatformService hookReadPlatformService;
private final TenantDetailsService tenantDetailsService;
@Override
public void onApplicationEvent(final HookEvent event) {
final String tenantIdentifier = event.getTenantIdentifier();
final FineractPlatformTenant tenant = this.tenantDetailsService.loadTenantById(tenantIdentifier);
ThreadLocalContextUtil.setTenant(tenant);
ThreadLocalContextUtil.init(event.getContext());
final AppUser appUser = event.getAppUser();
final String authToken = event.getAuthToken();
final HookEventSource hookEventSource = event.getSource();
final HookEventSource hookEventSource = (HookEventSource) event.getSource();
final FineractContext fineractContext = event.getContext();
final String entityName = hookEventSource.getEntityName();
final String actionName = hookEventSource.getActionName();
final String payload = event.getPayload();
@@ -62,10 +58,11 @@ public class FineractHookListener implements HookListener {
for (final Hook hook : hooks) {
final HookProcessor processor = this.hookProcessorProvider.getProcessor(hook);
try {
processor.process(hook, appUser, payload, entityName, actionName, tenantIdentifier, authToken);
processor.process(hook, payload, entityName, actionName, fineractContext);
} catch (Throwable e) {
log.error("Hook {} failed in HookProcessor {} for tenantIdentifier/user {}/{}, entityName: {}, actionName: {}, payload {} ",
hook.getId(), processor.getClass().getSimpleName(), tenantIdentifier, appUser, entityName, actionName, payload, e);
hook.getId(), processor.getClass().getSimpleName(), fineractContext.getTenantContext().getTenantIdentifier(),
appUser.getDisplayName(), entityName, actionName, payload, e);
}
}
}
@@ -27,9 +27,9 @@ import java.util.HashMap;
import java.util.Map;
import java.util.Set;
import lombok.RequiredArgsConstructor;
import org.apache.fineract.infrastructure.core.domain.FineractContext;
import org.apache.fineract.infrastructure.hooks.domain.Hook;
import org.apache.fineract.infrastructure.hooks.domain.HookConfiguration;
import org.apache.fineract.useradministration.domain.AppUser;
import org.springframework.stereotype.Service;
import retrofit2.Callback;
@@ -40,8 +40,8 @@ public class ElasticSearchHookProcessor implements HookProcessor {
private final ProcessorHelper processorHelper;
@Override
public void process(final Hook hook, @SuppressWarnings("unused") final AppUser appUser, final String payload, final String entityName,
final String actionName, final String tenantIdentifier, final String authToken) {
public void process(final Hook hook, final String payload, final String entityName, final String actionName,
final FineractContext context) {
final Set<HookConfiguration> config = hook.getHookConfig();
@@ -58,13 +58,13 @@ public class ElasticSearchHookProcessor implements HookProcessor {
}
}
sendRequest(url, contentType, payload, entityName, actionName, tenantIdentifier, authToken);
sendRequest(url, contentType, payload, entityName, actionName, context);
}
@SuppressWarnings("unchecked")
private void sendRequest(final String url, final String contentType, final String payload, final String entityName,
final String actionName, final String tenantIdentifier, @SuppressWarnings("unused") final String authToken) {
final String actionName, final FineractContext context) {
final String fineractEndpointUrl = System.getProperty("baseUrl");
final WebHookService service = processorHelper.createWebHookService(url);
@@ -74,11 +74,13 @@ public class ElasticSearchHookProcessor implements HookProcessor {
if (contentType.equalsIgnoreCase("json") || contentType.contains("json")) {
final JsonObject json = new Gson().fromJson(payload, JsonObject.class);
service.sendJsonRequest(entityName, actionName, tenantIdentifier, fineractEndpointUrl, json).enqueue(callback);
service.sendJsonRequest(entityName, actionName, context.getTenantContext().getTenantIdentifier(), fineractEndpointUrl, json)
.enqueue(callback);
} else {
Map<String, String> map = new HashMap<>();
map = new Gson().fromJson(payload, map.getClass());
service.sendFormRequest(entityName, actionName, tenantIdentifier, fineractEndpointUrl, map).enqueue(callback);
service.sendFormRequest(entityName, actionName, context.getTenantContext().getTenantIdentifier(), fineractEndpointUrl, map)
.enqueue(callback);
}
}
}
@@ -18,12 +18,11 @@
*/
package org.apache.fineract.infrastructure.hooks.processor;
import org.apache.fineract.infrastructure.core.domain.FineractContext;
import org.apache.fineract.infrastructure.hooks.domain.Hook;
import org.apache.fineract.useradministration.domain.AppUser;
public interface HookProcessor {
void process(Hook hook, AppUser appUser, String payload, String entityName, String actionName, String tenantIdentifier,
String authToken) throws Exception;
void process(Hook hook, String payload, String entityName, String actionName, FineractContext context) throws Exception;
}
@@ -30,6 +30,7 @@ import java.util.Map;
import java.util.Set;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.apache.fineract.infrastructure.core.domain.FineractContext;
import org.apache.fineract.infrastructure.core.exception.GeneralPlatformDomainRuleException;
import org.apache.fineract.infrastructure.hooks.domain.Hook;
import org.apache.fineract.infrastructure.hooks.domain.HookConfiguration;
@@ -41,7 +42,6 @@ import org.apache.fineract.portfolio.client.domain.ClientRepositoryWrapper;
import org.apache.fineract.template.domain.Template;
import org.apache.fineract.template.domain.TemplateRepository;
import org.apache.fineract.template.service.TemplateMergeService;
import org.apache.fineract.useradministration.domain.AppUser;
import org.springframework.stereotype.Service;
@Service
@@ -57,8 +57,8 @@ public class MessageGatewayHookProcessor implements HookProcessor {
private final SmsMessageScheduledJobService smsMessageScheduledJobService;
@Override
public void process(final Hook hook, @SuppressWarnings("unused") final AppUser appUser, final String payload, final String entityName,
final String actionName, final String tenantIdentifier, final String authToken) throws IOException {
public void process(final Hook hook, final String payload, final String entityName, final String actionName,
final FineractContext context) throws IOException {
final Set<HookConfiguration> config = hook.getHookConfig();
@@ -89,7 +89,9 @@ public class MessageGatewayHookProcessor implements HookProcessor {
// 2.1 : get customer details for basic template mapping
// 2.2 : cook up scope map
Type type = new TypeToken<Map<String, String>>() {}.getType();
Type type = new TypeToken<Map<String, String>>() {
}.getType();
Map<String, Object> reqMap = new Gson().fromJson(payload, type);
if (reqMap.get("clientId") != null) {
Long clientId = (Long) reqMap.get("clientId");
@@ -30,6 +30,7 @@ import java.io.IOException;
import java.util.HashMap;
import java.util.Map;
import lombok.RequiredArgsConstructor;
import org.apache.fineract.infrastructure.core.domain.FineractContext;
import org.apache.fineract.infrastructure.hooks.domain.Hook;
import org.apache.fineract.infrastructure.hooks.domain.HookConfiguration;
import org.apache.fineract.infrastructure.hooks.domain.HookConfigurationRepository;
@@ -37,7 +38,6 @@ import org.apache.fineract.infrastructure.hooks.processor.data.SmsProviderData;
import org.apache.fineract.portfolio.client.domain.Client;
import org.apache.fineract.portfolio.client.domain.ClientRepositoryWrapper;
import org.apache.fineract.template.service.TemplateMergeService;
import org.apache.fineract.useradministration.domain.AppUser;
import org.springframework.stereotype.Service;
import retrofit2.Callback;
@@ -51,17 +51,17 @@ public class TwilioHookProcessor implements HookProcessor {
private final ProcessorHelper processorHelper;
@Override
public void process(final Hook hook, @SuppressWarnings("unused") final AppUser appUser, final String payload, final String entityName,
final String actionName, final String tenantIdentifier, final String authToken) throws IOException {
public void process(final Hook hook, final String payload, final String entityName, final String actionName,
final FineractContext context) throws IOException {
final SmsProviderData smsProviderData = new SmsProviderData(hook.getHookConfig());
sendRequest(smsProviderData, payload, entityName, actionName, tenantIdentifier, authToken, hook);
sendRequest(smsProviderData, payload, entityName, actionName, hook, context);
}
@SuppressWarnings("unchecked")
private void sendRequest(final SmsProviderData smsProviderData, final String payload, String entityName, String actionName,
final String tenantIdentifier, final String authToken, final Hook hook) throws IOException {
final Hook hook, final FineractContext context) throws IOException {
final WebHookService service = processorHelper.createWebHookService(smsProviderData.getUrl());
@@ -72,8 +72,8 @@ public class TwilioHookProcessor implements HookProcessor {
if (apiKey == null) {
smsProviderData.setUrl(null);
smsProviderData.setEndpoint(System.getProperty("baseUrl"));
smsProviderData.setTenantId(tenantIdentifier);
smsProviderData.setMifosToken(authToken);
smsProviderData.setTenantId(context.getTenantContext().getTenantIdentifier());
smsProviderData.setMifosToken(context.getAuthTokenContext());
apiKey = service.sendSmsBridgeConfigRequest(smsProviderData).execute().body();
final HookConfiguration apiKeyEntry = HookConfiguration.createNew(hook, "string", apiKeyName, apiKey);
this.hookConfigurationRepository.save(apiKeyEntry);
@@ -84,14 +84,15 @@ public class TwilioHookProcessor implements HookProcessor {
if (hook.getUgdTemplate() != null) {
entityName = "sms";
actionName = "send";
json = processUgdTemplate(payload, hook, authToken);
json = processUgdTemplate(payload, hook, context.getAuthTokenContext());
if (json == null) {
return;
}
} else {
json = JsonParser.parseString(payload).getAsJsonObject();
}
service.sendSmsBridgeRequest(entityName, actionName, tenantIdentifier, apiKey, json).enqueue(callback);
service.sendSmsBridgeRequest(entityName, actionName, context.getTenantContext().getTenantIdentifier(), apiKey, json)
.enqueue(callback);
}
}
@@ -28,9 +28,9 @@ import java.util.HashMap;
import java.util.Map;
import java.util.Set;
import lombok.RequiredArgsConstructor;
import org.apache.fineract.infrastructure.core.domain.FineractContext;
import org.apache.fineract.infrastructure.hooks.domain.Hook;
import org.apache.fineract.infrastructure.hooks.domain.HookConfiguration;
import org.apache.fineract.useradministration.domain.AppUser;
import org.springframework.stereotype.Service;
import retrofit2.Callback;
@@ -41,8 +41,8 @@ public class WebHookProcessor implements HookProcessor {
private final ProcessorHelper processorHelper;
@Override
public void process(final Hook hook, @SuppressWarnings("unused") final AppUser appUser, final String payload, final String entityName,
final String actionName, final String tenantIdentifier, final String authToken) {
public void process(final Hook hook, final String payload, final String entityName, final String actionName,
final FineractContext context) {
final Set<HookConfiguration> config = hook.getHookConfig();
@@ -59,12 +59,12 @@ public class WebHookProcessor implements HookProcessor {
}
}
sendRequest(url, contentType, payload, entityName, actionName, tenantIdentifier, authToken);
sendRequest(url, contentType, payload, entityName, actionName, context);
}
@SuppressWarnings("unchecked")
private void sendRequest(final String url, final String contentType, final String payload, final String entityName,
final String actionName, final String tenantIdentifier, @SuppressWarnings("unused") final String authToken) {
final String actionName, final FineractContext context) {
final String fineractEndpointUrl = System.getProperty("baseUrl");
final WebHookService service = processorHelper.createWebHookService(url);
@@ -74,11 +74,13 @@ public class WebHookProcessor implements HookProcessor {
if (contentType.equalsIgnoreCase("json") || contentType.contains("json")) {
final JsonObject json = JsonParser.parseString(payload).getAsJsonObject();
service.sendJsonRequest(entityName, actionName, tenantIdentifier, fineractEndpointUrl, json).enqueue(callback);
service.sendJsonRequest(entityName, actionName, context.getTenantContext().getTenantIdentifier(), fineractEndpointUrl, json)
.enqueue(callback);
} else {
Map<String, String> map = new HashMap<>();
map = new Gson().fromJson(payload, map.getClass());
service.sendFormRequest(entityName, actionName, tenantIdentifier, fineractEndpointUrl, map).enqueue(callback);
service.sendFormRequest(entityName, actionName, context.getTenantContext().getTenantIdentifier(), fineractEndpointUrl, map)
.enqueue(callback);
}
}
}
@@ -18,7 +18,12 @@
*/
package org.apache.fineract.infrastructure.jobs.service;
import java.time.LocalDate;
import java.util.Date;
import java.util.HashMap;
import lombok.RequiredArgsConstructor;
import org.apache.fineract.infrastructure.businessdate.domain.BusinessDateType;
import org.apache.fineract.infrastructure.businessdate.service.BusinessDateReadPlatformService;
import org.apache.fineract.infrastructure.core.service.ThreadLocalContextUtil;
import org.apache.fineract.infrastructure.jobs.domain.ScheduledJobDetail;
import org.apache.fineract.infrastructure.jobs.domain.ScheduledJobRunHistory;
@@ -29,7 +34,6 @@ import org.quartz.JobExecutionException;
import org.quartz.JobKey;
import org.quartz.JobListener;
import org.quartz.Trigger;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.security.authentication.UsernamePasswordAuthenticationToken;
import org.springframework.security.core.authority.mapping.GrantedAuthoritiesMapper;
import org.springframework.security.core.authority.mapping.NullAuthoritiesMapper;
@@ -39,26 +43,17 @@ import org.springframework.stereotype.Component;
/**
* Global job Listener class to set Tenant details to {@link ThreadLocalContextUtil} for batch Job and stores the batch
* job status to database after the execution
*
*/
@Component
@RequiredArgsConstructor
public class SchedulerJobListener implements JobListener {
private int stackTraceLevel = 0;
private final String name = SchedulerServiceConstants.DEFAULT_LISTENER_NAME;
private final SchedularWritePlatformService schedularService;
private final AppUserRepositoryWrapper userRepository;
private final GrantedAuthoritiesMapper authoritiesMapper = new NullAuthoritiesMapper();
@Autowired
public SchedulerJobListener(final SchedularWritePlatformService schedularService, final AppUserRepositoryWrapper userRepository) {
this.schedularService = schedularService;
this.userRepository = userRepository;
}
private final BusinessDateReadPlatformService businessDateReadPlatformService;
private int stackTraceLevel = 0;
@Override
public String getName() {
@@ -71,6 +66,8 @@ public class SchedulerJobListener implements JobListener {
UsernamePasswordAuthenticationToken auth = new UsernamePasswordAuthenticationToken(user, user.getPassword(),
authoritiesMapper.mapAuthorities(user.getAuthorities()));
SecurityContextHolder.getContext().setAuthentication(auth);
HashMap<BusinessDateType, LocalDate> businessDates = businessDateReadPlatformService.getBusinessDates();
ThreadLocalContextUtil.setBusinessDates(businessDates);
}
@Override
@@ -20,6 +20,11 @@ package org.apache.fineract.infrastructure.jobs.service;
import edu.umd.cs.findbugs.annotations.SuppressFBWarnings;
import java.security.SecureRandom;
import java.time.LocalDate;
import java.util.HashMap;
import lombok.RequiredArgsConstructor;
import org.apache.fineract.infrastructure.businessdate.domain.BusinessDateType;
import org.apache.fineract.infrastructure.businessdate.service.BusinessDateReadPlatformService;
import org.apache.fineract.infrastructure.core.domain.FineractPlatformTenant;
import org.apache.fineract.infrastructure.core.service.ThreadLocalContextUtil;
import org.apache.fineract.infrastructure.security.service.TenantDetailsService;
@@ -30,10 +35,10 @@ import org.quartz.Trigger.CompletedExecutionInstruction;
import org.quartz.TriggerListener;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;
@Component
@RequiredArgsConstructor
public class SchedulerTriggerListener implements TriggerListener {
private static final Logger LOG = LoggerFactory.getLogger(SchedulerTriggerListener.class);
@@ -42,12 +47,7 @@ public class SchedulerTriggerListener implements TriggerListener {
private final SchedularWritePlatformService schedularService;
private final TenantDetailsService tenantDetailsService;
@Autowired
public SchedulerTriggerListener(final SchedularWritePlatformService schedularService, final TenantDetailsService tenantDetailsService) {
this.schedularService = schedularService;
this.tenantDetailsService = tenantDetailsService;
}
private final BusinessDateReadPlatformService businessDateReadPlatformService;
@Override
public String getName() {
@@ -66,6 +66,8 @@ public class SchedulerTriggerListener implements TriggerListener {
final String tenantIdentifier = trigger.getJobDataMap().getString(SchedulerServiceConstants.TENANT_IDENTIFIER);
final FineractPlatformTenant tenant = this.tenantDetailsService.loadTenantById(tenantIdentifier);
ThreadLocalContextUtil.setTenant(tenant);
HashMap<BusinessDateType, LocalDate> businessDates = businessDateReadPlatformService.getBusinessDates();
ThreadLocalContextUtil.setBusinessDates(businessDates);
final JobKey key = trigger.getJobKey();
final String jobKey = key.getName() + SchedulerServiceConstants.JOB_KEY_SEPERATOR + key.getGroup();
String triggerType = SchedulerServiceConstants.TRIGGER_TYPE_CRON;
@@ -19,11 +19,15 @@
package org.apache.fineract.infrastructure.security.filter;
import java.io.IOException;
import java.time.LocalDate;
import java.util.HashMap;
import javax.servlet.FilterChain;
import javax.servlet.ServletException;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import org.apache.commons.lang3.time.StopWatch;
import org.apache.fineract.infrastructure.businessdate.domain.BusinessDateType;
import org.apache.fineract.infrastructure.businessdate.service.BusinessDateReadPlatformService;
import org.apache.fineract.infrastructure.cache.domain.CacheType;
import org.apache.fineract.infrastructure.cache.service.CacheWritePlatformService;
import org.apache.fineract.infrastructure.configuration.domain.ConfigurationDomainService;
@@ -80,6 +84,9 @@ public class TenantAwareBasicAuthenticationFilter extends BasicAuthenticationFil
@Autowired
private BasicAuthTenantDetailsService basicAuthTenantDetailsService;
@Autowired
private BusinessDateReadPlatformService businessDateReadPlatformService;
private final String tenantRequestHeader = "Fineract-Platform-TenantId";
private final boolean exceptionIfHeaderMissing = true;
@@ -119,8 +126,9 @@ public class TenantAwareBasicAuthenticationFilter extends BasicAuthenticationFil
isReportRequest = true;
}
final FineractPlatformTenant tenant = this.basicAuthTenantDetailsService.loadTenantById(tenantIdentifier, isReportRequest);
ThreadLocalContextUtil.setTenant(tenant);
HashMap<BusinessDateType, LocalDate> businessDates = this.businessDateReadPlatformService.getBusinessDates();
ThreadLocalContextUtil.setBusinessDates(businessDates);
String authToken = request.getHeader("Authorization");
if (authToken != null && authToken.startsWith("Basic ")) {
@@ -19,13 +19,20 @@
package org.apache.fineract.infrastructure.security.filter;
import java.io.IOException;
import java.time.LocalDate;
import java.util.HashMap;
import java.util.concurrent.atomic.AtomicBoolean;
import javax.servlet.FilterChain;
import javax.servlet.ServletException;
import javax.servlet.ServletRequest;
import javax.servlet.ServletResponse;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.time.StopWatch;
import org.apache.fineract.infrastructure.businessdate.domain.BusinessDateType;
import org.apache.fineract.infrastructure.businessdate.service.BusinessDateReadPlatformService;
import org.apache.fineract.infrastructure.cache.domain.CacheType;
import org.apache.fineract.infrastructure.cache.service.CacheWritePlatformService;
import org.apache.fineract.infrastructure.configuration.domain.ConfigurationDomainService;
@@ -35,9 +42,6 @@ import org.apache.fineract.infrastructure.core.service.ThreadLocalContextUtil;
import org.apache.fineract.infrastructure.security.data.PlatformRequestLog;
import org.apache.fineract.infrastructure.security.exception.InvalidTenantIdentiferException;
import org.apache.fineract.infrastructure.security.service.BasicAuthTenantDetailsService;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty;
import org.springframework.security.core.context.SecurityContextHolder;
import org.springframework.stereotype.Service;
@@ -56,30 +60,23 @@ import org.springframework.web.filter.GenericFilterBean;
*/
@Service
@ConditionalOnProperty("fineract.security.oauth.enabled")
@RequiredArgsConstructor
@Slf4j
public class TenantAwareTenantIdentifierFilter extends GenericFilterBean {
private static boolean firstRequestProcessed = false;
private static final Logger LOG = LoggerFactory.getLogger(TenantAwareTenantIdentifierFilter.class);
private static AtomicBoolean firstRequestProcessed = new AtomicBoolean();
private final BasicAuthTenantDetailsService basicAuthTenantDetailsService;
private final ToApiJsonSerializer<PlatformRequestLog> toApiJsonSerializer;
private final ConfigurationDomainService configurationDomainService;
private final CacheWritePlatformService cacheWritePlatformService;
private final BusinessDateReadPlatformService businessDateReadPlatformService;
private final String tenantRequestHeader = "Fineract-Platform-TenantId";
private final boolean exceptionIfHeaderMissing = true;
private final String apiUri = "/api/v1/";
@Autowired
public TenantAwareTenantIdentifierFilter(final BasicAuthTenantDetailsService basicAuthTenantDetailsService,
final ToApiJsonSerializer<PlatformRequestLog> toApiJsonSerializer, final ConfigurationDomainService configurationDomainService,
final CacheWritePlatformService cacheWritePlatformService) {
this.basicAuthTenantDetailsService = basicAuthTenantDetailsService;
this.toApiJsonSerializer = toApiJsonSerializer;
this.configurationDomainService = configurationDomainService;
this.cacheWritePlatformService = cacheWritePlatformService;
}
@Override
public void doFilter(final ServletRequest req, final ServletResponse res, final FilterChain chain)
throws IOException, ServletException {
@@ -120,15 +117,16 @@ public class TenantAwareTenantIdentifierFilter extends GenericFilterBean {
isReportRequest = true;
}
final FineractPlatformTenant tenant = this.basicAuthTenantDetailsService.loadTenantById(tenantIdentifier, isReportRequest);
ThreadLocalContextUtil.setTenant(tenant);
HashMap<BusinessDateType, LocalDate> businessDates = this.businessDateReadPlatformService.getBusinessDates();
ThreadLocalContextUtil.setBusinessDates(businessDates);
String authToken = request.getHeader("Authorization");
if (authToken != null && authToken.startsWith("bearer ")) {
ThreadLocalContextUtil.setAuthToken(authToken.replaceFirst("bearer ", ""));
}
if (!firstRequestProcessed) {
if (!firstRequestProcessed.get()) {
final String baseUrl = request.getRequestURL().toString().replace(request.getRequestURI(),
request.getContextPath() + apiUri);
System.setProperty("baseUrl", baseUrl);
@@ -139,7 +137,7 @@ public class TenantAwareTenantIdentifierFilter extends GenericFilterBean {
} else {
this.cacheWritePlatformService.switchToCache(CacheType.NO_CACHE);
}
TenantAwareTenantIdentifierFilter.firstRequestProcessed = true;
firstRequestProcessed.set(true);
}
chain.doFilter(request, response);
}
@@ -151,8 +149,8 @@ public class TenantAwareTenantIdentifierFilter extends GenericFilterBean {
response.sendError(HttpServletResponse.SC_BAD_REQUEST, e.getMessage());
} finally {
task.stop();
final PlatformRequestLog log = PlatformRequestLog.from(task, request);
LOG.info("{}", this.toApiJsonSerializer.serialize(log));
final PlatformRequestLog logRequest = PlatformRequestLog.from(task, request);
log.info("{}", this.toApiJsonSerializer.serialize(logRequest));
}
}
@@ -18,8 +18,6 @@
*/
package org.apache.fineract.infrastructure.sms.domain;
import java.time.LocalDate;
import java.time.ZoneId;
import java.util.Date;
import java.util.LinkedHashMap;
import java.util.Map;
@@ -122,8 +120,7 @@ public class SmsMessage extends AbstractPersistableCustom {
this.mobileNo = mobileNo;
this.message = message;
this.smsCampaign = smsCampaign;
this.submittedOnDate = Date
.from(LocalDate.now(DateUtils.getDateTimeZoneOfTenant()).atStartOfDay(ZoneId.systemDefault()).toInstant());
this.submittedOnDate = DateUtils.getBusinessDate();
this.isNotification = isNotification;
}
@@ -28,11 +28,12 @@ import java.util.Map;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import javax.annotation.PostConstruct;
import lombok.extern.slf4j.Slf4j;
import org.apache.fineract.infrastructure.campaigns.helper.SmsConfigUtils;
import org.apache.fineract.infrastructure.campaigns.sms.constants.SmsCampaignConstants;
import org.apache.fineract.infrastructure.campaigns.sms.domain.SmsCampaign;
import org.apache.fineract.infrastructure.campaigns.sms.exception.ConnectionFailureException;
import org.apache.fineract.infrastructure.core.domain.FineractPlatformTenant;
import org.apache.fineract.infrastructure.core.domain.FineractContext;
import org.apache.fineract.infrastructure.core.service.Page;
import org.apache.fineract.infrastructure.core.service.ThreadLocalContextUtil;
import org.apache.fineract.infrastructure.gcm.service.NotificationSenderService;
@@ -44,8 +45,6 @@ import org.apache.fineract.infrastructure.sms.domain.SmsMessage;
import org.apache.fineract.infrastructure.sms.domain.SmsMessageRepository;
import org.apache.fineract.infrastructure.sms.domain.SmsMessageStatusType;
import org.apache.fineract.infrastructure.sms.service.SmsReadPlatformService;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.ApplicationListener;
import org.springframework.context.event.ContextClosedEvent;
@@ -63,16 +62,16 @@ import org.springframework.web.client.RestTemplate;
* Scheduled job services that send SMS messages and get delivery reports for the sent SMS messages
**/
@Service
@Slf4j
public class SmsMessageScheduledJobServiceImpl implements SmsMessageScheduledJobService {
private final SmsMessageRepository smsMessageRepository;
private final SmsReadPlatformService smsReadPlatformService;
private static final Logger LOG = LoggerFactory.getLogger(SmsMessageScheduledJobServiceImpl.class);
private final RestTemplate restTemplate = new RestTemplate();
private ExecutorService genericExecutorService;
private ExecutorService triggeredExecutorService;
private final SmsConfigUtils smsConfigUtils;
private final NotificationSenderService notificationSenderService;
private ExecutorService genericExecutorService;
private ExecutorService triggeredExecutorService;
/**
* SmsMessageScheduledJobServiceImpl constructor
@@ -131,7 +130,7 @@ public class SmsMessageScheduledJobServiceImpl implements SmsMessageScheduledJob
if (toSaveMessages.size() > 0) {
this.smsMessageRepository.saveAll(toSaveMessages);
this.smsMessageRepository.flush();
this.genericExecutorService.execute(new SmsTask(ThreadLocalContextUtil.getTenant(), apiQueueResourceDatas));
this.genericExecutorService.execute(new SmsTask(apiQueueResourceDatas, ThreadLocalContextUtil.getContext()));
}
if (!toSendNotificationMessages.isEmpty()) {
this.notificationSenderService.sendNotification(toSendNotificationMessages);
@@ -147,40 +146,18 @@ public class SmsMessageScheduledJobServiceImpl implements SmsMessageScheduledJob
} while (page < totalRecords);
}
class SmsTask implements Runnable, ApplicationListener<ContextClosedEvent> {
private final FineractPlatformTenant tenant;
private final Collection<SmsMessageApiQueueResourceData> apiQueueResourceDatas;
SmsTask(final FineractPlatformTenant tenant, final Collection<SmsMessageApiQueueResourceData> apiQueueResourceDatas) {
this.tenant = tenant;
this.apiQueueResourceDatas = apiQueueResourceDatas;
}
@Override
public void run() {
ThreadLocalContextUtil.setTenant(tenant);
connectAndSendToIntermediateServer(apiQueueResourceDatas);
}
@Override
public void onApplicationEvent(ContextClosedEvent event) {
genericExecutorService.shutdown();
LOG.info("Shutting down the ExecutorService");
}
}
private void connectAndSendToIntermediateServer(Collection<SmsMessageApiQueueResourceData> apiQueueResourceDatas) {
Map<String, Object> hostConfig = this.smsConfigUtils.getMessageGateWayRequestURI("sms",
SmsMessageApiQueueResourceData.toJsonString(apiQueueResourceDatas));
URI uri = (URI) hostConfig.get("uri");
HttpEntity<?> entity = (HttpEntity<?>) hostConfig.get("entity");
ResponseEntity<String> responseOne = restTemplate.exchange(uri, HttpMethod.POST, entity,
new ParameterizedTypeReference<String>() {});
ResponseEntity<String> responseOne = restTemplate.exchange(uri, HttpMethod.POST, entity, new ParameterizedTypeReference<String>() {
});
if (responseOne != null) {
// String smsResponse = responseOne.getBody();
if (!responseOne.getStatusCode().equals(HttpStatus.ACCEPTED)) {
LOG.debug("{}", responseOne.getStatusCode().name());
log.debug("{}", responseOne.getStatusCode().name());
throw new ConnectionFailureException(SmsCampaignConstants.SMS);
}
}
@@ -213,7 +190,7 @@ public class SmsMessageScheduledJobServiceImpl implements SmsMessageScheduledJob
if (toSaveMessages.size() > 0) {
this.smsMessageRepository.saveAll(toSaveMessages);
this.smsMessageRepository.flush();
this.triggeredExecutorService.execute(new SmsTask(ThreadLocalContextUtil.getTenant(), apiQueueResourceDatas));
this.triggeredExecutorService.execute(new SmsTask(apiQueueResourceDatas, ThreadLocalContextUtil.getContext()));
}
if (!toSendNotificationMessages.isEmpty()) {
this.notificationSenderService.sendNotification(toSendNotificationMessages);
@@ -222,7 +199,7 @@ public class SmsMessageScheduledJobServiceImpl implements SmsMessageScheduledJob
}
}
} catch (Exception e) {
LOG.error("Error occured.", e);
log.error("Error occured.", e);
}
}
@@ -239,10 +216,10 @@ public class SmsMessageScheduledJobServiceImpl implements SmsMessageScheduledJob
}
this.smsMessageRepository.saveAll(smsMessages);
request.append(SmsMessageApiQueueResourceData.toJsonString(apiQueueResourceDatas));
LOG.info("Sending triggered SMS to specific provider with request - {}", request);
this.triggeredExecutorService.execute(new SmsTask(ThreadLocalContextUtil.getTenant(), apiQueueResourceDatas));
log.info("Sending triggered SMS to specific provider with request - {}", request);
this.triggeredExecutorService.execute(new SmsTask(apiQueueResourceDatas, ThreadLocalContextUtil.getContext()));
} catch (Exception e) {
LOG.error("Error occured.", e);
log.error("Error occured.", e);
}
}
@@ -268,7 +245,9 @@ public class SmsMessageScheduledJobServiceImpl implements SmsMessageScheduledJob
URI uri = (URI) hostConfig.get("uri");
HttpEntity<?> entity = (HttpEntity<?>) hostConfig.get("entity");
ResponseEntity<Collection<SmsMessageDeliveryReportData>> responseOne = restTemplate.exchange(uri, HttpMethod.POST,
entity, new ParameterizedTypeReference<Collection<SmsMessageDeliveryReportData>>() {});
entity, new ParameterizedTypeReference<Collection<SmsMessageDeliveryReportData>>() {
});
Collection<SmsMessageDeliveryReportData> smsMessageDeliveryReportDatas = responseOne.getBody();
Iterator<SmsMessageDeliveryReportData> responseReportIterator = smsMessageDeliveryReportDatas.iterator();
@@ -315,23 +294,44 @@ public class SmsMessageScheduledJobServiceImpl implements SmsMessageScheduledJob
this.smsMessageRepository.save(smsMessage);
if (statusChanged) {
LOG.info("Status of SMS message id: {} successfully changed to {}", smsMessage.getId(), statusType);
log.info("Status of SMS message id: {} successfully changed to {}", smsMessage.getId(), statusType);
}
}
}
if (smsMessageDeliveryReportDatas.size() > 0) {
LOG.info("{} delivery report(s) successfully received from the intermediate gateway - sms",
log.info("{} delivery report(s) successfully received from the intermediate gateway - sms",
smsMessageDeliveryReportDatas.size());
}
}
}
catch (Exception e) {
LOG.error("Error occured.", e);
} catch (Exception e) {
log.error("Error occured.", e);
}
page++;
totalRecords = smsMessageInternalIds.getTotalFilteredRecords();
} while (page < totalRecords);
}
class SmsTask implements Runnable, ApplicationListener<ContextClosedEvent> {
private final FineractContext context;
private final Collection<SmsMessageApiQueueResourceData> apiQueueResourceDatas;
SmsTask(final Collection<SmsMessageApiQueueResourceData> apiQueueResourceDatas, final FineractContext context) {
this.context = context;
this.apiQueueResourceDatas = apiQueueResourceDatas;
}
@Override
public void run() {
ThreadLocalContextUtil.init(context);
connectAndSendToIntermediateServer(apiQueueResourceDatas);
}
@Override
public void onApplicationEvent(ContextClosedEvent event) {
genericExecutorService.shutdown();
log.info("Shutting down the ExecutorService");
}
}
}
@@ -380,7 +380,7 @@ public class InteropServiceImpl implements InteropService {
public InteropTransferResponseData prepareTransfer(@NotNull JsonCommand command) {
InteropTransferRequestData request = dataValidator.validateAndParseTransferRequest(command);
String transferCode = request.getTransferCode();
LocalDateTime transactionDate = DateUtils.getLocalDateTimeOfTenant();
LocalDate transactionDate = DateUtils.getBusinessLocalDate();
// TODO validate request fee/comission and account quote amount
// matching, at CREATE it is debited anyway
@@ -401,12 +401,11 @@ public class InteropServiceImpl implements InteropService {
PaymentDetail paymentDetail = instance(findPaymentType(), savingsAccount.getExternalId(), null, getRoutingCode(), transferCode,
null);
SavingsAccountTransaction holdTransaction = SavingsAccountTransaction.holdAmount(savingsAccount, savingsAccount.office(),
paymentDetail, transactionDate.toLocalDate(), Money.of(savingsAccount.getCurrency(), total), new Date(), getLoginUser(),
false);
paymentDetail, transactionDate, Money.of(savingsAccount.getCurrency(), total), new Date(), getLoginUser(), false);
MonetaryCurrency accountCurrency = savingsAccount.getCurrency().copy();
holdTransaction.updateRunningBalance(
Money.of(accountCurrency, savingsAccount.getWithdrawableBalance().subtract(holdTransaction.getAmount())));
holdTransaction.updateCumulativeBalanceAndDates(accountCurrency, transactionDate.toLocalDate());
holdTransaction.updateCumulativeBalanceAndDates(accountCurrency, transactionDate);
savingsAccount.holdAmount(total);
savingsAccount.addTransaction(holdTransaction);
@@ -415,7 +414,7 @@ public class InteropServiceImpl implements InteropService {
}
return InteropTransferResponseData.build(command.commandId(), request.getTransactionCode(), InteropActionState.ACCEPTED,
request.getExpiration(), request.getExtensionList(), transferCode, transactionDate);
request.getExpiration(), request.getExtensionList(), transferCode, DateUtils.getLocalDateTimeOfTenant());
}
@Override
@@ -432,7 +431,7 @@ public class InteropServiceImpl implements InteropService {
}
LocalDateTime transactionDateTime = DateUtils.getLocalDateTimeOfTenant();
LocalDate transactionDate = transactionDateTime.toLocalDate();
LocalDate transactionDate = DateUtils.getBusinessLocalDate();
DateTimeFormatter fmt = getDateTimeFormatter(command);
SavingsAccountTransaction transaction;
final boolean backdatedTxnsAllowedTill = false;
@@ -489,15 +488,15 @@ public class InteropServiceImpl implements InteropService {
SavingsAccount savingsAccount = validateAndGetSavingAccount(request);
LocalDateTime transactionDateTime = DateUtils.getLocalDateTimeOfTenant();
LocalDate transactionDate = DateUtils.getBusinessLocalDate();
SavingsAccountTransaction holdTransaction = findTransaction(savingsAccount, request.getTransferCode(), AMOUNT_HOLD.getValue());
if (holdTransaction != null && holdTransaction.getReleaseIdOfHoldAmountTransaction() == null) {
SavingsAccountTransaction releaseTransaction = releaseAmount(holdTransaction, transactionDateTime.toLocalDate(), new Date(),
getLoginUser());
SavingsAccountTransaction releaseTransaction = releaseAmount(holdTransaction, transactionDate, new Date(), getLoginUser());
MonetaryCurrency accountCurrency = savingsAccount.getCurrency().copy();
releaseTransaction.updateRunningBalance(
Money.of(accountCurrency, savingsAccount.getWithdrawableBalance().add(holdTransaction.getAmount())));
releaseTransaction.updateCumulativeBalanceAndDates(accountCurrency, transactionDateTime.toLocalDate());
releaseTransaction.updateCumulativeBalanceAndDates(accountCurrency, transactionDate);
releaseTransaction = savingsAccountTransactionRepository.saveAndFlush(releaseTransaction);
holdTransaction.updateReleaseId(releaseTransaction.getId());
@@ -536,8 +535,6 @@ public class InteropServiceImpl implements InteropService {
Loan loan = validateAndGetLoan(accountId);
Long loanId = loan.getId();
LocalDateTime disbursedOnDate = DateUtils.getLocalDateTimeOfTenant();
final CommandWrapperBuilder builder = new CommandWrapperBuilder().withJson(apiRequestBodyAsJson);
final CommandWrapper commandRequest = builder.disburseLoanApplication(loanId).build();
@@ -18,16 +18,17 @@
*/
package org.apache.fineract.notification.eventandlistener;
import org.apache.fineract.infrastructure.core.domain.FineractContext;
import org.apache.fineract.infrastructure.core.domain.FineractEvent;
import org.apache.fineract.notification.data.NotificationData;
import org.springframework.context.ApplicationEvent;
@SuppressWarnings("serial")
public class SpringEvent extends ApplicationEvent {
public class NotificationEvent extends FineractEvent {
private NotificationData notificationData;
public SpringEvent(Object source, NotificationData notificationData) {
super(source);
public NotificationEvent(Object source, NotificationData notificationData, FineractContext context) {
super(source, context);
this.notificationData = notificationData;
}
@@ -23,9 +23,6 @@ import java.util.List;
import java.util.Objects;
import java.util.Set;
import lombok.RequiredArgsConstructor;
import org.apache.fineract.infrastructure.core.domain.FineractPlatformTenant;
import org.apache.fineract.infrastructure.core.service.ThreadLocalContextUtil;
import org.apache.fineract.infrastructure.security.service.BasicAuthTenantDetailsService;
import org.apache.fineract.notification.data.NotificationData;
import org.apache.fineract.notification.service.NotificationWritePlatformService;
import org.apache.fineract.useradministration.domain.AppUser;
@@ -36,15 +33,10 @@ import org.springframework.stereotype.Service;
@RequiredArgsConstructor
public class NotificationEventListener {
private final BasicAuthTenantDetailsService basicAuthTenantDetailsService;
private final NotificationWritePlatformService notificationWritePlatformService;
private final AppUserRepository appUserRepository;
public void receive(NotificationData notificationData) {
final FineractPlatformTenant tenant = this.basicAuthTenantDetailsService.loadTenantById(notificationData.getTenantIdentifier(),
false);
ThreadLocalContextUtil.setTenant(tenant);
Long appUserId = notificationData.getActorId();
Set<Long> userIds = notificationData.getUserIds();
@@ -20,6 +20,7 @@ package org.apache.fineract.notification.eventandlistener;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.apache.fineract.infrastructure.core.service.ThreadLocalContextUtil;
import org.apache.fineract.notification.data.NotificationData;
import org.springframework.context.ApplicationListener;
import org.springframework.context.annotation.Profile;
@@ -29,13 +30,14 @@ import org.springframework.stereotype.Component;
@Profile("!activeMqEnabled")
@RequiredArgsConstructor
@Slf4j
public class SpringNotificationEventListener implements ApplicationListener<SpringEvent> {
public class SpringNotificationEventListener implements ApplicationListener<NotificationEvent> {
private final NotificationEventListener notificationEventListener;
@Override
public void onApplicationEvent(SpringEvent event) {
public void onApplicationEvent(NotificationEvent event) {
log.debug("Processing Spring notification event {}", event);
ThreadLocalContextUtil.init(event.getContext());
NotificationData notificationData = event.getNotificationData();
notificationEventListener.receive(notificationData);
}
@@ -20,6 +20,7 @@ package org.apache.fineract.notification.eventandlistener;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.apache.fineract.infrastructure.core.service.ThreadLocalContextUtil;
import org.apache.fineract.notification.data.NotificationData;
import org.springframework.context.ApplicationEventPublisher;
import org.springframework.context.annotation.Profile;
@@ -36,7 +37,8 @@ public class SpringNotificationEventPublisher implements NotificationEventPublis
@Override
public void broadcastNotification(final NotificationData notificationData) {
log.debug("Sending Spring notification event: {}", notificationData);
SpringEvent event = new SpringEvent(this, notificationData);
NotificationEvent event = new NotificationEvent(SpringNotificationEventPublisher.class, notificationData,
ThreadLocalContextUtil.getContext());
applicationEventPublisher.publishEvent(event);
}
}
@@ -161,7 +161,7 @@ public class AccountTransfersReadPlatformServiceImpl implements AccountTransfers
}
// defaults
final LocalDate transferDate = DateUtils.getLocalDateOfTenant();
final LocalDate transferDate = DateUtils.getBusinessLocalDate();
Collection<OfficeData> toOfficeOptions = fromOfficeOptions;
Collection<ClientData> toClientOptions = null;
@@ -516,7 +516,7 @@ public class AccountTransfersReadPlatformServiceImpl implements AccountTransfers
}
// defaults
final LocalDate transferDate = DateUtils.getLocalDateOfTenant();
final LocalDate transferDate = DateUtils.getBusinessLocalDate();
Collection<OfficeData> toOfficeOptions = fromOfficeOptions;
Collection<ClientData> toClientOptions = null;
@@ -294,10 +294,14 @@ public class PortfolioAccountReadPlatformServiceImpl implements PortfolioAccount
private static final class PortfolioLoanAccountRefundByTransferMapper implements RowMapper<PortfolioAccountData> {
private final String schemaSql;
private String schemaSql;
private final DatabaseSpecificSQLGenerator sqlGenerator;
PortfolioLoanAccountRefundByTransferMapper(DatabaseSpecificSQLGenerator sqlGenerator) {
this.sqlGenerator = sqlGenerator;
}
public String schema() {
final StringBuilder amountQueryString = new StringBuilder(400);
amountQueryString.append("(select (SUM(COALESCE(mr.principal_completed_derived, 0)) +");
amountQueryString.append("SUM(COALESCE(mr.interest_completed_derived, 0)) + ");
@@ -305,7 +309,7 @@ public class PortfolioAccountReadPlatformServiceImpl implements PortfolioAccount
amountQueryString.append(" SUM(COALESCE(mr.penalty_charges_completed_derived, 0))) as total_in_advance_derived");
amountQueryString.append(" from m_loan ml INNER JOIN m_loan_repayment_schedule mr on mr.loan_id = ml.id");
amountQueryString.append(" where ml.id=? and ml.loan_status_id = 300");
amountQueryString.append(" and mr.duedate >= " + sqlGenerator.currentDate() + " group by ml.id having");
amountQueryString.append(" and mr.duedate >= " + sqlGenerator.currentBusinessDate() + " group by ml.id having");
amountQueryString.append(" (SUM(COALESCE(mr.principal_completed_derived, 0)) + ");
amountQueryString.append(" SUM(COALESCE(mr.interest_completed_derived, 0)) + ");
amountQueryString.append("SUM(COALESCE(mr.fee_charges_completed_derived, 0)) + ");
@@ -331,9 +335,7 @@ public class PortfolioAccountReadPlatformServiceImpl implements PortfolioAccount
sqlBuilder.append("left join m_staff s ON s.id = la.loan_officer_id ");
this.schemaSql = sqlBuilder.toString();
}
public String schema() {
return this.schemaSql;
}
@@ -186,7 +186,7 @@ public class StandingInstructionReadPlatformServiceImpl implements StandingInstr
}
// defaults
final LocalDate transferDate = DateUtils.getLocalDateOfTenant();
final LocalDate transferDate = DateUtils.getBusinessLocalDate();
Collection<OfficeData> toOfficeOptions = fromOfficeOptions;
Collection<ClientData> toClientOptions = null;
@@ -334,12 +334,13 @@ public class StandingInstructionReadPlatformServiceImpl implements StandingInstr
@Override
public Collection<StandingInstructionData> retrieveAll(final Integer status) {
final StringBuilder sqlBuilder = new StringBuilder(200);
String businessDate = sqlGenerator.currentBusinessDate();
sqlBuilder.append("select ");
sqlBuilder.append(this.standingInstructionMapper.schema());
sqlBuilder
.append(" where atsi.status=? and " + sqlGenerator.currentDate() + " >= atsi.valid_from and (atsi.valid_till IS NULL or "
+ sqlGenerator.currentDate() + " < atsi.valid_till) ")
.append(" and (atsi.last_run_date <> " + sqlGenerator.currentDate() + " or atsi.last_run_date IS NULL)")
.append(" where atsi.status=? and " + businessDate + " >= atsi.valid_from and (atsi.valid_till IS NULL or " + businessDate
+ " < atsi.valid_till) ")
.append(" and (atsi.last_run_date <> " + businessDate + " or atsi.last_run_date IS NULL)")
.append(" ORDER BY atsi.priority DESC");
return this.jdbcTemplate.query(sqlBuilder.toString(), this.standingInstructionMapper, status);
}
@@ -359,7 +360,7 @@ public class StandingInstructionReadPlatformServiceImpl implements StandingInstr
@Override
public StandingInstructionDuesData retriveLoanDuesData(final Long loanId) {
final StandingInstructionLoanDuesMapper rm = new StandingInstructionLoanDuesMapper();
final String sql = "select " + rm.schema() + " where ml.id= ? and ls.duedate <= " + sqlGenerator.currentDate()
final String sql = "select " + rm.schema() + " where ml.id= ? and ls.duedate <= " + sqlGenerator.currentBusinessDate()
+ " and ls.completed_derived <> 1";
return this.jdbcTemplate.queryForObject(sql, rm, new Object[] { loanId }); // NOSONAR
}
@@ -199,7 +199,7 @@ public class StandingInstructionWritePlatformServiceImpl implements StandingInst
Collection<StandingInstructionData> instructionDatas = this.standingInstructionReadPlatformService
.retrieveAll(StandingInstructionStatus.ACTIVE.getValue());
List<Throwable> errors = new ArrayList<>();
LocalDate transactionDate = DateUtils.getLocalDateOfTenant();
LocalDate transactionDate = DateUtils.getBusinessLocalDate();
for (StandingInstructionData data : instructionDatas) {
boolean isDueForTransfer = false;
AccountTransferRecurrenceType recurrenceType = data.recurrenceType();
@@ -232,7 +232,7 @@ public class StandingInstructionWritePlatformServiceImpl implements StandingInst
transactionAmount = standingInstructionDuesData.totalDueAmount();
}
if (recurrenceType.isDuesRecurrence()) {
isDueForTransfer = LocalDate.now(DateUtils.getDateTimeZoneOfTenant()).equals(standingInstructionDuesData.dueDate());
isDueForTransfer = DateUtils.getBusinessLocalDate().equals(standingInstructionDuesData.dueDate());
}
}
@@ -265,7 +265,7 @@ public class StandingInstructionWritePlatformServiceImpl implements StandingInst
StringBuilder errorLog = new StringBuilder();
StringBuilder updateQuery = new StringBuilder(
"INSERT INTO m_account_transfer_standing_instructions_history (standing_instruction_id, " + sqlGenerator.escape("status")
+ ", amount,execution_time, error_log) VALUES (");
+ ", amount, execution_time, error_log) VALUES (");
try {
this.accountTransfersWritePlatformService.transferFunds(accountTransferDTO);
} catch (final PlatformApiDataValidationException e) {
@@ -294,8 +294,8 @@ public class StandingInstructionWritePlatformServiceImpl implements StandingInst
updateQuery.append("'success'").append(",");
}
updateQuery.append(accountTransferDTO.getTransactionAmount().doubleValue());
updateQuery.append(", now(),");
updateQuery.append("'").append(errorLog.toString()).append("')");
updateQuery.append(", ").append(sqlGenerator.currentTenantDateTime()).append(" ");
updateQuery.append(", '").append(errorLog).append("')");
this.jdbcTemplate.update(updateQuery.toString());
return transferCompleted;
}
@@ -190,7 +190,7 @@ public final class ClientDataValidator {
if (this.fromApiJsonHelper.parameterExists(ClientApiConstants.dateOfBirthParamName, element)) {
final LocalDate dateOfBirth = this.fromApiJsonHelper.extractLocalDateNamed(ClientApiConstants.dateOfBirthParamName, element);
baseDataValidator.reset().parameter(ClientApiConstants.dateOfBirthParamName).value(dateOfBirth).notNull()
.validateDateBefore(DateUtils.getLocalDateOfTenant()).validateDateBefore(submittedOnDate);
.validateDateBefore(DateUtils.getBusinessLocalDate()).validateDateBefore(submittedOnDate);
}
if (this.fromApiJsonHelper.parameterExists(ClientApiConstants.genderIdParamName, element)) {
@@ -497,7 +497,7 @@ public final class ClientDataValidator {
atLeastOneParameterPassedForUpdate = true;
final LocalDate dateOfBirth = this.fromApiJsonHelper.extractLocalDateNamed(ClientApiConstants.dateOfBirthParamName, element);
baseDataValidator.reset().parameter(ClientApiConstants.dateOfBirthParamName).value(dateOfBirth).notNull()
.validateDateBefore(DateUtils.getLocalDateOfTenant()).validateDateBefore(submittedDate);
.validateDateBefore(DateUtils.getBusinessLocalDate()).validateDateBefore(submittedDate);
}
if (this.fromApiJsonHelper.parameterExists(ClientApiConstants.legalFormIdParamName, element)) {
@@ -824,7 +824,7 @@ public final class ClientDataValidator {
final LocalDate undoRejectionDate = this.fromApiJsonHelper.extractLocalDateNamed(ClientApiConstants.reopenedDateParamName, element);
baseDataValidator.reset().parameter(ClientApiConstants.reopenedDateParamName).value(undoRejectionDate).notNull()
.validateDateBeforeOrEqual(DateUtils.getLocalDateOfTenant());
.validateDateBeforeOrEqual(DateUtils.getBusinessLocalDate());
throwExceptionIfValidationWarningsExist(dataValidationErrors);
@@ -850,7 +850,7 @@ public final class ClientDataValidator {
final LocalDate undoWithdrawnDate = this.fromApiJsonHelper.extractLocalDateNamed(ClientApiConstants.reopenedDateParamName, element);
baseDataValidator.reset().parameter(ClientApiConstants.reopenedDateParamName).value(undoWithdrawnDate).notNull()
.validateDateBeforeOrEqual(DateUtils.getLocalDateOfTenant());
.validateDateBeforeOrEqual(DateUtils.getBusinessLocalDate());
throwExceptionIfValidationWarningsExist(dataValidationErrors);
@@ -273,7 +273,7 @@ public final class Client extends AbstractPersistableCustom {
officeJoiningDate = activationDate;
}
LocalDate submittedOnDate = LocalDate.now(DateUtils.getDateTimeZoneOfTenant());
LocalDate submittedOnDate = DateUtils.getBusinessLocalDate();
if (active && submittedOnDate.isAfter(activationDate)) {
submittedOnDate = activationDate;
}
@@ -486,7 +486,7 @@ public final class Client extends AbstractPersistableCustom {
}
private boolean isDateInTheFuture(final LocalDate localDate) {
return localDate.isAfter(DateUtils.getLocalDateOfTenant());
return localDate.isAfter(DateUtils.getBusinessLocalDate());
}
public boolean isRejected() {
@@ -24,7 +24,6 @@ import com.google.gson.JsonElement;
import com.google.gson.reflect.TypeToken;
import java.lang.reflect.Type;
import java.time.LocalDate;
import java.time.LocalDateTime;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.HashSet;
@@ -162,7 +161,7 @@ public final class ClientFamilyMemberCommandFromApiJsonDeserializer {
if (this.fromApiJsonHelper.extractLocalDateNamed("dateOfBirth", element) != null) {
final LocalDate dateOfBirth = this.fromApiJsonHelper.extractLocalDateNamed("dateOfBirth", element);
baseDataValidator.reset().parameter("dateOfBirth").value(dateOfBirth).value(dateOfBirth).notNull()
.validateDateBefore(DateUtils.getLocalDateOfTenant());
.validateDateBefore(DateUtils.getBusinessLocalDate());
}
@@ -229,10 +228,8 @@ public final class ClientFamilyMemberCommandFromApiJsonDeserializer {
}
if (this.fromApiJsonHelper.extractLocalDateNamed("dateOfBirth", element) != null) {
LocalDateTime currentDate = LocalDateTime.now(DateUtils.getDateTimeZoneOfTenant());
final LocalDate dateOfBirth = this.fromApiJsonHelper.extractLocalDateNamed("dateOfBirth", element);
baseDataValidator.reset().parameter("dateOfBirth").value(dateOfBirth).validateDateBefore(currentDate.toLocalDate());
baseDataValidator.reset().parameter("dateOfBirth").value(dateOfBirth).validateDateBefore(DateUtils.getBusinessLocalDate());
}
@@ -207,7 +207,7 @@ public class ClientChargeWritePlatformServiceJpaRepositoryImpl implements Client
try {
final Client client = this.clientRepository.getActiveClientInUserScope(clientId);
final ClientCharge clientCharge = this.clientChargeRepository.findOneWithNotFoundDetection(clientChargeId);
final LocalDate transactionDate = DateUtils.getLocalDateOfTenant();
final LocalDate transactionDate = DateUtils.getBusinessLocalDate();
// Validate business rules for payment
validateWaiverTransaction(client, clientCharge);
@@ -134,7 +134,7 @@ public class CollectionSheetTransactionDataValidator {
final LocalDate transactionDate = this.fromApiJsonHelper.extractLocalDateNamed(CollectionSheetConstants.transactionDateParamName,
element);
baseDataValidator.reset().parameter(CollectionSheetConstants.transactionDateParamName).value(transactionDate).notNull()
.validateDateBeforeOrEqual(DateUtils.getLocalDateOfTenant());
.validateDateBeforeOrEqual(DateUtils.getBusinessLocalDate());
final String note = this.fromApiJsonHelper.extractStringNamed(CollectionSheetConstants.noteParamName, element);
if (StringUtils.isNotBlank(note)) {
@@ -49,6 +49,7 @@ import org.apache.fineract.portfolio.floatingrates.data.FloatingRateDTO;
import org.apache.fineract.portfolio.floatingrates.data.FloatingRatePeriodData;
import org.apache.fineract.useradministration.domain.AppUser;
//TODO: refactor to use AbstractAuditableCustom!
@Entity
@Table(name = "m_floating_rates", uniqueConstraints = { @UniqueConstraint(columnNames = { "name" }, name = "unq_name") })
public class FloatingRate extends AbstractPersistableCustom {
@@ -109,11 +110,9 @@ public class FloatingRate extends AbstractPersistableCustom {
: false;
final boolean isActive = command.parameterExists("isActive") ? command.booleanPrimitiveValueOfParameterNamed("isActive") : true;
final List<FloatingRatePeriod> floatingRatePeriods = getRatePeriods(currentUser, command);
final LocalDate currentDate = DateUtils.getLocalDateOfTenant();
final Date currentDate = DateUtils.getBusinessDate();
return new FloatingRate(name, isBaseLendingRate, isActive, floatingRatePeriods, currentUser, currentUser,
Date.from(currentDate.atStartOfDay(ZoneId.systemDefault()).toInstant()),
Date.from(currentDate.atStartOfDay(ZoneId.systemDefault()).toInstant()));
return new FloatingRate(name, isBaseLendingRate, isActive, floatingRatePeriods, currentUser, currentUser, currentDate, currentDate);
}
private static List<FloatingRatePeriod> getRatePeriods(final AppUser currentUser, final JsonCommand command) {
@@ -132,7 +131,7 @@ public class FloatingRate extends AbstractPersistableCustom {
? ratePeriodObject.get("isDifferentialToBaseLendingRate").getAsBoolean()
: false;
final boolean isActive = true;
final Date currentDate = DateUtils.getDateOfTenant();
final Date currentDate = DateUtils.getBusinessDate();
ratePeriods.add(new FloatingRatePeriod(fromDate, interestRate, isDifferentialToBaseLendingRate, isActive, currentUser,
currentUser, currentDate, currentDate));
}
@@ -204,7 +203,7 @@ public class FloatingRate extends AbstractPersistableCustom {
}
private void updateRatePeriods(final List<FloatingRatePeriod> newRatePeriods, final AppUser appUser) {
final LocalDate today = DateUtils.getLocalDateOfTenant();
final LocalDate today = DateUtils.getBusinessLocalDate();
if (this.floatingRatePeriods != null) {
for (FloatingRatePeriod ratePeriod : this.floatingRatePeriods) {
LocalDate fromDate = LocalDate.ofInstant(ratePeriod.getFromDate().toInstant(), DateUtils.getDateTimeZoneOfTenant());
@@ -34,6 +34,7 @@ import org.apache.fineract.portfolio.floatingrates.data.FloatingRateDTO;
import org.apache.fineract.portfolio.floatingrates.data.FloatingRatePeriodData;
import org.apache.fineract.useradministration.domain.AppUser;
//TODO: refactor to use AbstractAuditableCustom!
@Entity
@Table(name = "m_floating_rates_periods")
public class FloatingRatePeriod extends AbstractPersistableCustom {
@@ -117,7 +117,7 @@ public class FloatingRateDataValidator {
final LocalDate fromDate = this.fromApiJsonHelper.extractLocalDateNamed("fromDate", ratePeriod);
baseDataValidator.reset().parameter("fromDate").parameterAtIndexArray("fromDate", i + 1).value(fromDate).notBlank()
.validateDateAfter(DateUtils.getLocalDateOfTenant().plusDays(1));
.validateDateAfter(DateUtils.getBusinessLocalDate().plusDays(1));
if (fromDate != null) {
fromDates.add(fromDate);
}
@@ -283,7 +283,7 @@ public final class Group extends AbstractPersistableCustom {
}
private boolean isDateInTheFuture(final LocalDate localDate) {
return localDate.isAfter(DateUtils.getLocalDateOfTenant());
return localDate.isAfter(DateUtils.getBusinessLocalDate());
}
public boolean isNotPending() {
@@ -446,7 +446,7 @@ public final class Group extends AbstractPersistableCustom {
public void updateStaff(final Staff staff) {
if (this.isCenter() && this.isActive()) {
LocalDate updatedDate = DateUtils.getLocalDateOfTenant();
LocalDate updatedDate = DateUtils.getBusinessLocalDate();
reassignStaff(staff, updatedDate);
}
this.staff = staff;
@@ -454,7 +454,7 @@ public final class Group extends AbstractPersistableCustom {
public void unassignStaff() {
if (this.isCenter() && this.isActive()) {
LocalDate dateOfStaffUnassigned = DateUtils.getLocalDateOfTenant();
LocalDate dateOfStaffUnassigned = DateUtils.getBusinessLocalDate();
removeStaff(dateOfStaffUnassigned);
}
this.staff = null;
@@ -154,7 +154,7 @@ public class GroupingTypesWritePlatformServiceJpaRepositoryImpl implements Group
final Set<Group> groupMembers = assembleSetOfChildGroups(officeId, command);
final boolean active = command.booleanPrimitiveValueOfParameterNamed(GroupingTypesApiConstants.activeParamName);
LocalDate submittedOnDate = LocalDate.now(DateUtils.getDateTimeZoneOfTenant());
LocalDate submittedOnDate = DateUtils.getBusinessLocalDate();
if (active && submittedOnDate.isAfter(activationDate)) {
submittedOnDate = activationDate;
}
@@ -509,7 +509,7 @@ public class GroupingTypesWritePlatformServiceJpaRepositoryImpl implements Group
groupForUpdate.updateStaff(staff);
if (inheritStaffForClientAccounts) {
LocalDate loanOfficerReassignmentDate = LocalDate.now(DateUtils.getDateTimeZoneOfTenant());
LocalDate loanOfficerReassignmentDate = DateUtils.getBusinessLocalDate();
/*
* update loan officer for client and update loan officer for clients loans and savings
*/
@@ -154,10 +154,10 @@ public class InterestRateChartFields {
public boolean isOverlapping(InterestRateChartFields that) {
final LocalDate thisFromDate = this.getFromDateAsLocalDate();
LocalDate thisEndDate = this.getEndDateAsLocalDate();
thisEndDate = thisEndDate == null ? DateUtils.getLocalDateOfTenant() : thisEndDate;
thisEndDate = thisEndDate == null ? DateUtils.getBusinessLocalDate() : thisEndDate;
final LocalDate thatFromDate = that.getFromDateAsLocalDate();
LocalDate thatEndDate = that.getEndDateAsLocalDate();
thatEndDate = thatEndDate == null ? DateUtils.getLocalDateOfTenant() : thatEndDate;
thatEndDate = thatEndDate == null ? DateUtils.getBusinessLocalDate() : thatEndDate;
final LocalDateInterval thisInterval = LocalDateInterval.create(thisFromDate, thisEndDate);
final LocalDateInterval thatInterval = LocalDateInterval.create(thatFromDate, thatEndDate);
@@ -169,7 +169,7 @@ public class InterestRateChartFields {
}
public boolean isApplicableChartFor(final LocalDate target) {
final LocalDate endDate = this.endDate == null ? DateUtils.getLocalDateOfTenant() : this.getEndDateAsLocalDate();
final LocalDate endDate = this.endDate == null ? DateUtils.getBusinessLocalDate() : this.getEndDateAsLocalDate();
final LocalDateInterval interval = LocalDateInterval.create(getFromDateAsLocalDate(), endDate);
return interval.contains(target);
}
@@ -42,12 +42,11 @@ public class ClientAttributeIncentiveCalculation extends AttributeIncentiveCalcu
break;
case AGE:
if (client.dateOfBirth() != null) {
final LocalDate dobLacalDate = LocalDate.ofInstant(client.dateOfBirth().toInstant(),
final LocalDate dobLocalDate = LocalDate.ofInstant(client.dateOfBirth().toInstant(),
DateUtils.getDateTimeZoneOfTenant());
final int age = Math
.toIntExact(ChronoUnit.YEARS.between(dobLacalDate, LocalDate.now(DateUtils.getDateTimeZoneOfTenant())));
final int age = Math.toIntExact(ChronoUnit.YEARS.between(dobLocalDate, DateUtils.getBusinessLocalDate()));
applyIncentive = applyIncentive(incentivesFields.conditionType(), Long.valueOf(incentivesFields.attributeValue()),
Long.valueOf(age));
(long) age);
}
break;
case CLIENT_TYPE:
@@ -135,15 +135,15 @@ public class LoanTransactionsApiResource {
if (is(commandParam, "repayment")) {
transactionData = this.loanReadPlatformService.retrieveLoanTransactionTemplate(loanId);
} else if (is(commandParam, "merchantIssuedRefund")) {
LocalDate transactionDate = DateUtils.getLocalDateOfTenant();
LocalDate transactionDate = DateUtils.getBusinessLocalDate();
transactionData = this.loanReadPlatformService.retrieveLoanPrePaymentTemplate(LoanTransactionType.MERCHANT_ISSUED_REFUND,
loanId, transactionDate);
} else if (is(commandParam, "payoutRefund")) {
LocalDate transactionDate = DateUtils.getLocalDateOfTenant();
LocalDate transactionDate = DateUtils.getBusinessLocalDate();
transactionData = this.loanReadPlatformService.retrieveLoanPrePaymentTemplate(LoanTransactionType.PAYOUT_REFUND, loanId,
transactionDate);
} else if (is(commandParam, "goodwillCredit")) {
LocalDate transactionDate = DateUtils.getLocalDateOfTenant();
LocalDate transactionDate = DateUtils.getBusinessLocalDate();
transactionData = this.loanReadPlatformService.retrieveLoanPrePaymentTemplate(LoanTransactionType.GOODWILL_CREDIT, loanId,
transactionDate);
} else if (is(commandParam, "waiveinterest")) {
@@ -167,7 +167,7 @@ public class LoanTransactionsApiResource {
} else if (is(commandParam, "prepayLoan")) {
LocalDate transactionDate = null;
if (transactionDateParam == null) {
transactionDate = DateUtils.getLocalDateOfTenant();
transactionDate = DateUtils.getBusinessLocalDate();
} else {
transactionDate = LocalDate.ofInstant(transactionDateParam.getDate("transactionDate", dateFormat, locale).toInstant(),
DateUtils.getDateTimeZoneOfTenant());
@@ -181,7 +181,7 @@ public class LoanTransactionsApiResource {
} else if (is(commandParam, "foreclosure")) {
LocalDate transactionDate = null;
if (transactionDateParam == null) {
transactionDate = DateUtils.getLocalDateOfTenant();
transactionDate = DateUtils.getBusinessLocalDate();
} else {
transactionDate = LocalDate.ofInstant(transactionDateParam.getDate("transactionDate", dateFormat, locale).toInstant(),
DateUtils.getDateTimeZoneOfTenant());
@@ -704,7 +704,7 @@ public class Loan extends AbstractPersistableCustom {
transactionDate = suppliedTransactionDate;
} else {
transactionDate = loanCharge.getDueLocalDate();
final LocalDate currentDate = DateUtils.getLocalDateOfTenant();
final LocalDate currentDate = DateUtils.getBusinessLocalDate();
// if loan charge is to be applied on a future date, the loan
// transaction would show todays date as applied date
@@ -1045,8 +1045,8 @@ public class Loan extends AbstractPersistableCustom {
LocalDate transactionDate = getDisbursementDate();
if (loanCharge.isDueDateCharge()) {
if (loanCharge.getDueLocalDate().isAfter(DateUtils.getLocalDateOfTenant())) {
transactionDate = DateUtils.getLocalDateOfTenant();
if (loanCharge.getDueLocalDate().isAfter(DateUtils.getBusinessLocalDate())) {
transactionDate = DateUtils.getBusinessLocalDate();
} else {
transactionDate = loanCharge.getDueLocalDate();
}
@@ -1067,8 +1067,8 @@ public class Loan extends AbstractPersistableCustom {
waiveLoanChargeTransaction.getAmount(getCurrency()).getAmount(), loanInstallmentNumber);
waiveLoanChargeTransaction.getLoanChargesPaid().add(loanChargePaidBy);
addLoanTransaction(waiveLoanChargeTransaction);
if (this.repaymentScheduleDetail().isInterestRecalculationEnabled() && (loanCharge.getDueLocalDate() == null
|| LocalDate.now(DateUtils.getDateTimeZoneOfTenant()).isAfter(loanCharge.getDueLocalDate()))) {
if (this.repaymentScheduleDetail().isInterestRecalculationEnabled()
&& (loanCharge.getDueLocalDate() == null || DateUtils.getBusinessLocalDate().isAfter(loanCharge.getDueLocalDate()))) {
regenerateRepaymentScheduleWithInterestRecalculation(scheduleGeneratorDTO, currentUser);
}
// Waive of charges whose due date falls after latest 'repayment'
@@ -1562,9 +1562,9 @@ public class Loan extends AbstractPersistableCustom {
}
// the comparison should be done with the tenant date
// (DateUtils.getLocalDateOfTenant()) and not the server date (new
// (DateUtils.getBusinessDate()) and not the server date (new
// LocalDate())
if (getSubmittedOnDate().isAfter(DateUtils.getLocalDateOfTenant())) {
if (getSubmittedOnDate().isAfter(DateUtils.getBusinessLocalDate())) {
final String errorMessage = "The date on which a loan is submitted cannot be in the future.";
throw new InvalidLoanStateTransitionException("submittal", "cannot.be.a.future.date", errorMessage, getSubmittedOnDate());
}
@@ -1774,7 +1774,7 @@ public class Loan extends AbstractPersistableCustom {
private BigDecimal calculateOverdueAmountPercentageAppliedTo(final LoanCharge loanCharge, final int penaltyWaitPeriod) {
LoanRepaymentScheduleInstallment installment = loanCharge.getOverdueInstallmentCharge().getInstallment();
LocalDate graceDate = DateUtils.getLocalDateOfTenant().minusDays(penaltyWaitPeriod);
LocalDate graceDate = DateUtils.getBusinessLocalDate().minusDays(penaltyWaitPeriod);
Money amount = Money.zero(getCurrency());
if (graceDate.isAfter(installment.getDueDate())) {
amount = calculateOverdueAmountPercentageAppliedTo(installment, loanCharge.getChargeCalculation());
@@ -2090,7 +2090,7 @@ public class Loan extends AbstractPersistableCustom {
updateLoanScheduleDependentDerivedFields();
if (submittedOn.isAfter(DateUtils.getLocalDateOfTenant())) {
if (submittedOn.isAfter(DateUtils.getBusinessLocalDate())) {
final String errorMessage = "The date on which a loan is submitted cannot be in the future.";
throw new InvalidLoanStateTransitionException("submittal", "cannot.be.a.future.date", errorMessage, submittedOn);
}
@@ -2190,7 +2190,7 @@ public class Loan extends AbstractPersistableCustom {
validateActivityNotBeforeClientOrGroupTransferDate(LoanEvent.LOAN_REJECTED, rejectedOn);
if (rejectedOn.isAfter(DateUtils.getLocalDateOfTenant())) {
if (rejectedOn.isAfter(DateUtils.getBusinessLocalDate())) {
final String errorMessage = "The date on which a loan is rejected cannot be in the future.";
throw new InvalidLoanStateTransitionException("reject", "cannot.be.a.future.date", errorMessage, rejectedOn);
}
@@ -2239,7 +2239,7 @@ public class Loan extends AbstractPersistableCustom {
validateActivityNotBeforeClientOrGroupTransferDate(LoanEvent.LOAN_WITHDRAWN, withdrawnOn);
if (withdrawnOn.isAfter(DateUtils.getLocalDateOfTenant())) {
if (withdrawnOn.isAfter(DateUtils.getBusinessLocalDate())) {
final String errorMessage = "The date on which a loan is withdrawn cannot be in the future.";
throw new InvalidLoanStateTransitionException("withdraw", "cannot.be.a.future.date", errorMessage, command);
}
@@ -2355,7 +2355,7 @@ public class Loan extends AbstractPersistableCustom {
validateActivityNotBeforeClientOrGroupTransferDate(LoanEvent.LOAN_APPROVED, approvedOn);
if (approvedOn.isAfter(DateUtils.getLocalDateOfTenant())) {
if (approvedOn.isAfter(DateUtils.getBusinessLocalDate())) {
final String errorMessage = "The date on which a loan is approved cannot be in the future.";
throw new InvalidLoanStateTransitionException("approval", "cannot.be.a.future.date", errorMessage, getApprovedOnDate());
}
@@ -2513,7 +2513,7 @@ public class Loan extends AbstractPersistableCustom {
LocalDate firstInstallmentDueDate = fetchRepaymentScheduleInstallment(1).getDueDate();
if (interestRecalculationEnabledParam
&& (firstInstallmentDueDate.isBefore(LocalDate.now(DateUtils.getDateTimeZoneOfTenant())) || disbursementMissedParam)) {
&& (firstInstallmentDueDate.isBefore(DateUtils.getBusinessLocalDate()) || disbursementMissedParam)) {
regenerateRepaymentScheduleWithInterestRecalculation(scheduleGeneratorDTO, currentUser);
}
@@ -2729,8 +2729,8 @@ public class Loan extends AbstractPersistableCustom {
private boolean isDisbursementMissed() {
boolean isDisbursementMissed = false;
for (LoanDisbursementDetails disbursementDetail : this.disbursementDetails) {
if (disbursementDetail.actualDisbursementDate() == null && LocalDate.now(DateUtils.getDateTimeZoneOfTenant())
.isAfter(disbursementDetail.expectedDisbursementDateAsLocalDate())) {
if (disbursementDetail.actualDisbursementDate() == null
&& DateUtils.getBusinessLocalDate().isAfter(disbursementDetail.expectedDisbursementDateAsLocalDate())) {
isDisbursementMissed = true;
break;
}
@@ -2840,7 +2840,7 @@ public class Loan extends AbstractPersistableCustom {
if (loanProduct.isLinkedToFloatingInterestRate()) {
floatingRateDTO.resetInterestRateDiff();
Collection<FloatingRatePeriodData> applicableRates = loanProduct.fetchInterestRates(floatingRateDTO);
LocalDate interestRateStartDate = DateUtils.getLocalDateOfTenant();
LocalDate interestRateStartDate = DateUtils.getBusinessLocalDate();
for (FloatingRatePeriodData periodData : applicableRates) {
LoanTermVariationsData loanTermVariation = new LoanTermVariationsData(
LoanEnumerations.loanvariationType(LoanTermVariationType.INTEREST_RATE), periodData.getFromDateAsLocalDate(),
@@ -2932,7 +2932,7 @@ public class Loan extends AbstractPersistableCustom {
validateActivityNotBeforeClientOrGroupTransferDate(LoanEvent.LOAN_DISBURSED, disbursedOn);
if (disbursedOn.isAfter(DateUtils.getLocalDateOfTenant())) {
if (disbursedOn.isAfter(DateUtils.getBusinessLocalDate())) {
final String errorMessage = "The date on which a loan with identifier : " + this.accountNumber
+ " is disbursed cannot be in the future.";
throw new InvalidLoanStateTransitionException("disbursal", "cannot.be.a.future.date", errorMessage, disbursedOn);
@@ -3132,7 +3132,7 @@ public class Loan extends AbstractPersistableCustom {
validateRepaymentDateIsOnNonWorkingDay(paymentTransaction.getTransactionDate(), holidayDetailDTO.getWorkingDays(),
holidayDetailDTO.isAllowTransactionsOnNonWorkingDay());
if (paymentTransaction.getTransactionDate().isAfter(DateUtils.getLocalDateOfTenant())) {
if (paymentTransaction.getTransactionDate().isAfter(DateUtils.getBusinessLocalDate())) {
final String errorMessage = "The date on which a loan charge paid cannot be in the future.";
throw new InvalidLoanStateTransitionException("charge.payment", "cannot.be.a.future.date", errorMessage,
paymentTransaction.getTransactionDate());
@@ -3231,7 +3231,7 @@ public class Loan extends AbstractPersistableCustom {
loanTransactionDate, getDisbursementDate());
}
if (loanTransactionDate.isAfter(DateUtils.getLocalDateOfTenant())) {
if (loanTransactionDate.isAfter(DateUtils.getBusinessLocalDate())) {
final String errorMessage = "The transaction date cannot be in the future.";
throw new InvalidLoanStateTransitionException("transaction", "cannot.be.a.future.date", errorMessage, loanTransactionDate);
}
@@ -3265,7 +3265,7 @@ public class Loan extends AbstractPersistableCustom {
boolean reprocess = true;
if (!isForeclosure() && isTransactionChronologicallyLatest && adjustedTransaction == null
&& loanTransaction.getTransactionDate().isEqual(DateUtils.getLocalDateOfTenant()) && currentInstallment != null
&& loanTransaction.getTransactionDate().isEqual(DateUtils.getBusinessLocalDate()) && currentInstallment != null
&& currentInstallment.getTotalOutstanding(getCurrency()).isEqualTo(loanTransaction.getAmount(getCurrency()))) {
reprocess = false;
}
@@ -3570,7 +3570,7 @@ public class Loan extends AbstractPersistableCustom {
}
public LocalDate possibleNextRepaymentDate() {
LocalDate earliestUnpaidInstallmentDate = LocalDate.now(DateUtils.getDateTimeZoneOfTenant());
LocalDate earliestUnpaidInstallmentDate = DateUtils.getBusinessLocalDate();
List<LoanRepaymentScheduleInstallment> installments = getRepaymentScheduleInstallments();
for (final LoanRepaymentScheduleInstallment installment : installments) {
if (installment.isNotFullyPaidOff()) {
@@ -3611,7 +3611,7 @@ public class Loan extends AbstractPersistableCustom {
final Money totalInterestOutstanding = getTotalInterestOutstandingOnLoan();
Money possibleInterestToWaive = totalInterestOutstanding.copy();
LocalDate transactionDate = LocalDate.now(DateUtils.getDateTimeZoneOfTenant());
LocalDate transactionDate = DateUtils.getBusinessLocalDate();
if (totalInterestOutstanding.isGreaterThanZero()) {
// find earliest known instance of overdue interest and default to
@@ -3620,8 +3620,8 @@ public class Loan extends AbstractPersistableCustom {
for (final LoanRepaymentScheduleInstallment scheduledRepayment : installments) {
final Money outstandingForPeriod = scheduledRepayment.getInterestOutstanding(loanCurrency());
if (scheduledRepayment.isOverdueOn(LocalDate.now(DateUtils.getDateTimeZoneOfTenant()))
&& scheduledRepayment.isNotFullyPaidOff() && outstandingForPeriod.isGreaterThanZero()) {
if (scheduledRepayment.isOverdueOn(DateUtils.getBusinessLocalDate()) && scheduledRepayment.isNotFullyPaidOff()
&& outstandingForPeriod.isGreaterThanZero()) {
transactionDate = scheduledRepayment.getDueDate();
possibleInterestToWaive = outstandingForPeriod;
break;
@@ -3799,7 +3799,7 @@ public class Loan extends AbstractPersistableCustom {
validateActivityNotBeforeClientOrGroupTransferDate(LoanEvent.WRITE_OFF_OUTSTANDING, writtenOffOnLocalDate);
if (writtenOffOnLocalDate.isAfter(DateUtils.getLocalDateOfTenant())) {
if (writtenOffOnLocalDate.isAfter(DateUtils.getBusinessLocalDate())) {
final String errorMessage = "The date on which a loan is written off cannot be in the future.";
throw new InvalidLoanStateTransitionException("writeoff", "cannot.be.a.future.date", errorMessage, writtenOffOnLocalDate);
}
@@ -3883,7 +3883,7 @@ public class Loan extends AbstractPersistableCustom {
getDisbursementDate());
}
if (closureDate.isAfter(DateUtils.getLocalDateOfTenant())) {
if (closureDate.isAfter(DateUtils.getBusinessLocalDate())) {
final String errorMessage = "The date on which a loan is closed cannot be in the future.";
throw new InvalidLoanStateTransitionException("close", "cannot.be.a.future.date", errorMessage, closureDate);
}
@@ -3980,7 +3980,7 @@ public class Loan extends AbstractPersistableCustom {
rescheduledOnLocalDate, getDisbursementDate());
}
if (rescheduledOnLocalDate.isAfter(DateUtils.getLocalDateOfTenant())) {
if (rescheduledOnLocalDate.isAfter(DateUtils.getBusinessLocalDate())) {
final String errorMessage = "The date on which a loan is rescheduled cannot be in the future.";
throw new InvalidLoanStateTransitionException("close.reschedule", "cannot.be.a.future.date", errorMessage,
rescheduledOnLocalDate);
@@ -4214,7 +4214,7 @@ public class Loan extends AbstractPersistableCustom {
for (final LoanRepaymentScheduleInstallment scheduledRepayment : installments) {
final Money interestOutstandingForPeriod = scheduledRepayment.getInterestOutstanding(loanCurrency());
if (scheduledRepayment.isOverdueOn(LocalDate.now(DateUtils.getDateTimeZoneOfTenant()))) {
if (scheduledRepayment.isOverdueOn(DateUtils.getBusinessLocalDate())) {
cumulativeInterestOverdue = cumulativeInterestOverdue.plus(interestOutstandingForPeriod);
}
}
@@ -4288,7 +4288,7 @@ public class Loan extends AbstractPersistableCustom {
throw new LoanOfficerAssignmentDateException("cannot.be.before.previous.unassignement.date", errorMessage, assignmentDate,
lastAssignmentRecord.getEndDate());
} else if (DateUtils.getLocalDateOfTenant().isBefore(assignmentDate)) {
} else if (DateUtils.getBusinessLocalDate().isBefore(assignmentDate)) {
final String errorMessage = "The Loan Officer assignment date (" + assignmentDate + ") cannot be in the future.";
@@ -4332,7 +4332,7 @@ public class Loan extends AbstractPersistableCustom {
private void validateUnassignDate(final LoanOfficerAssignmentHistory latestHistoryRecord, final LocalDate unassignDate) {
final LocalDate today = DateUtils.getLocalDateOfTenant();
final LocalDate today = DateUtils.getBusinessLocalDate();
if (latestHistoryRecord.getStartDate().isAfter(unassignDate)) {
@@ -4616,7 +4616,7 @@ public class Loan extends AbstractPersistableCustom {
// FIXME: AA this won't update repayment dates before current date.
if (oldDueDate.isAfter(seedDate) && oldDueDate.isAfter(DateUtils.getLocalDateOfTenant())) {
if (oldDueDate.isAfter(seedDate) && oldDueDate.isAfter(DateUtils.getBusinessLocalDate())) {
newRepaymentDate = CalendarUtils.getNewRepaymentMeetingDate(recuringRule, seedDate, oldDueDate, loanRepaymentInterval,
frequency, workingDays, isSkipRepaymentonfirstdayofmonth, numberofDays);
@@ -5421,7 +5421,7 @@ public class Loan extends AbstractPersistableCustom {
return;
}
updateLoanSchedule(loanSchedule.getInstallments(), currentUser);
this.interestRecalculatedOn = DateUtils.getDateOfTenant();
this.interestRecalculatedOn = DateUtils.getBusinessDate();
LocalDate lastRepaymentDate = this.getLastRepaymentPeriodDueDate(true);
Set<LoanCharge> charges = this.charges();
for (final LoanCharge loanCharge : charges) {
@@ -5475,7 +5475,7 @@ public class Loan extends AbstractPersistableCustom {
List<LoanTransaction> incomeTransactions = retreiveListOfIncomePostingTransactions();
List<LoanTransaction> accrualTransactions = retreiveListOfAccrualTransactions();
for (LoanInterestRecalcualtionAdditionalDetails compoundingDetail : compoundingDetails) {
if (!compoundingDetail.getEffectiveDate().isBefore(DateUtils.getLocalDateOfTenant())) {
if (!compoundingDetail.getEffectiveDate().isBefore(DateUtils.getBusinessLocalDate())) {
break;
}
LoanTransaction incomeTransaction = getTransactionForDate(incomeTransactions, compoundingDetail.getEffectiveDate());
@@ -5775,9 +5775,9 @@ public class Loan extends AbstractPersistableCustom {
feeCharges = feeCharges.plus(scheduledRepayment.getFeeChargesOutstanding(loanCurrency()));
penaltyCharges = penaltyCharges.plus(scheduledRepayment.getPenaltyChargesOutstanding(loanCurrency()));
}
return new LoanRepaymentScheduleInstallment(null, 0, LocalDate.now(DateUtils.getDateTimeZoneOfTenant()),
LocalDate.now(DateUtils.getDateTimeZoneOfTenant()), totalPrincipal.getAmount(), totalInterest.getAmount(),
feeCharges.getAmount(), penaltyCharges.getAmount(), false, compoundingDetails);
LocalDate businessDate = DateUtils.getBusinessLocalDate();
return new LoanRepaymentScheduleInstallment(null, 0, businessDate, businessDate, totalPrincipal.getAmount(),
totalInterest.getAmount(), feeCharges.getAmount(), penaltyCharges.getAmount(), false, compoundingDetails);
}
public LocalDate getAccruedTill() {
@@ -6217,7 +6217,7 @@ public class Loan extends AbstractPersistableCustom {
loanTransactionDate, getDisbursementDate());
}
if (loanTransactionDate.isAfter(DateUtils.getLocalDateOfTenant())) {
if (loanTransactionDate.isAfter(DateUtils.getBusinessLocalDate())) {
final String errorMessage = "The transaction date cannot be in the future.";
throw new InvalidLoanStateTransitionException("transaction", "cannot.be.a.future.date", errorMessage, loanTransactionDate);
}
@@ -6257,7 +6257,7 @@ public class Loan extends AbstractPersistableCustom {
public LocalDate possibleNextRefundDate() {
final LocalDate now = LocalDate.now(DateUtils.getDateTimeZoneOfTenant());
final LocalDate now = DateUtils.getBusinessLocalDate();
LocalDate lastTransactionDate = null;
for (final LoanTransaction transaction : this.loanTransactions) {
@@ -6435,7 +6435,7 @@ public class Loan extends AbstractPersistableCustom {
*/
public LocalDate getNextPossibleRepaymentDateForRescheduling() {
List<LoanDisbursementDetails> loanDisbursementDetails = this.disbursementDetails;
LocalDate nextRepaymentDate = LocalDate.now(DateUtils.getDateTimeZoneOfTenant());
LocalDate nextRepaymentDate = DateUtils.getBusinessLocalDate();
for (LoanDisbursementDetails loanDisbursementDetail : loanDisbursementDetails) {
if (loanDisbursementDetail.actualDisbursementDate() == null) {
List<LoanRepaymentScheduleInstallment> installments = getRepaymentScheduleInstallments();
@@ -6500,7 +6500,7 @@ public class Loan extends AbstractPersistableCustom {
Money totalPrincipal = Money.of(getCurrency(), this.getSummary().getTotalPrincipalOutstanding());
totalPrincipal = totalPrincipal.minus(receivables[3]);
final Set<LoanInterestRecalcualtionAdditionalDetails> compoundingDetails = null;
final LocalDate currentDate = DateUtils.getLocalDateOfTenant();
final LocalDate currentDate = DateUtils.getBusinessLocalDate();
return new LoanRepaymentScheduleInstallment(null, 0, currentDate, currentDate, totalPrincipal.getAmount(),
receivables[0].getAmount(), receivables[1].getAmount(), receivables[2].getAmount(), false, compoundingDetails);
}
@@ -546,7 +546,7 @@ public class LoanAccountDomainServiceJpa implements LoanAccountDomainService {
}
boolean isOrganisationDateEnabled = this.configurationDomainService.isOrganisationstartDateEnabled();
Date organisationStartDate = new Date();
Date organisationStartDate = DateUtils.getBusinessDate();
if (isOrganisationDateEnabled) {
organisationStartDate = this.configurationDomainService.retrieveOrganisationStartDate();
}
@@ -566,7 +566,7 @@ public class LoanAccountDomainServiceJpa implements LoanAccountDomainService {
for (LoanRepaymentScheduleInstallment installment : installments) {
if (installment.getDueDate().isAfter(loan.getMaturityDate())) {
accruedTill = DateUtils.getLocalDateOfTenant();
accruedTill = DateUtils.getBusinessLocalDate();
}
if (!isOrganisationDateEnabled || LocalDate.ofInstant(organisationStartDate.toInstant(), DateUtils.getDateTimeZoneOfTenant())
.isBefore(installment.getDueDate())) {
@@ -348,7 +348,7 @@ public class LoanTransaction extends AbstractPersistableCustom {
this.paymentDetail = paymentDetail;
this.office = office;
this.externalId = externalId;
this.submittedOnDate = DateUtils.getDateOfTenant();
this.submittedOnDate = DateUtils.getBusinessDate();
this.createdDate = Date.from(createdDate.atZone(DateUtils.getDateTimeZoneOfTenant()).toInstant());
this.appUser = appUser;
}
@@ -376,7 +376,7 @@ public class LoanTransaction extends AbstractPersistableCustom {
this.dateOf = Date.from(date.atStartOfDay(ZoneId.systemDefault()).toInstant());
this.externalId = externalId;
this.office = office;
this.submittedOnDate = DateUtils.getDateOfTenant();
this.submittedOnDate = DateUtils.getBusinessDate();
this.createdDate = Date.from(createdDate.atZone(DateUtils.getDateTimeZoneOfTenant()).toInstant());
this.appUser = appUser;
}
@@ -391,7 +391,7 @@ public class LoanTransaction extends AbstractPersistableCustom {
this.dateOf = Date.from(date.atStartOfDay(ZoneId.systemDefault()).toInstant());
this.externalId = externalId;
this.office = office;
this.submittedOnDate = DateUtils.getDateOfTenant();
this.submittedOnDate = DateUtils.getBusinessDate();
this.createdDate = Date.from(createdDate.atZone(DateUtils.getDateTimeZoneOfTenant()).toInstant());
this.appUser = appUser;
}
@@ -211,7 +211,7 @@ public class GuarantorDomainServiceImpl implements GuarantorDomainService {
final List<Guarantor> existGuarantorList = this.guarantorRepository.findByLoan(loan);
final boolean isRegularTransaction = true;
final boolean isExceptionForBalanceCheck = true;
LocalDate transactionDate = LocalDate.now(DateUtils.getDateTimeZoneOfTenant());
LocalDate transactionDate = DateUtils.getBusinessLocalDate();
PortfolioAccountType fromAccountType = PortfolioAccountType.SAVINGS;
PortfolioAccountType toAccountType = PortfolioAccountType.LOAN;
final Long toAccountId = loan.getId();
@@ -18,7 +18,6 @@
*/
package org.apache.fineract.portfolio.loanaccount.guarantor.service;
import java.time.LocalDate;
import java.util.ArrayList;
import java.util.Collection;
import java.util.List;
@@ -125,7 +124,7 @@ public class GuarantorWritePlatformServiceJpaRepositoryIImpl implements Guaranto
guarantorFundingDetails.add(fundingDetails);
if (loan.isDisbursed()
|| (loan.isApproved() && (loan.getGuaranteeAmount() != null || loan.loanProduct().isHoldGuaranteeFundsEnabled()))) {
this.guarantorDomainService.assignGuarantor(fundingDetails, LocalDate.now(DateUtils.getDateTimeZoneOfTenant()));
this.guarantorDomainService.assignGuarantor(fundingDetails, DateUtils.getBusinessLocalDate());
loan.updateGuaranteeAmount(fundingDetails.getAmount());
}
}
@@ -312,7 +311,7 @@ public class GuarantorWritePlatformServiceJpaRepositoryIImpl implements Guaranto
GuarantorFundStatusType fundStatusType = GuarantorFundStatusType.DELETED;
if (guarantorForDelete.getLoan().isDisbursed() || guarantorForDelete.getLoan().isApproved()) {
fundStatusType = GuarantorFundStatusType.WITHDRAWN;
this.guarantorDomainService.releaseGuarantor(guarantorFundingDetails, LocalDate.now(DateUtils.getDateTimeZoneOfTenant()));
this.guarantorDomainService.releaseGuarantor(guarantorFundingDetails, DateUtils.getBusinessLocalDate());
}
guarantorForDelete.updateStatus(guarantorFundingDetails, fundStatusType);
}
@@ -193,7 +193,7 @@ public final class LoanSchedulePeriodData {
this.totalOutstandingForPeriod = this.feeChargesOutstanding;
this.totalActualCostOfLoanForPeriod = this.feeChargesDue;
this.totalInstallmentAmountForPeriod = null;
if (dueDate.isBefore(LocalDate.now(DateUtils.getDateTimeZoneOfTenant()))) {
if (dueDate.isBefore(DateUtils.getBusinessLocalDate())) {
this.totalOverdue = this.totalOutstandingForPeriod;
} else {
this.totalOverdue = null;
@@ -255,7 +255,7 @@ public final class LoanSchedulePeriodData {
this.totalActualCostOfLoanForPeriod = interestDueOnPrincipalOutstanding.add(feeChargesDueForPeriod);
this.totalInstallmentAmountForPeriod = totalInstallmentAmountForPeriod;
if (dueDate.isBefore(LocalDate.now(DateUtils.getDateTimeZoneOfTenant()))) {
if (dueDate.isBefore(DateUtils.getBusinessLocalDate())) {
this.totalOverdue = this.totalOutstandingForPeriod;
} else {
this.totalOverdue = null;
@@ -326,7 +326,7 @@ public final class LoanSchedulePeriodData {
this.totalActualCostOfLoanForPeriod = totalActualCostOfLoanForPeriod;
this.totalInstallmentAmountForPeriod = totalInstallmentAmountForPeriod;
if (dueDate.isBefore(LocalDate.now(DateUtils.getDateTimeZoneOfTenant()))) {
if (dueDate.isBefore(DateUtils.getBusinessLocalDate())) {
this.totalOverdue = this.totalOutstandingForPeriod;
} else {
this.totalOverdue = null;
@@ -146,7 +146,7 @@ public abstract class AbstractLoanScheduleGenerator implements LoanScheduleGener
// set and handled separately after all installments generated
final Set<LoanCharge> nonCompoundingCharges = seperateTotalCompoundingPercentageCharges(loanCharges);
LocalDate currentDate = DateUtils.getLocalDateOfTenant();
LocalDate currentDate = DateUtils.getBusinessLocalDate();
LocalDate lastRestDate = currentDate;
if (loanApplicationTerms.getRestCalendarInstance() != null) {
lastRestDate = getNextRestScheduleDate(currentDate.minusDays(1), loanApplicationTerms, holidayDetailDTO);
@@ -1596,7 +1596,7 @@ public abstract class AbstractLoanScheduleGenerator implements LoanScheduleGener
final MonetaryCurrency currency, final Map<LocalDate, Money> latePaymentMap, final LocalDate scheduledDueDate,
List<LoanRepaymentScheduleInstallment> installments, boolean applyRestFrequencyForPrincipal, final LocalDate lastRestDate) {
latePaymentMap.clear();
LocalDate currentDate = DateUtils.getLocalDateOfTenant();
LocalDate currentDate = DateUtils.getBusinessLocalDate();
Money totalCompoundingAmount = Money.zero(currency);
for (LoanRepaymentScheduleInstallment loanRepaymentScheduleInstallment : installments) {
@@ -1632,10 +1632,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.getLocalDateOfTenant());
&& loanRepaymentScheduleInstallment.getDueDate().isBefore(DateUtils.getBusinessLocalDate());
} else {
final boolean isPastDate = params.applyInterestRecalculation()
&& loanRepaymentScheduleInstallment.getDueDate().isBefore(DateUtils.getLocalDateOfTenant());
&& loanRepaymentScheduleInstallment.getDueDate().isBefore(DateUtils.getBusinessLocalDate());
boolean periodHasCompoundingDate = false;
Money amountCharged = Money.zero(currency);
if (loanApplicationTerms.getInterestRecalculationCompoundingMethod() != null) {
@@ -1915,7 +1915,7 @@ public abstract class AbstractLoanScheduleGenerator implements LoanScheduleGener
periods.add(disbursementPeriod);
principal = principal.add(disbursementData.amount());
} else if (!excludePastUndisbursed || disbursementData.isDisbursed()
|| !disbursementData.disbursementDate().isBefore(DateUtils.getLocalDateOfTenant())) {
|| !disbursementData.disbursementDate().isBefore(DateUtils.getBusinessLocalDate())) {
/*
* 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
@@ -2124,7 +2124,7 @@ public abstract class AbstractLoanScheduleGenerator implements LoanScheduleGener
// interest calculation
final TreeMap<LocalDate, Money> compoundingMap = new TreeMap<>();
final Map<LocalDate, Map<LocalDate, Money>> compoundingDateVariations = new HashMap<>();
LocalDate currentDate = DateUtils.getLocalDateOfTenant();
LocalDate currentDate = DateUtils.getBusinessLocalDate();
LocalDate lastRestDate = currentDate;
if (loanApplicationTerms.isInterestRecalculationEnabled()) {
lastRestDate = getNextRestScheduleDate(currentDate.minusDays(1), loanApplicationTerms, holidayDetailDTO);
@@ -2494,7 +2494,7 @@ public abstract class AbstractLoanScheduleGenerator implements LoanScheduleGener
}
compoundingDateVariations.put(installment.getFromDate(), compoundingMap);
if (totalCompounded.isGreaterThanZero()) {
final boolean isPastDate = installment.getDueDate().isBefore(DateUtils.getLocalDateOfTenant());
final boolean isPastDate = installment.getDueDate().isBefore(DateUtils.getBusinessLocalDate());
final LocalDate restDate = getNextRestScheduleDate(installment.getDueDate().minusDays(1), loanApplicationTerms,
holidayDetailDTO);
if (isPastDate) {
@@ -418,7 +418,7 @@ public class LoanScheduleAssembler {
baseLendingRatePeriods);
Collection<FloatingRatePeriodData> applicableRates = loanProduct.fetchInterestRates(floatingRateDTO);
LocalDate interestRateStartDate = DateUtils.getLocalDateOfTenant();
LocalDate interestRateStartDate = DateUtils.getBusinessLocalDate();
final LocalDate dateValue = null;
final boolean isSpecificToInstallment = false;
for (FloatingRatePeriodData periodData : applicableRates) {
@@ -144,7 +144,7 @@ public class LoanScheduleCalculationPlatformServiceImpl implements LoanScheduleC
final Loan loan = this.loanAssembler.assembleFrom(loanId);
LocalDate today = DateUtils.getLocalDateOfTenant();
LocalDate today = DateUtils.getBusinessLocalDate();
final LoanRepaymentScheduleTransactionProcessor loanRepaymentScheduleTransactionProcessor = loanRepaymentScheduleTransactionProcessorFactory
.determineProcessor(loan.transactionProcessingStrategy());
@@ -496,7 +496,7 @@ public class LoanRescheduleRequestWritePlatformServiceImpl implements LoanResche
}
loan.updateRescheduledByUser(appUser);
loan.updateRescheduledOnDate(LocalDate.now(DateUtils.getDateTimeZoneOfTenant()));
loan.updateRescheduledOnDate(DateUtils.getBusinessLocalDate());
// update the status of the request
loanRescheduleRequest.approve(appUser, approvedOnDate);
@@ -83,7 +83,7 @@ public class LoanAccrualPlatformServiceImpl implements LoanAccrualPlatformServic
@CronTarget(jobName = JobName.ADD_PERIODIC_ACCRUAL_ENTRIES)
public void addPeriodicAccruals() throws JobExecutionException {
try {
addPeriodicAccruals(LocalDate.now(DateUtils.getDateTimeZoneOfTenant()));
addPeriodicAccruals(DateUtils.getBusinessLocalDate());
} catch (MultiException e) {
throw new JobExecutionException(e);
}
@@ -272,7 +272,7 @@ public class LoanAccrualWritePlatformServiceImpl implements LoanAccrualWritePlat
+ "fee_charges_portion_derived,penalty_charges_portion_derived, submitted_on_date) VALUES (?, ?, false, ?, ?, ?, ?, ?, ?, ?)";
this.jdbcTemplate.update(transactionSql, scheduleAccrualData.getLoanId(), scheduleAccrualData.getOfficeId(),
LoanTransactionType.ACCRUAL.getValue(), Date.from(accruedTill.atStartOfDay(ZoneId.systemDefault()).toInstant()), amount,
interestportion, feeportion, penaltyportion, DateUtils.getDateOfTenant());
interestportion, feeportion, penaltyportion, DateUtils.getBusinessDate());
@SuppressWarnings("deprecation")
final Long transactonId = this.jdbcTemplate.queryForObject("SELECT " + sqlGenerator.lastInsertId(), Long.class); // NOSONAR
@@ -124,7 +124,8 @@ public class LoanArrearsAgingServiceImpl implements LoanArrearsAgingService {
updateSqlBuilder.append(" WHERE ml.loan_status_id = 300 "); // active
updateSqlBuilder.append(" and mr.completed_derived is false ");
updateSqlBuilder.append(" and mr.duedate < ")
.append(sqlGenerator.subDate(sqlGenerator.currentDate(), "COALESCE(ml.grace_on_arrears_ageing, 0)", "day")).append(" ");
.append(sqlGenerator.subDate(sqlGenerator.currentBusinessDate(), "COALESCE(ml.grace_on_arrears_ageing, 0)", "day"))
.append(" ");
updateSqlBuilder.append(" and (prd.arrears_based_on_original_schedule = false or prd.arrears_based_on_original_schedule is null) ");
updateSqlBuilder.append(" GROUP BY ml.id");
@@ -180,9 +181,10 @@ public class LoanArrearsAgingServiceImpl implements LoanArrearsAgingService {
BigDecimal interestOverdue = BigDecimal.ZERO;
BigDecimal feeOverdue = BigDecimal.ZERO;
BigDecimal penaltyOverdue = BigDecimal.ZERO;
LocalDate overDueSince = LocalDate.now(DateUtils.getDateTimeZoneOfTenant());
LocalDate businessDate = DateUtils.getBusinessLocalDate();
LocalDate overDueSince = businessDate;
for (LoanRepaymentScheduleInstallment installment : installments) {
if (installment.getDueDate().isBefore(LocalDate.now(DateUtils.getDateTimeZoneOfTenant()))) {
if (installment.getDueDate().isBefore(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());
@@ -215,7 +217,7 @@ public class LoanArrearsAgingServiceImpl implements LoanArrearsAgingService {
loanIdentifier.append(
"inner join m_product_loan_recalculation_details prd on prd.product_id = ml.product_id and prd.arrears_based_on_original_schedule = true ");
loanIdentifier.append("WHERE ml.loan_status_id = 300 and mr.completed_derived is false and mr.duedate < ")
.append(sqlGenerator.subDate(sqlGenerator.currentDate(), "COALESCE(ml.grace_on_arrears_ageing, 0)", "day"))
.append(sqlGenerator.subDate(sqlGenerator.currentBusinessDate(), "COALESCE(ml.grace_on_arrears_ageing, 0)", "day"))
.append(" group by ml.id");
List<Long> loanIds = this.jdbcTemplate.queryForList(loanIdentifier.toString(), Long.class);
if (!loanIds.isEmpty()) {
@@ -276,7 +278,7 @@ public class LoanArrearsAgingServiceImpl implements LoanArrearsAgingService {
BigDecimal interestOverdue = BigDecimal.ZERO;
BigDecimal feeOverdue = BigDecimal.ZERO;
BigDecimal penaltyOverdue = BigDecimal.ZERO;
LocalDate overDueSince = LocalDate.now(DateUtils.getDateTimeZoneOfTenant());
LocalDate overDueSince = DateUtils.getBusinessLocalDate();
for (LoanSchedulePeriodData loanSchedulePeriodData : entry.getValue()) {
if (!loanSchedulePeriodData.getComplete()) {
@@ -437,7 +439,7 @@ public class LoanArrearsAgingServiceImpl implements LoanArrearsAgingService {
"mr.interest_amount as interestAmount, mr.fee_charges_amount as feeAmount, mr.penalty_charges_amount as penaltyAmount ");
scheduleDetail.append("from m_loan ml INNER JOIN m_loan_repayment_schedule_history mr on mr.loan_id = ml.id ");
scheduleDetail.append("where mr.duedate < "
+ sqlGenerator.subDate(sqlGenerator.currentDate(), "COALESCE(ml.grace_on_arrears_ageing, 0)", "day") + " and ");
+ sqlGenerator.subDate(sqlGenerator.currentBusinessDate(), "COALESCE(ml.grace_on_arrears_ageing, 0)", "day") + " and ");
scheduleDetail.append("ml.id IN(").append(loanIdsAsString).append(") and mr.version = (");
scheduleDetail.append("select max(lrs.version) from m_loan_repayment_schedule_history lrs where mr.loan_id = lrs.loan_id");
scheduleDetail.append(") order by ml.id,mr.duedate");
@@ -25,7 +25,6 @@ import java.sql.ResultSet;
import java.sql.SQLException;
import java.time.LocalDate;
import java.time.ZoneId;
import java.time.format.DateTimeFormatter;
import java.time.temporal.ChronoUnit;
import java.util.ArrayList;
import java.util.Arrays;
@@ -152,7 +151,6 @@ public class LoanReadPlatformServiceImpl implements LoanReadPlatformService {
private final PaginationHelper paginationHelper;
private final LoanMapper loaanLoanMapper;
private final NamedParameterJdbcTemplate namedParameterJdbcTemplate;
private final DateTimeFormatter formatter = DateTimeFormatter.ofPattern("yyyy-MM-dd");
private final PaymentTypeReadPlatformService paymentTypeReadPlatformService;
private final LoanRepaymentScheduleTransactionProcessorFactory loanRepaymentScheduleTransactionProcessorFactory;
private final FloatingRatesReadPlatformService floatingRatesReadPlatformService;
@@ -374,7 +372,7 @@ public class LoanReadPlatformServiceImpl implements LoanReadPlatformService {
this.context.authenticatedUser();
final ClientData clientAccount = this.clientReadPlatformService.retrieveOne(clientId);
final LocalDate expectedDisbursementDate = DateUtils.getLocalDateOfTenant();
final LocalDate expectedDisbursementDate = DateUtils.getBusinessLocalDate();
LoanAccountData loanTemplateDetails = LoanAccountData.clientDefaults(clientAccount.id(), clientAccount.accountNo(),
clientAccount.displayName(), clientAccount.officeId(), expectedDisbursementDate);
@@ -392,7 +390,7 @@ public class LoanReadPlatformServiceImpl implements LoanReadPlatformService {
this.context.authenticatedUser();
final GroupGeneralData groupAccount = this.groupReadPlatformService.retrieveOne(groupId);
final LocalDate expectedDisbursementDate = DateUtils.getLocalDateOfTenant();
final LocalDate expectedDisbursementDate = DateUtils.getBusinessLocalDate();
LoanAccountData loanDetails = LoanAccountData.groupDefaults(groupAccount, expectedDisbursementDate);
if (productId != null) {
@@ -420,7 +418,7 @@ public class LoanReadPlatformServiceImpl implements LoanReadPlatformService {
collectionMeetingCalendar);
}
final LocalDate expectedDisbursementDate = DateUtils.getLocalDateOfTenant();
final LocalDate expectedDisbursementDate = DateUtils.getBusinessLocalDate();
LoanAccountData loanDetails = LoanAccountData.groupDefaults(groupAccount, expectedDisbursementDate);
if (productId != null) {
@@ -459,7 +457,7 @@ public class LoanReadPlatformServiceImpl implements LoanReadPlatformService {
final CurrencyData currencyData = applicationCurrency.toData();
final LocalDate earliestUnpaidInstallmentDate = LocalDate.now(DateUtils.getDateTimeZoneOfTenant());
final LocalDate earliestUnpaidInstallmentDate = DateUtils.getBusinessLocalDate();
final LocalDate recalculateFrom = null;
final ScheduleGeneratorDTO scheduleGeneratorDTO = loanUtilService.buildScheduleGeneratorDTO(loan, recalculateFrom);
final LoanRepaymentScheduleInstallment loanRepaymentScheduleInstallment = loan.fetchPrepaymentDetail(scheduleGeneratorDTO, onDate);
@@ -525,7 +523,7 @@ public class LoanReadPlatformServiceImpl implements LoanReadPlatformService {
final BigDecimal outstandingLoanBalance = null;
final LoanTransactionEnumData transactionType = LoanEnumerations.transactionType(LoanTransactionType.WRITEOFF);
final BigDecimal unrecognizedIncomePortion = null;
return new LoanTransactionData(null, null, null, transactionType, null, null, DateUtils.getLocalDateOfTenant(), null, null, null,
return new LoanTransactionData(null, null, null, transactionType, null, null, DateUtils.getBusinessLocalDate(), null, null, null,
null, null, null, null, null, null, null, outstandingLoanBalance, unrecognizedIncomePortion, false);
}
@@ -533,7 +531,7 @@ public class LoanReadPlatformServiceImpl implements LoanReadPlatformService {
@Override
public LoanApprovalData retrieveApprovalTemplate(final Long loanId) {
final Loan loan = this.loanRepositoryWrapper.findOneWithNotFoundDetection(loanId, true);
return new LoanApprovalData(loan.getProposedPrincipal(), DateUtils.getLocalDateOfTenant(), loan.getNetDisbursalAmount());
return new LoanApprovalData(loan.getProposedPrincipal(), DateUtils.getBusinessLocalDate(), loan.getNetDisbursalAmount());
}
@Override
@@ -1173,8 +1171,8 @@ public class LoanReadPlatformServiceImpl implements LoanReadPlatformService {
}
this.outstandingLoanPrincipalBalance = this.outstandingLoanPrincipalBalance.add(data.amount());
} else if (data.isDueForDisbursement(fromDate, dueDate)) {
if (!excludePastUndisbursed || (excludePastUndisbursed && (data.isDisbursed()
|| !data.disbursementDate().isBefore(LocalDate.now(DateUtils.getDateTimeZoneOfTenant()))))) {
if (!excludePastUndisbursed || (excludePastUndisbursed
&& (data.isDisbursed() || !data.disbursementDate().isBefore(DateUtils.getBusinessLocalDate())))) {
principal = principal.add(data.amount());
LoanSchedulePeriodData periodData = null;
if (data.getChargeAmount() == null) {
@@ -1472,7 +1470,7 @@ public class LoanReadPlatformServiceImpl implements LoanReadPlatformService {
this.context.authenticatedUser();
final ClientData clientAccount = this.clientReadPlatformService.retrieveOne(clientId);
final LocalDate expectedDisbursementDate = DateUtils.getLocalDateOfTenant();
final LocalDate expectedDisbursementDate = DateUtils.getBusinessLocalDate();
return LoanAccountData.clientDefaults(clientAccount.id(), clientAccount.accountNo(), clientAccount.displayName(),
clientAccount.officeId(), expectedDisbursementDate);
@@ -1482,14 +1480,14 @@ public class LoanReadPlatformServiceImpl implements LoanReadPlatformService {
public LoanAccountData retrieveGroupDetailsTemplate(final Long groupId) {
this.context.authenticatedUser();
final GroupGeneralData groupAccount = this.groupReadPlatformService.retrieveOne(groupId);
final LocalDate expectedDisbursementDate = DateUtils.getLocalDateOfTenant();
final LocalDate expectedDisbursementDate = DateUtils.getBusinessLocalDate();
return LoanAccountData.groupDefaults(groupAccount, expectedDisbursementDate);
}
@Override
public LoanAccountData retrieveGroupAndMembersDetailsTemplate(final Long groupId) {
GroupGeneralData groupAccount = this.groupReadPlatformService.retrieveOne(groupId);
final LocalDate expectedDisbursementDate = DateUtils.getLocalDateOfTenant();
final LocalDate expectedDisbursementDate = DateUtils.getBusinessLocalDate();
// get group associations
final Collection<ClientData> membersOfGroup = this.clientReadPlatformService.retrieveActiveClientMembersOfGroup(groupId);
@@ -1546,7 +1544,7 @@ public class LoanReadPlatformServiceImpl implements LoanReadPlatformService {
final StringBuilder sqlBuilder = new StringBuilder(400);
sqlBuilder.append("select ").append(rm.schema())
.append(" where " + sqlGenerator.subDate(sqlGenerator.currentDate(), "?", "day") + " > ls.duedate ")
.append(" where " + sqlGenerator.subDate(sqlGenerator.currentBusinessDate(), "?", "day") + " > ls.duedate ")
.append(" and ls.completed_derived <> true and mc.charge_applies_to_enum =1 ")
.append(" and ls.recalculated_interest_component <> true ")
.append(" and mc.charge_time_enum = 9 and ml.loan_status_id = 300 ");
@@ -1556,7 +1554,7 @@ public class LoanReadPlatformServiceImpl implements LoanReadPlatformService {
}
// Only apply for duedate = yesterday (so that we don't apply
// penalties on the duedate itself)
sqlBuilder.append(" and ls.duedate >= " + sqlGenerator.subDate(sqlGenerator.currentDate(), "(? + 1)", "day"));
sqlBuilder.append(" and ls.duedate >= " + sqlGenerator.subDate(sqlGenerator.currentBusinessDate(), "(? + 1)", "day"));
return this.jdbcTemplate.query(sqlBuilder.toString(), rm, new Object[] { penaltyWaitPeriod, penaltyWaitPeriod });
}
@@ -1666,18 +1664,17 @@ public class LoanReadPlatformServiceImpl implements LoanReadPlatformService {
.append(" and (((ls.fee_charges_amount <> COALESCE(ls.accrual_fee_charges_derived, 0))")
.append(" or ( ls.penalty_charges_amount <> COALESCE(ls.accrual_penalty_charges_derived, 0))")
.append(" or ( ls.interest_amount <> COALESCE(ls.accrual_interest_derived, 0)))")
.append(" and loan.loan_status_id=:active and mpl.accounting_type=:type and loan.is_npa=false and ls.duedate <= "
+ sqlGenerator.currentDate() + ") ");
.append(" and loan.loan_status_id=:active and mpl.accounting_type=:type and loan.is_npa=false and ls.duedate <= :currentDate) ");
if (organisationStartDate != null) {
sqlBuilder.append(" and ls.duedate > :organisationstartdate ");
sqlBuilder.append(" and ls.duedate > :organisationStartDate ");
}
sqlBuilder.append(" order by loan.id,ls.duedate ");
Map<String, Object> paramMap = new HashMap<>(3);
paramMap.put("active", LoanStatus.ACTIVE.getValue());
paramMap.put("type", AccountingRuleType.ACCRUAL_PERIODIC.getValue());
paramMap.put("organisationstartdate",
(organisationStartDate == null) ? formatter.format(LocalDate.now(DateUtils.getDateTimeZoneOfTenant()))
: formatter.format(LocalDate.ofInstant(organisationStartDate.toInstant(), DateUtils.getDateTimeZoneOfTenant())));
paramMap.put("organisationStartDate", (organisationStartDate == null) ? DateUtils.getBusinessLocalDate()
: LocalDate.ofInstant(organisationStartDate.toInstant(), DateUtils.getDateTimeZoneOfTenant()));
paramMap.put("currentDate", DateUtils.getBusinessLocalDate());
return this.namedParameterJdbcTemplate.query(sqlBuilder.toString(), paramMap, mapper);
}
@@ -1687,26 +1684,24 @@ public class LoanReadPlatformServiceImpl implements LoanReadPlatformService {
LoanSchedulePeriodicAccrualMapper mapper = new LoanSchedulePeriodicAccrualMapper();
Date organisationStartDate = this.configurationDomainService.retrieveOrganisationStartDate();
String formattedTillDate = formatter.format(tillDate);
final StringBuilder sqlBuilder = new StringBuilder(400);
sqlBuilder.append("select ").append(mapper.schema()).append(
" where (recaldet.is_compounding_to_be_posted_as_transaction is null or recaldet.is_compounding_to_be_posted_as_transaction = false) ")
.append(" and (((ls.fee_charges_amount <> COALESCE(ls.accrual_fee_charges_derived, 0))")
.append(" or (ls.penalty_charges_amount <> COALESCE(ls.accrual_penalty_charges_derived, 0))")
.append(" or (ls.interest_amount <> COALESCE(ls.accrual_interest_derived, 0)))")
.append(" and loan.loan_status_id=:active and mpl.accounting_type=:type and (loan.closedon_date <= '" + formattedTillDate
+ "' or loan.closedon_date is null)")
.append(" and loan.is_npa=false and (ls.duedate <= '" + formattedTillDate + "' or (ls.duedate > '" + formattedTillDate
+ "' and ls.fromdate < '" + formattedTillDate + "'))) ");
.append(" and loan.loan_status_id=:active and mpl.accounting_type=:type and (loan.closedon_date <= :tillDate or loan.closedon_date is null)")
.append(" and loan.is_npa=false and (ls.duedate <= :tillDate or (ls.duedate > :tillDate and ls.fromdate < :tillDate))) ");
Map<String, Object> paramMap = new HashMap<>(4);
if (organisationStartDate != null) {
String formattedOrganizationStartDate = formatter
.format(LocalDate.ofInstant(organisationStartDate.toInstant(), DateUtils.getDateTimeZoneOfTenant()));
sqlBuilder.append(" and ls.duedate > '" + formattedOrganizationStartDate + "' ");
sqlBuilder.append(" and ls.duedate > :organisationStartDate ");
paramMap.put("organisationStartDate",
LocalDate.ofInstant(organisationStartDate.toInstant(), DateUtils.getDateTimeZoneOfTenant()));
}
sqlBuilder.append(" order by loan.id,ls.duedate ");
Map<String, Object> paramMap = new HashMap<>(4);
paramMap.put("active", LoanStatus.ACTIVE.getValue());
paramMap.put("type", AccountingRuleType.ACCRUAL_PERIODIC.getValue());
paramMap.put("tillDate", tillDate);
return this.namedParameterJdbcTemplate.query(sqlBuilder.toString(), paramMap, mapper);
}
@@ -1852,7 +1847,7 @@ public class LoanReadPlatformServiceImpl implements LoanReadPlatformService {
final List<CodeValueData> writeOffReasonOptions = new ArrayList<>(
this.codeValueReadPlatformService.retrieveCodeValuesByCode(LoanApiConstants.WRITEOFFREASONS));
LoanTransactionData loanTransactionData = new LoanTransactionData(null, null, null, transactionType, null, loan.currency(),
DateUtils.getLocalDateOfTenant(), loan.getTotalOutstandingAmount(), loan.getNetDisbursalAmount(), null, null, null, null,
DateUtils.getBusinessLocalDate(), loan.getTotalOutstandingAmount(), loan.getNetDisbursalAmount(), null, null, null, null,
null, null, null, null, outstandingLoanBalance, unrecognizedIncomePortion, false);
loanTransactionData.setWriteOffReasonOptions(writeOffReasonOptions);
return loanTransactionData;
@@ -1891,9 +1886,9 @@ public class LoanReadPlatformServiceImpl implements LoanReadPlatformService {
sqlBuilder.append(" ))");
sqlBuilder.append(" group by ml.id");
try {
String currentdate = formatter.format(DateUtils.getLocalDateOfTenant());
LocalDate currentdate = DateUtils.getBusinessLocalDate();
// will look only for yesterday modified rates
String yesterday = formatter.format(DateUtils.getLocalDateOfTenant().minusDays(1));
LocalDate yesterday = DateUtils.getBusinessLocalDate().minusDays(1);
return this.jdbcTemplate.queryForList(sqlBuilder.toString(), Long.class,
new Object[] { yesterday, LoanStatus.ACTIVE.getValue(), currentdate, currentdate, currentdate, yesterday });
} catch (final EmptyResultDataAccessException e) {
@@ -1903,9 +1898,9 @@ public class LoanReadPlatformServiceImpl implements LoanReadPlatformService {
@Override
public List<Long> fetchLoansForInterestRecalculation(Integer pageSize, Long maxLoanIdInList, String officeHierarchy) {
String currentdate = formatter.format(DateUtils.getLocalDateOfTenant());
LocalDate currentdate = DateUtils.getBusinessLocalDate();
// will look only for yesterday modified rates
String yesterday = formatter.format(DateUtils.getLocalDateOfTenant().minusDays(1));
LocalDate yesterday = DateUtils.getBusinessLocalDate().minusDays(1);
StringBuilder sqlBuilder = new StringBuilder();
sqlBuilder.append("SELECT ml.id FROM m_loan ml ");
sqlBuilder.append(" left join m_client mc on mc.id = ml.client_id ");
@@ -1920,20 +1915,19 @@ public class LoanReadPlatformServiceImpl implements LoanReadPlatformService {
sqlBuilder.append(" left join m_loan_reschedule_request lrr on lrr.loan_id = ml.id");
// this is to identify the applicable rates when base rate is changed
sqlBuilder.append(" left join m_floating_rates bfr on bfr.is_base_lending_rate = true");
sqlBuilder.append(" left join m_floating_rates_periods bfrp on bfr.id = bfrp.floating_rates_id and bfrp.created_date >= '"
+ yesterday + "'");
sqlBuilder.append(" left join m_floating_rates_periods bfrp on bfr.id = bfrp.floating_rates_id and bfrp.created_date >= ?");
sqlBuilder.append(" WHERE ml.loan_status_id = ? ");
sqlBuilder.append(" and ml.is_npa = false ");
sqlBuilder.append(" and ((");
sqlBuilder.append("ml.interest_recalculation_enabled = true ");
sqlBuilder.append(" and (ml.interest_recalcualated_on is null or ml.interest_recalcualated_on <> '" + currentdate + "')");
sqlBuilder.append(" and (ml.interest_recalcualated_on is null or ml.interest_recalcualated_on <> ? )");
sqlBuilder.append(" and ((");
sqlBuilder.append(" mr.completed_derived is false ");
sqlBuilder.append(" and mr.duedate < '" + currentdate + "' )");
sqlBuilder.append(" or dd.expected_disburse_date < '" + currentdate + "' )) ");
sqlBuilder.append(" and mr.duedate < ? )");
sqlBuilder.append(" or dd.expected_disburse_date < ? )) ");
sqlBuilder.append(" or (");
sqlBuilder.append(" fr.is_active = true and frp.is_active = true");
sqlBuilder.append(" and (frp.created_date >= '" + yesterday + "' or ");
sqlBuilder.append(" and (frp.created_date >= ? or ");
sqlBuilder
.append("(bfrp.id is not null and frp.is_differential_to_base_lending_rate = true and frp.from_date >= bfrp.from_date)) ");
sqlBuilder.append("and lrr.loan_id is null");
@@ -1943,7 +1937,8 @@ public class LoanReadPlatformServiceImpl implements LoanReadPlatformService {
sqlBuilder.append(" limit ? ");
try {
return Collections.synchronizedList(this.jdbcTemplate.queryForList(sqlBuilder.toString(), Long.class,
new Object[] { LoanStatus.ACTIVE.getValue(), maxLoanIdInList, officeHierarchy, pageSize }));
new Object[] { yesterday, LoanStatus.ACTIVE.getValue(), currentdate, currentdate, currentdate, yesterday,
maxLoanIdInList, officeHierarchy, pageSize }));
} catch (final EmptyResultDataAccessException e) {
return null;
}
@@ -2105,7 +2100,7 @@ public class LoanReadPlatformServiceImpl implements LoanReadPlatformService {
+ " + SUM(COALESCE(mr.interest_completed_derived, 0)) " + " + SUM(COALESCE(mr.fee_charges_completed_derived, 0)) "
+ " + SUM(COALESCE(mr.penalty_charges_completed_derived, 0))) as total_in_advance_derived "
+ " from m_loan ml INNER JOIN m_loan_repayment_schedule mr on mr.loan_id = ml.id "
+ " where ml.id=? and mr.duedate >= " + sqlGenerator.currentDate() + " group by ml.id having "
+ " where ml.id=? and mr.duedate >= " + sqlGenerator.currentBusinessDate() + " group by ml.id having "
+ " (SUM(COALESCE(mr.principal_completed_derived, 0)) " + " + SUM(COALESCE(mr.interest_completed_derived, 0)) "
+ " + SUM(COALESCE(mr.fee_charges_completed_derived, 0)) "
+ "+ SUM(COALESCE(mr.penalty_charges_completed_derived, 0))) > 0";
@@ -2200,7 +2195,7 @@ public class LoanReadPlatformServiceImpl implements LoanReadPlatformService {
@Override
public Collection<Long> retrieveLoanIdsWithPendingIncomePostingTransactions() {
String currentdate = formatter.format(DateUtils.getLocalDateOfTenant());
LocalDate currentdate = DateUtils.getBusinessLocalDate();
StringBuilder sqlBuilder = new StringBuilder().append(" select distinct loan.id ").append(" from m_loan as loan ").append(
" inner join m_loan_recalculation_details as recdet on (recdet.loan_id = loan.id and recdet.is_compounding_to_be_posted_as_transaction is not null and recdet.is_compounding_to_be_posted_as_transaction = true) ")
.append(" inner join m_loan_repayment_schedule as repsch on repsch.loan_id = loan.id ")
@@ -2208,9 +2203,9 @@ public class LoanReadPlatformServiceImpl implements LoanReadPlatformService {
.append(" left join m_loan_transaction as trans on (trans.is_reversed <> true and trans.transaction_type_enum = 19 and trans.loan_id = loan.id and trans.transaction_date = adddet.effective_date) ")
.append(" where loan.loan_status_id = 300 ").append(" and loan.is_npa = false ")
.append(" and adddet.effective_date is not null ").append(" and trans.transaction_date is null ")
.append(" and adddet.effective_date < '" + currentdate + "' ");
.append(" and adddet.effective_date < ? ");
try {
return this.jdbcTemplate.queryForList(sqlBuilder.toString(), Long.class);
return this.jdbcTemplate.queryForList(sqlBuilder.toString(), new Object[] { currentdate }, Long.class);
} catch (final EmptyResultDataAccessException e) {
return null;
}
@@ -2227,7 +2222,7 @@ public class LoanReadPlatformServiceImpl implements LoanReadPlatformService {
final CurrencyData currencyData = applicationCurrency.toData();
final LocalDate earliestUnpaidInstallmentDate = DateUtils.getLocalDateOfTenant();
final LocalDate earliestUnpaidInstallmentDate = DateUtils.getBusinessLocalDate();
final LoanRepaymentScheduleInstallment loanRepaymentScheduleInstallment = loan.fetchLoanForeclosureDetail(transactionDate);
BigDecimal unrecognizedIncomePortion = null;
@@ -2377,13 +2372,15 @@ public class LoanReadPlatformServiceImpl implements LoanReadPlatformService {
sqlBuilder.append(
"l.id as loanId, coalesce((l.approved_principal - l.principal_disbursed_derived), 0) as availableDisbursementAmount, ");
sqlBuilder.append(sqlGenerator.dateDiff(sqlGenerator.currentDate(), "laa.overdue_since_date_derived") + " as pastDueDays, ");
sqlBuilder.append(
sqlGenerator.dateDiff(sqlGenerator.currentBusinessDate(), "laa.overdue_since_date_derived") + " as pastDueDays, ");
sqlBuilder.append(
"(select coalesce(min(lrs.duedate), null) as duedate from m_loan_repayment_schedule lrs where lrs.loan_id=l.id and lrs.completed_derived is false and lrs.duedate >= "
+ sqlGenerator.currentDate() + ") as nextPaymentDueDate, ");
sqlBuilder.append(sqlGenerator.dateDiff(sqlGenerator.currentDate(), "laa.overdue_since_date_derived") + " as delinquentDays, ");
+ sqlGenerator.currentBusinessDate() + ") as nextPaymentDueDate, ");
sqlBuilder.append(
sqlGenerator.currentDate() + " as delinquentDate, coalesce(laa.total_overdue_derived, 0) as delinquentAmount, ");
sqlGenerator.dateDiff(sqlGenerator.currentBusinessDate(), "laa.overdue_since_date_derived") + " as delinquentDays, ");
sqlBuilder.append(sqlGenerator.currentBusinessDate()
+ " as delinquentDate, coalesce(laa.total_overdue_derived, 0) as delinquentAmount, ");
sqlBuilder.append("lre.transactionDate as lastPaymentDate, coalesce(lre.amount, 0) as lastPaymentAmount ");
sqlBuilder.append("from m_loan l left join m_loan_arrears_aging laa on laa.loan_id = l.id ");
sqlBuilder.append(
@@ -587,7 +587,7 @@ public class LoanWritePlatformServiceJpaRepositoryImpl implements LoanWritePlatf
final Integer instructionType = StandingInstructionType.DUES.getValue();
final Integer status = StandingInstructionStatus.ACTIVE.getValue();
final Integer recurrenceType = AccountTransferRecurrenceType.AS_PER_DUES.getValue();
final LocalDate validFrom = LocalDate.now(DateUtils.getDateTimeZoneOfTenant());
final LocalDate validFrom = DateUtils.getBusinessLocalDate();
AccountTransferDetails accountTransferDetails = AccountTransferDetails.savingsToLoanTransfer(fromOffice, fromClient,
linkedSavingsAccount, toOffice, toClient, loan, transferType);
@@ -1619,7 +1619,7 @@ public class LoanWritePlatformServiceJpaRepositoryImpl implements LoanWritePlatf
this.loanTransactionRepository.saveAndFlush(applyLoanChargeTransaction);
}
boolean isAppliedOnBackDate = false;
if (loanCharge.getDueLocalDate() == null || DateUtils.getLocalDateOfTenant().isAfter(loanCharge.getDueLocalDate())) {
if (loanCharge.getDueLocalDate() == null || DateUtils.getBusinessLocalDate().isAfter(loanCharge.getDueLocalDate())) {
isAppliedOnBackDate = true;
}
return isAppliedOnBackDate;
@@ -2053,29 +2053,28 @@ public class LoanWritePlatformServiceJpaRepositoryImpl implements LoanWritePlatf
.retrieveInstallmentLoanCharges(chargeData.getId(), true);
PortfolioAccountData portfolioAccountData = null;
for (final LoanInstallmentChargeData installmentChargeData : chargePerInstallments) {
if (!installmentChargeData.getDueDate().isAfter(DateUtils.getLocalDateOfTenant())) {
if (!installmentChargeData.getDueDate().isAfter(DateUtils.getBusinessLocalDate())) {
if (portfolioAccountData == null) {
portfolioAccountData = this.accountAssociationsReadPlatformService
.retriveLoanLinkedAssociation(chargeData.getLoanId());
}
final SavingsAccount fromSavingsAccount = null;
final boolean isExceptionForBalanceCheck = false;
final AccountTransferDTO accountTransferDTO = new AccountTransferDTO(
LocalDate.now(DateUtils.getDateTimeZoneOfTenant()), installmentChargeData.getAmountOutstanding(),
PortfolioAccountType.SAVINGS, PortfolioAccountType.LOAN, portfolioAccountData.accountId(),
chargeData.getLoanId(), "Loan Charge Payment", null, null, null, null,
final AccountTransferDTO accountTransferDTO = new AccountTransferDTO(DateUtils.getBusinessLocalDate(),
installmentChargeData.getAmountOutstanding(), PortfolioAccountType.SAVINGS, PortfolioAccountType.LOAN,
portfolioAccountData.accountId(), chargeData.getLoanId(), "Loan Charge Payment", null, null, null, null,
LoanTransactionType.CHARGE_PAYMENT.getValue(), chargeData.getId(),
installmentChargeData.getInstallmentNumber(), AccountTransferType.CHARGE_PAYMENT.getValue(), null, null,
null, null, null, fromSavingsAccount, isRegularTransaction, isExceptionForBalanceCheck);
transferFeeCharge(accountTransferDTO, errors);
}
}
} else if (chargeData.getDueDate() != null && !chargeData.getDueDate().isAfter(DateUtils.getLocalDateOfTenant())) {
} else if (chargeData.getDueDate() != null && !chargeData.getDueDate().isAfter(DateUtils.getBusinessLocalDate())) {
final PortfolioAccountData portfolioAccountData = this.accountAssociationsReadPlatformService
.retriveLoanLinkedAssociation(chargeData.getLoanId());
final SavingsAccount fromSavingsAccount = null;
final boolean isExceptionForBalanceCheck = false;
final AccountTransferDTO accountTransferDTO = new AccountTransferDTO(LocalDate.now(DateUtils.getDateTimeZoneOfTenant()),
final AccountTransferDTO accountTransferDTO = new AccountTransferDTO(DateUtils.getBusinessLocalDate(),
chargeData.getAmountOutstanding(), PortfolioAccountType.SAVINGS, PortfolioAccountType.LOAN,
portfolioAccountData.accountId(), chargeData.getLoanId(), "Loan Charge Payment", null, null, null, null,
LoanTransactionType.CHARGE_PAYMENT.getValue(), chargeData.getId(), null,
@@ -2607,7 +2606,7 @@ public class LoanWritePlatformServiceJpaRepositoryImpl implements LoanWritePlatf
final List<Long> existingTransactionIds = new ArrayList<>();
final List<Long> existingReversedTransactionIds = new ArrayList<>();
boolean runInterestRecalculation = false;
LocalDate recalculateFrom = DateUtils.getLocalDateOfTenant();
LocalDate recalculateFrom = DateUtils.getBusinessLocalDate();
LocalDate lastChargeDate = null;
for (final OverdueLoanScheduleData overdueInstallment : overdueLoanScheduleDatas) {
@@ -2714,7 +2713,7 @@ public class LoanWritePlatformServiceJpaRepositoryImpl implements LoanWritePlatf
if (feeFrequency == null) {
scheduleDates.put(frequencyNunber++, startDate.minusDays(diff));
} else {
while (!startDate.isAfter(DateUtils.getLocalDateOfTenant())) {
while (!startDate.isAfter(DateUtils.getBusinessLocalDate())) {
scheduleDates.put(frequencyNunber++, startDate.minusDays(diff));
LocalDate scheduleDate = scheduledDateGenerator.getRepaymentPeriodDate(PeriodFrequencyType.fromInt(feeFrequency),
chargeDefinition.feeInterval(), startDate);
@@ -2739,7 +2738,7 @@ public class LoanWritePlatformServiceJpaRepositoryImpl implements LoanWritePlatf
installment = loan.fetchRepaymentScheduleInstallment(periodNumber);
lastChargeAppliedDate = installment.getDueDate();
}
LocalDate recalculateFrom = DateUtils.getLocalDateOfTenant();
LocalDate recalculateFrom = DateUtils.getBusinessLocalDate();
if (loan != null) {
businessEventNotifierService.notifyPreBusinessEvent(new LoanApplyOverdueChargeBusinessEvent(loan));
@@ -335,7 +335,7 @@ public class LoanProductReadPlatformServiceImpl implements LoanProductReadPlatfo
final LocalDate startDate = JdbcSupport.getLocalDate(rs, "startDate");
final LocalDate closeDate = JdbcSupport.getLocalDate(rs, "closeDate");
String status = "";
if (closeDate != null && closeDate.isBefore(DateUtils.getLocalDateOfTenant())) {
if (closeDate != null && closeDate.isBefore(DateUtils.getBusinessLocalDate())) {
status = "loanProduct.inActive";
} else {
status = "loanProduct.active";
@@ -499,7 +499,7 @@ public class LoanProductReadPlatformServiceImpl implements LoanProductReadPlatfo
}
public String activeOnlySchema() {
return schema() + " where (close_date is null or close_date >= " + sqlGenerator.currentDate() + ")";
return schema() + " where (close_date is null or close_date >= " + sqlGenerator.currentBusinessDate() + ")";
}
public String productMixSchema() {
@@ -130,7 +130,7 @@ public class MeetingsApiResource {
calendarData = this.calendarReadPlatformService.retrieveCalendar(calendarId, entityId, entityTypeId);
final boolean withHistory = true;
final Collection<LocalDate> recurringDates = this.calendarReadPlatformService.generateRecurringDates(calendarData, withHistory,
DateUtils.getLocalDateOfTenant());
DateUtils.getBusinessLocalDate());
final Collection<LocalDate> nextTenRecurringDates = this.calendarReadPlatformService
.generateNextTenRecurringDates(calendarData);
final LocalDate recentEligibleMeetingDate = null;
@@ -89,7 +89,7 @@ public class Meeting extends AbstractPersistableCustom {
public void associateClientsAttendance(final Collection<ClientAttendance> clientsAttendance) {
// do not allow to capture attendance in advance.
if (isMeetingDateAfter(DateUtils.getLocalDateOfTenant())) {
if (isMeetingDateAfter(DateUtils.getBusinessLocalDate())) {
final String errorMessage = "Attendance cannot be in the future.";
throw new MeetingDateException("cannot.be.a.future.date", errorMessage, getMeetingDateLocalDate());
}
@@ -234,7 +234,7 @@ public class SavingsAccountSummaryData implements Serializable {
public void updateFromInterestPeriodSummaries(final MonetaryCurrency currency, final List<PostingPeriod> allPostingPeriods) {
Money totalEarned = Money.zero(currency);
LocalDate interestCalculationDate = DateUtils.getLocalDateOfTenant();
LocalDate interestCalculationDate = DateUtils.getBusinessLocalDate();
for (final PostingPeriod period : allPostingPeriods) {
Money interestEarned = period.interest();
interestEarned = interestEarned == null ? Money.zero(currency) : interestEarned;
@@ -934,7 +934,7 @@ public final class SavingsAccountTransactionData implements Serializable {
public static SavingsAccountTransactionData withWithDrawalTransactionDetails(
final SavingsAccountTransactionData savingsAccountTransactionData) {
final LocalDate currentDate = DateUtils.getLocalDateOfTenant();
final LocalDate currentDate = DateUtils.getBusinessLocalDate();
final SavingsAccountTransactionEnumData transactionType = SavingsEnumerations
.transactionType(SavingsAccountTransactionType.WITHDRAWAL.getValue());
@@ -324,7 +324,7 @@ public class SavingsAccountTransactionDataValidator {
throwExceptionIfValidationWarningsExist(dataValidationErrors);
Date createdDate = new Date();
LocalDate transactionDate = DateUtils.getLocalDateOfTenant();
LocalDate transactionDate = DateUtils.getBusinessLocalDate();
SavingsAccountTransaction transaction = SavingsAccountTransaction.releaseAmount(holdTransaction, transactionDate, createdDate,
createdUser);
return transaction;
@@ -355,7 +355,7 @@ public class DepositAccountAssembler {
if (account != null) {
account.setHelpers(this.savingsAccountTransactionSummaryWrapper, this.savingsHelper);
account.validateNewApplicationState(DateUtils.getLocalDateOfTenant(), depositAccountType.resourceName());
account.validateNewApplicationState(DateUtils.getBusinessLocalDate(), depositAccountType.resourceName());
}
return account;
@@ -161,7 +161,7 @@ public class DepositAccountDomainServiceJpa implements DepositAccountDomainServi
account.handleScheduleInstallments(deposit);
account.updateMaturityDateAndAmount(mc, isPreMatureClosure, isSavingsInterestPostingAtCurrentPeriodEnd,
financialYearBeginningMonth);
account.updateOverduePayments(DateUtils.getLocalDateOfTenant());
account.updateOverduePayments(DateUtils.getBusinessLocalDate());
if (isAnyActivationChargesDue) {
postJournalEntries(account, existingTransactionIds, existingReversedTransactionIds, isAccountTransfer);
}
@@ -127,7 +127,7 @@ public class DepositAccountRecurringDetail extends AbstractPersistableCustom {
throw new PlatformApiDataValidationException(dataValidationErrors);
}
depositAccount.updateScheduleInstallmentsWithNewRecommendedDepositAmount(newMandatoryRecommendedDepositAmount, effectiveDate);
depositAccount.updateOverduePayments(DateUtils.getLocalDateOfTenant());
depositAccount.updateOverduePayments(DateUtils.getBusinessLocalDate());
MathContext mc = MathContext.DECIMAL64;
Boolean isPreMatureClosure = false;
depositAccount.updateMaturityDateAndAmount(mc, isPreMatureClosure, isSavingsInterestPostingAtCurrentPeriodEnd,
@@ -231,7 +231,7 @@ public class FixedDepositAccount extends SavingsAccount {
isSavingsInterestPostingAtCurrentPeriodEnd, financialYearBeginningMonth);
// reset end of day balance back to today's date
this.resetAccountTransactionsEndOfDayBalances(transactions, DateUtils.getLocalDateOfTenant());
this.resetAccountTransactionsEndOfDayBalances(transactions, DateUtils.getBusinessLocalDate());
Money totalInterestPayable = Money.zero(getCurrency());
for (PostingPeriod postingPeriod : postingPeriods) {
@@ -256,7 +256,7 @@ public class FixedDepositAccount extends SavingsAccount {
}
}
final LocalDate todayDate = DateUtils.getLocalDateOfTenant();
final LocalDate todayDate = DateUtils.getBusinessLocalDate();
if (!this.maturityDate().isAfter(todayDate)) {
// update account status
this.status = SavingsAccountStatusType.MATURED.getValue();
@@ -763,7 +763,7 @@ public class FixedDepositAccount extends SavingsAccount {
if (this.chart != null) {
final LocalDate chartFromDate = this.chart.getFromDateAsLocalDate();
LocalDate chartEndDate = this.chart.getEndDateAsLocalDate();
chartEndDate = chartEndDate == null ? DateUtils.getLocalDateOfTenant() : chartEndDate;
chartEndDate = chartEndDate == null ? DateUtils.getBusinessLocalDate() : chartEndDate;
final LocalDateInterval chartInterval = LocalDateInterval.create(chartFromDate, chartEndDate);
if (!chartInterval.contains(accountSubmittedOrActivationDate())) {
@@ -225,7 +225,7 @@ public class RecurringDepositAccount extends SavingsAccount {
}
if (depositCloseDate == null) {
depositCloseDate = DateUtils.getLocalDateOfTenant();
depositCloseDate = DateUtils.getBusinessLocalDate();
}
final BigDecimal depositAmount = accountTermAndPreClosure.depositAmount();
@@ -248,7 +248,7 @@ public class RecurringDepositAccount extends SavingsAccount {
LocalDate interestCalculationUpto = null;
List<SavingsAccountTransaction> allTransactions = null;
if (maturityDate == null) {
interestCalculationUpto = DateUtils.getLocalDateOfTenant();
interestCalculationUpto = DateUtils.getBusinessLocalDate();
allTransactions = getTransactions(interestCalculationUpto, false);
} else {
interestCalculationUpto = maturityDate.minusDays(1);
@@ -285,7 +285,7 @@ public class RecurringDepositAccount extends SavingsAccount {
}
}
final LocalDate todayDate = DateUtils.getLocalDateOfTenant();
final LocalDate todayDate = DateUtils.getBusinessLocalDate();
if (!this.maturityDate().isAfter(todayDate)) {
// update account status
this.status = SavingsAccountStatusType.MATURED.getValue();
@@ -549,7 +549,7 @@ public class RecurringDepositAccount extends SavingsAccount {
// update existing transactions so derived balance fields are
// correct.
recalculateDailyBalances(Money.zero(this.currency), DateUtils.getLocalDateOfTenant(), backdatedTxnsAllowedTill);
recalculateDailyBalances(Money.zero(this.currency), DateUtils.getBusinessLocalDate(), backdatedTxnsAllowedTill);
}
}
@@ -1059,7 +1059,7 @@ public class RecurringDepositAccount extends SavingsAccount {
if (this.chart != null) {
final LocalDate chartFromDate = this.chart.getFromDateAsLocalDate();
LocalDate chartEndDate = this.chart.getEndDateAsLocalDate();
chartEndDate = chartEndDate == null ? DateUtils.getLocalDateOfTenant() : chartEndDate;
chartEndDate = chartEndDate == null ? DateUtils.getBusinessLocalDate() : chartEndDate;
final LocalDateInterval chartInterval = LocalDateInterval.create(chartFromDate, chartEndDate);
if (!chartInterval.contains(accountSubmittedOrActivationDate())) {
@@ -1067,7 +1067,7 @@ public class RecurringDepositAccount extends SavingsAccount {
}
if (maturityDate == null) {
maturityDate = DateUtils.getLocalDateOfTenant();
maturityDate = DateUtils.getBusinessLocalDate();
}
final BigDecimal maturityAmount = this.accountTermAndPreClosure.depositAmount();
@@ -1199,7 +1199,7 @@ public class RecurringDepositAccount extends SavingsAccount {
private LocalDate calcualteScheduleTillDate(final PeriodFrequencyType frequency, final Integer recurringEvery) {
LocalDate tillDate = calculateMaturityDate();
if (tillDate == null) {
final LocalDate today = DateUtils.getLocalDateOfTenant();
final LocalDate today = DateUtils.getBusinessLocalDate();
tillDate = DepositAccountUtils.calculateNextDepositDate(today, frequency,
recurringEvery * (DepositAccountUtils.GENERATE_MINIMUM_NUMBER_OF_FUTURE_INSTALMENTS + 1));
}
@@ -1309,23 +1309,16 @@ public class SavingsAccount extends AbstractPersistableCustom {
Integer restartPeriod = charge.getRestartFrequency();
if (charge.getRestartFrequencyEnum() == 2) { // calculation for months
Date currentDate = new Date();
LocalDate localDate = currentDate.toInstant().atZone(ZoneId.systemDefault()).toLocalDate();
Integer currentMonth = localDate.getMonthValue();
LocalDate localDate = DateUtils.getBusinessLocalDate();
LocalDate resetLocalDate = null;
LocalDate resetLocalDate;
if (resetDate == null) {
resetLocalDate = this.activatedOnDate.toInstant().atZone(ZoneId.systemDefault()).toLocalDate();
} else {
resetLocalDate = resetDate.toInstant().atZone(ZoneId.systemDefault()).toLocalDate();
}
Integer resetMonth = resetLocalDate.getMonthValue();
LocalDate gapIntervalMonth = resetLocalDate.plusMonths(restartPeriod);
Integer gapMonth = gapIntervalMonth.getMonthValue();
Integer resetYear = resetLocalDate.getYear();
Integer currentYear = localDate.getYear();
YearMonth gapYearMonth = YearMonth.from(gapIntervalMonth);
YearMonth localYearMonth = YearMonth.from(localDate);
@@ -1335,18 +1328,18 @@ public class SavingsAccount extends AbstractPersistableCustom {
discountCharge(1, charge);
}
} else { // calculation for days
Long completedDays = null;
Long days = null;
Long completedDays;
Long days;
if (resetDate == null) {
completedDays = DateUtils.getDateOfTenant().getTime() - this.activatedOnDate.getTime();
completedDays = DateUtils.getBusinessDate().getTime() - this.activatedOnDate.getTime();
days = TimeUnit.DAYS.convert(completedDays, TimeUnit.MILLISECONDS);
} else {
completedDays = DateUtils.getDateOfTenant().getTime() - resetDate.getTime();
completedDays = DateUtils.getBusinessDate().getTime() - resetDate.getTime();
days = TimeUnit.DAYS.convert(completedDays, TimeUnit.MILLISECONDS);
}
Integer totalDays = days.intValue();
int totalDays = days.intValue();
if (totalDays < restartPeriod) {
countValidation(charge, transactionAmount, transactionDate, user, refNo);
@@ -1371,7 +1364,7 @@ public class SavingsAccount extends AbstractPersistableCustom {
private void discountCharge(Integer freeWithdrawalCount, SavingsAccountCharge charge) {
charge.setFreeWithdrawalCount(freeWithdrawalCount);
charge.setDiscountDueDate(DateUtils.getDateOfTenant());
charge.setDiscountDueDate(DateUtils.getBusinessDate());
charge.updateNoWithdrawalFee();
}
@@ -1572,7 +1565,7 @@ public class SavingsAccount extends AbstractPersistableCustom {
}
private boolean isDateInTheFuture(final LocalDate transactionDate) {
return transactionDate.isAfter(DateUtils.getLocalDateOfTenant());
return transactionDate.isAfter(DateUtils.getBusinessLocalDate());
}
public BigDecimal getAccountBalance() {
@@ -2067,7 +2060,7 @@ public class SavingsAccount extends AbstractPersistableCustom {
throw new SavingsOfficerAssignmentDateException("cannot.be.before.previous.unassignement.date", errorMessage, assignmentDate,
lastAssignmentRecord.getEndDate());
} else if (DateUtils.getLocalDateOfTenant().isBefore(assignmentDate)) {
} else if (DateUtils.getBusinessLocalDate().isBefore(assignmentDate)) {
final String errorMessage = "The Savings Officer assignment date (" + assignmentDate + ") cannot be in the future.";
@@ -2164,7 +2157,7 @@ public class SavingsAccount extends AbstractPersistableCustom {
private void validateUnassignDate(final SavingsOfficerAssignmentHistory latestHistoryRecord, final LocalDate unassignDate) {
final LocalDate today = DateUtils.getLocalDateOfTenant();
final LocalDate today = DateUtils.getBusinessLocalDate();
if (latestHistoryRecord.getStartDate().isAfter(unassignDate)) {
@@ -2768,12 +2761,12 @@ public class SavingsAccount extends AbstractPersistableCustom {
boolean isInterestTransfer = false;
LocalDate postInterestAsOnDate = null;
if (this.isBeforeLastPostingPeriod(getActivationLocalDate(), backdatedTxnsAllowedTill)) {
final LocalDate today = DateUtils.getLocalDateOfTenant();
final LocalDate today = DateUtils.getBusinessLocalDate();
boolean postReversals = false;
this.postInterest(mc, today, isInterestTransfer, isSavingsInterestPostingAtCurrentPeriodEnd, financialYearBeginningMonth,
postInterestAsOnDate, backdatedTxnsAllowedTill, postReversals);
} else {
final LocalDate today = DateUtils.getLocalDateOfTenant();
final LocalDate today = DateUtils.getBusinessLocalDate();
this.calculateInterestUsing(mc, today, isInterestTransfer, isSavingsInterestPostingAtCurrentPeriodEnd,
financialYearBeginningMonth, postInterestAsOnDate, backdatedTxnsAllowedTill);
}
@@ -3236,7 +3229,7 @@ public class SavingsAccount extends AbstractPersistableCustom {
private void handleWaiverChargeTransactions(SavingsAccountCharge savingsAccountCharge, Money transactionAmount, AppUser user,
boolean backdatedTxnsAllowedTill) {
final SavingsAccountTransaction chargeTransaction = SavingsAccountTransaction.waiver(this, office(),
DateUtils.getLocalDateOfTenant(), transactionAmount, user);
DateUtils.getBusinessLocalDate(), transactionAmount, user);
handleChargeTransactions(savingsAccountCharge, chargeTransaction, backdatedTxnsAllowedTill);
}
@@ -3511,7 +3504,7 @@ public class SavingsAccount extends AbstractPersistableCustom {
public void setSubStatusInactive(AppUser appUser, final boolean backdatedTxnsAllowedTill) {
this.sub_status = SavingsAccountSubStatusEnum.INACTIVE.getValue();
LocalDate transactionDate = DateUtils.getLocalDateOfTenant();
LocalDate transactionDate = DateUtils.getBusinessLocalDate();
for (SavingsAccountCharge charge : this.charges()) {
if (charge.isSavingsNoActivity() && charge.isActive()) {
charge.updateWithdralFeeAmount(this.getAccountBalance());
@@ -3531,10 +3524,10 @@ public class SavingsAccount extends AbstractPersistableCustom {
public void escheat(AppUser appUser) {
this.status = SavingsAccountStatusType.CLOSED.getValue();
this.sub_status = SavingsAccountSubStatusEnum.ESCHEAT.getValue();
this.closedOnDate = DateUtils.getDateOfTenant();
this.closedOnDate = DateUtils.getBusinessDate();
this.closedBy = appUser;
boolean postInterestAsOnDate = false;
LocalDate transactionDate = DateUtils.getLocalDateOfTenant();
LocalDate transactionDate = DateUtils.getBusinessLocalDate();
if (this.getSummary().getAccountBalance(this.getCurrency()).isGreaterThanZero()) {
SavingsAccountTransaction transaction = SavingsAccountTransaction.escheat(this, transactionDate, appUser, postInterestAsOnDate);
this.transactions.add(transaction);
@@ -326,7 +326,7 @@ public class SavingsAccountAssembler {
nominalAnnualInterestRateOverdraft, minOverdraftForInterestCalculation, withHoldTax);
account.setHelpers(this.savingsAccountTransactionSummaryWrapper, this.savingsHelper);
account.validateNewApplicationState(DateUtils.getLocalDateOfTenant(), SAVINGS_ACCOUNT_RESOURCE_NAME);
account.validateNewApplicationState(DateUtils.getBusinessLocalDate(), SAVINGS_ACCOUNT_RESOURCE_NAME);
account.validateAccountValuesWithProduct();
@@ -444,7 +444,7 @@ public class SavingsAccountAssembler {
product.withHoldTax());
account.setHelpers(this.savingsAccountTransactionSummaryWrapper, this.savingsHelper);
account.validateNewApplicationState(DateUtils.getLocalDateOfTenant(), SAVINGS_ACCOUNT_RESOURCE_NAME);
account.validateNewApplicationState(DateUtils.getBusinessLocalDate(), SAVINGS_ACCOUNT_RESOURCE_NAME);
account.validateAccountValuesWithProduct();
@@ -114,13 +114,12 @@ public class SavingsAccountDomainServiceJpa implements SavingsAccountDomainServi
backdatedTxnsAllowedTill, refNo.toString());
final MathContext mc = MathContext.DECIMAL64;
final LocalDate today = DateUtils.getBusinessLocalDate();
if (account.isBeforeLastPostingPeriod(transactionDate, backdatedTxnsAllowedTill)) {
final LocalDate today = DateUtils.getLocalDateOfTenant();
boolean postReversals = false;
account.postInterest(mc, today, transactionBooleanValues.isInterestTransfer(), isSavingsInterestPostingAtCurrentPeriodEnd,
financialYearBeginningMonth, postInterestOnDate, backdatedTxnsAllowedTill, postReversals);
} else {
final LocalDate today = DateUtils.getLocalDateOfTenant();
account.calculateInterestUsing(mc, today, transactionBooleanValues.isInterestTransfer(),
isSavingsInterestPostingAtCurrentPeriodEnd, financialYearBeginningMonth, postInterestOnDate, backdatedTxnsAllowedTill);
}
@@ -196,13 +195,12 @@ public class SavingsAccountDomainServiceJpa implements SavingsAccountDomainServi
final LocalDate postInterestOnDate = null;
final MathContext mc = MathContext.DECIMAL64;
final LocalDate today = DateUtils.getBusinessLocalDate();
if (account.isBeforeLastPostingPeriod(transactionDate, backdatedTxnsAllowedTill)) {
final LocalDate today = DateUtils.getLocalDateOfTenant();
boolean postReversals = false;
account.postInterest(mc, today, isInterestTransfer, isSavingsInterestPostingAtCurrentPeriodEnd, financialYearBeginningMonth,
postInterestOnDate, backdatedTxnsAllowedTill, postReversals);
} else {
final LocalDate today = DateUtils.getLocalDateOfTenant();
account.calculateInterestUsing(mc, today, isInterestTransfer, isSavingsInterestPostingAtCurrentPeriodEnd,
financialYearBeginningMonth, postInterestOnDate, backdatedTxnsAllowedTill);
}
@@ -315,7 +313,7 @@ public class SavingsAccountDomainServiceJpa implements SavingsAccountDomainServi
boolean isInterestTransfer = false;
LocalDate postInterestOnDate = null;
final LocalDate today = DateUtils.getLocalDateOfTenant();
final LocalDate today = DateUtils.getBusinessLocalDate();
final MathContext mc = new MathContext(15, MoneyHelper.getRoundingMode());
for (SavingsAccountTransaction savingsAccountTransaction : savingsAccountTransactions) {
if (savingsAccountTransaction.isPostInterestCalculationRequired()
@@ -241,7 +241,7 @@ public final class SavingsAccountSummary {
public void updateFromInterestPeriodSummaries(final MonetaryCurrency currency, final List<PostingPeriod> allPostingPeriods) {
Money totalEarned = Money.zero(currency);
LocalDate interestCalculationDate = DateUtils.getLocalDateOfTenant();
LocalDate interestCalculationDate = DateUtils.getBusinessLocalDate();
for (final PostingPeriod period : allPostingPeriods) {
Money interestEarned = period.interest();
interestEarned = interestEarned == null ? Money.zero(currency) : interestEarned;

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