FINERACT-1955: Timezone handling of Savings account

This commit is contained in:
jmarta
2023-10-24 16:00:57 +02:00
committed by Adam Saghy
parent 6cb8ae0ed3
commit 71afd6dead
74 changed files with 1584 additions and 1431 deletions
@@ -67,7 +67,7 @@ public abstract class AbstractAuditableCustom extends AbstractPersistableCustom
@Override
public Optional<LocalDateTime> getCreatedDate() {
return null == this.createdDate ? Optional.empty() : Optional.of(this.createdDate);
return Optional.ofNullable(this.createdDate);
}
@Override
@@ -87,7 +87,7 @@ public abstract class AbstractAuditableCustom extends AbstractPersistableCustom
@Override
public Optional<LocalDateTime> getLastModifiedDate() {
return null == this.lastModifiedDate ? Optional.empty() : Optional.of(this.lastModifiedDate);
return Optional.ofNullable(this.lastModifiedDate);
}
@Override
@@ -25,8 +25,10 @@ import static org.apache.fineract.infrastructure.core.domain.AuditableFieldsCons
import jakarta.persistence.Column;
import jakarta.persistence.MappedSuperclass;
import jakarta.validation.constraints.NotNull;
import java.time.OffsetDateTime;
import java.util.Optional;
import lombok.AccessLevel;
import lombok.Getter;
import lombok.NoArgsConstructor;
import lombok.Setter;
@@ -44,7 +46,7 @@ import org.springframework.data.jpa.domain.AbstractAuditable;
@MappedSuperclass
@Getter
@Setter
@NoArgsConstructor
@NoArgsConstructor(access = AccessLevel.PROTECTED)
public abstract class AbstractAuditableWithUTCDateTimeCustom extends AbstractPersistableCustom
implements Auditable<Long, Long, OffsetDateTime> {
@@ -67,33 +69,36 @@ public abstract class AbstractAuditableWithUTCDateTimeCustom extends AbstractPer
private OffsetDateTime lastModifiedDate;
@Override
@NotNull
public Optional<Long> getCreatedBy() {
return Optional.ofNullable(this.createdBy);
}
@Override
@NotNull
public Optional<OffsetDateTime> getCreatedDate() {
if (this.createdDate == null) {
return Optional.empty();
} else {
return Optional.of(this.createdDate
.withOffsetSameInstant(DateUtils.getDateTimeZoneOfTenant().getRules().getOffset(this.createdDate.toInstant())));
}
return Optional.ofNullable(createdDate);
}
@NotNull
public OffsetDateTime getCreatedDateTime() {
return getCreatedDate().orElseGet(DateUtils::getAuditOffsetDateTime);
}
@Override
@NotNull
public Optional<Long> getLastModifiedBy() {
return Optional.ofNullable(this.lastModifiedBy);
}
@Override
@NotNull
public Optional<OffsetDateTime> getLastModifiedDate() {
if (this.lastModifiedDate == null) {
return Optional.empty();
} else {
return Optional.of(this.lastModifiedDate
.withOffsetSameInstant(DateUtils.getDateTimeZoneOfTenant().getRules().getOffset(this.lastModifiedDate.toInstant())));
}
return Optional.ofNullable(lastModifiedDate);
}
@NotNull
public OffsetDateTime getLastModifiedDateTime() {
return getLastModifiedDate().orElseGet(DateUtils::getAuditOffsetDateTime);
}
}
@@ -20,6 +20,7 @@ package org.apache.fineract.infrastructure.core.service;
import static java.time.temporal.ChronoUnit.DAYS;
import jakarta.validation.constraints.NotNull;
import java.time.LocalDate;
import java.time.LocalDateTime;
import java.time.OffsetDateTime;
@@ -33,7 +34,6 @@ import java.util.Locale;
import org.apache.fineract.infrastructure.core.data.ApiParameterError;
import org.apache.fineract.infrastructure.core.domain.FineractPlatformTenant;
import org.apache.fineract.infrastructure.core.exception.PlatformApiDataValidationException;
import org.jetbrains.annotations.NotNull;
public final class DateUtils {
@@ -46,6 +46,8 @@ public final class DateUtils {
}
// DateTime
public static ZoneId getSystemZoneId() {
return ZoneId.systemDefault();
}
@@ -56,27 +58,38 @@ public final class DateUtils {
}
public static LocalDate getLocalDateOfTenant() {
final ZoneId zone = getDateTimeZoneOfTenant();
return LocalDate.now(zone);
return LocalDate.now(getDateTimeZoneOfTenant());
}
public static LocalDateTime getLocalDateTimeOfTenant() {
final ZoneId zone = getDateTimeZoneOfTenant();
return LocalDateTime.now(zone).truncatedTo(ChronoUnit.SECONDS);
return getLocalDateTimeOfTenant(null);
}
public static OffsetDateTime getOffsetDateTimeOfTenant() {
final ZoneId zone = getDateTimeZoneOfTenant();
return OffsetDateTime.now(zone).truncatedTo(ChronoUnit.SECONDS);
public static LocalDateTime getLocalDateTimeOfTenant(ChronoUnit truncate) {
LocalDateTime now = LocalDateTime.now(getDateTimeZoneOfTenant());
return truncate == null ? now : now.truncatedTo(truncate);
}
public static OffsetDateTime getOffsetDateTimeOfTenantWithMostPrecision() {
final ZoneId zone = getDateTimeZoneOfTenant();
return OffsetDateTime.now(zone);
return getOffsetDateTimeOfTenant(null);
}
public static OffsetDateTime getOffsetDateTimeOfTenant() {
return getOffsetDateTimeOfTenant(null);
}
public static OffsetDateTime getOffsetDateTimeOfTenant(ChronoUnit truncate) {
OffsetDateTime now = OffsetDateTime.now(getDateTimeZoneOfTenant());
return truncate == null ? now : now.truncatedTo(truncate);
}
public static LocalDateTime getLocalDateTimeOfSystem() {
return LocalDateTime.now(ZoneId.systemDefault()).truncatedTo(ChronoUnit.SECONDS);
return getLocalDateTimeOfSystem(null);
}
public static LocalDateTime getLocalDateTimeOfSystem(ChronoUnit truncate) {
LocalDateTime now = LocalDateTime.now(ZoneId.systemDefault());
return truncate == null ? now : now.truncatedTo(truncate);
}
public static LocalDateTime getAuditLocalDateTime() {
@@ -87,22 +100,176 @@ public final class DateUtils {
return OffsetDateTime.now(ZoneOffset.UTC);
}
public static boolean isDateInTheFuture(final LocalDate localDate) {
return localDate.isAfter(getBusinessLocalDate());
public static int compare(LocalDateTime first, LocalDateTime second) {
return compare(first, second, null);
}
public static int compare(LocalDateTime first, LocalDateTime second, ChronoUnit truncate) {
if (first == null) {
return second == null ? 0 : -1;
}
if (second == null) {
return 1;
}
return truncate == null ? first.compareTo(second) : first.truncatedTo(truncate).compareTo(second.truncatedTo(truncate));
}
public static boolean isEqual(LocalDateTime first, LocalDateTime second) {
return isEqual(first, second, null);
}
public static boolean isEqual(LocalDateTime first, LocalDateTime second, ChronoUnit truncate) {
return compare(first, second, truncate) == 0;
}
public static boolean isEqualTenantDateTime(LocalDateTime dateTime) {
return isEqualTenantDateTime(dateTime, null);
}
public static boolean isEqualTenantDateTime(LocalDateTime dateTime, ChronoUnit truncate) {
return isEqual(dateTime, getLocalDateTimeOfTenant(), truncate);
}
public static boolean isEqualSystemDateTime(LocalDateTime dateTime) {
return isEqualSystemDateTime(dateTime, null);
}
public static boolean isEqualSystemDateTime(LocalDateTime dateTime, ChronoUnit truncate) {
return isEqual(dateTime, getLocalDateTimeOfSystem(), truncate);
}
public static boolean isBefore(LocalDateTime first, LocalDateTime second) {
return isBefore(first, second, null);
}
public static boolean isBefore(LocalDateTime first, LocalDateTime second, ChronoUnit truncate) {
return compare(first, second, truncate) < 0;
}
public static boolean isBeforeTenantDateTime(LocalDateTime dateTime) {
return isBeforeTenantDateTime(dateTime, null);
}
public static boolean isBeforeTenantDateTime(LocalDateTime dateTime, ChronoUnit truncate) {
return isBefore(dateTime, getLocalDateTimeOfTenant(), truncate);
}
public static boolean isBeforeSystemDateTime(LocalDateTime dateTime) {
return isBeforeSystemDateTime(dateTime, null);
}
public static boolean isBeforeSystemDateTime(LocalDateTime dateTime, ChronoUnit truncate) {
return isBefore(dateTime, getLocalDateTimeOfSystem(), truncate);
}
public static boolean isAfter(LocalDateTime first, LocalDateTime second) {
return isAfter(first, second, null);
}
public static boolean isAfter(LocalDateTime first, LocalDateTime second, ChronoUnit truncate) {
return compare(first, second, truncate) > 0;
}
public static boolean isAfterTenantDateTime(LocalDateTime dateTime) {
return isAfterTenantDateTime(dateTime, null);
}
public static boolean isAfterTenantDateTime(LocalDateTime dateTime, ChronoUnit truncate) {
return isAfter(dateTime, getLocalDateTimeOfTenant(), truncate);
}
public static boolean isAfterSystemDateTime(LocalDateTime dateTime) {
return isAfterSystemDateTime(dateTime, null);
}
public static boolean isAfterSystemDateTime(LocalDateTime dateTime, ChronoUnit truncate) {
return isAfter(dateTime, getLocalDateTimeOfSystem(), truncate);
}
public static int compare(OffsetDateTime first, OffsetDateTime second) {
return compare(first, second, null);
}
public static int compare(OffsetDateTime first, OffsetDateTime second, ChronoUnit truncate) {
if (first == null) {
return second == null ? 0 : -1;
}
if (second == null) {
return 1;
}
return truncate == null ? first.compareTo(second) : first.truncatedTo(truncate).compareTo(second.truncatedTo(truncate));
}
public static boolean isEqual(OffsetDateTime first, OffsetDateTime second) {
return isEqual(first, second, null);
}
public static boolean isEqual(OffsetDateTime first, OffsetDateTime second, ChronoUnit truncate) {
return compare(first, second, truncate) == 0;
}
public static boolean isEqualTenantDateTime(OffsetDateTime dateTime) {
return isEqualTenantDateTime(dateTime, null);
}
public static boolean isEqualTenantDateTime(OffsetDateTime dateTime, ChronoUnit truncate) {
return isEqual(dateTime, getOffsetDateTimeOfTenant(), truncate);
}
public static boolean isBefore(OffsetDateTime first, OffsetDateTime second) {
return isBefore(first, second, null);
}
public static boolean isBefore(OffsetDateTime first, OffsetDateTime second, ChronoUnit truncate) {
return compare(first, second, truncate) < 0;
}
public static boolean isBeforeTenantDateTime(OffsetDateTime dateTime) {
return isBeforeTenantDateTime(dateTime, null);
}
public static boolean isBeforeTenantDateTime(OffsetDateTime dateTime, ChronoUnit truncate) {
return isBefore(dateTime, getOffsetDateTimeOfTenant(), truncate);
}
public static boolean isAfter(OffsetDateTime first, OffsetDateTime second) {
return isAfter(first, second, null);
}
public static boolean isAfter(OffsetDateTime first, OffsetDateTime second, ChronoUnit truncate) {
return compare(first, second, truncate) > 0;
}
public static boolean isAfterTenantDateTime(OffsetDateTime dateTime) {
return isAfterTenantDateTime(dateTime, null);
}
public static boolean isAfterTenantDateTime(OffsetDateTime dateTime, ChronoUnit truncate) {
return isAfter(dateTime, getOffsetDateTimeOfTenant(), truncate);
}
// Date
public static LocalDate getBusinessLocalDate() {
return ThreadLocalContextUtil.getBusinessDate();
}
public static long getDifferenceInDays(final LocalDate localDateBefore, final LocalDate localDateAfter) {
return DAYS.between(localDateBefore, localDateAfter);
}
public static int compareToBusinessDate(LocalDate date) {
return compare(date, getBusinessLocalDate());
}
public static boolean isEqualTenantDate(LocalDate date) {
return isEqual(date, getLocalDateOfTenant());
}
public static boolean isBeforeTenantDate(LocalDate date) {
return isBefore(date, getLocalDateOfTenant());
}
public static boolean isAfterTenantDate(LocalDate date) {
return isAfter(date, getLocalDateOfTenant());
}
public static boolean isEqualBusinessDate(LocalDate date) {
return isEqual(date, getBusinessLocalDate());
}
@@ -115,8 +282,12 @@ public final class DateUtils {
return isAfter(date, getBusinessLocalDate());
}
public static boolean isDateInTheFuture(final LocalDate localDate) {
return isAfterBusinessDate(localDate);
}
public static int compare(LocalDate first, LocalDate second) {
return first == null ? (second == null ? 0 : -1) : first.compareTo(second);
return first == null ? (second == null ? 0 : -1) : (second == null ? 1 : first.compareTo(second));
}
public static boolean isEqual(LocalDate first, LocalDate second) {
@@ -131,6 +302,12 @@ public final class DateUtils {
return first != null && (second == null || first.isAfter(second));
}
public static long getDifferenceInDays(final LocalDate localDateBefore, final LocalDate localDateAfter) {
return DAYS.between(localDateBefore, localDateAfter);
}
// Parse, format
public static LocalDate parseLocalDate(String stringDate) {
return parseLocalDate(stringDate, null);
}
@@ -259,7 +259,7 @@ public final class Group extends AbstractPersistableCustom {
}
public boolean isActivatedAfter(final LocalDate submittedOn) {
return getActivationLocalDate().isAfter(submittedOn);
return DateUtils.isAfter(getActivationDate(), submittedOn);
}
public boolean isNotActive() {
@@ -267,11 +267,7 @@ public final class Group extends AbstractPersistableCustom {
}
public boolean isActive() {
return this.status != null ? GroupingTypeStatus.fromInt(this.status).isActive() : false;
}
private boolean isDateInTheFuture(final LocalDate localDate) {
return localDate.isAfter(DateUtils.getBusinessLocalDate());
return this.status != null && GroupingTypeStatus.fromInt(this.status).isActive();
}
public boolean isNotPending() {
@@ -316,7 +312,7 @@ public final class Group extends AbstractPersistableCustom {
final String dateFormatAsInput = command.dateFormat();
final String localeAsInput = command.locale();
if (command.isChangeInLocalDateParameterNamed(GroupingTypesApiConstants.activationDateParamName, getActivationLocalDate())) {
if (command.isChangeInLocalDateParameterNamed(GroupingTypesApiConstants.activationDateParamName, getActivationDate())) {
final String valueAsInput = command.stringValueOfParameterNamed(GroupingTypesApiConstants.activationDateParamName);
actualChanges.put(GroupingTypesApiConstants.activationDateParamName, valueAsInput);
actualChanges.put(GroupingTypesApiConstants.dateFormatParamName, dateFormatAsInput);
@@ -347,7 +343,7 @@ public final class Group extends AbstractPersistableCustom {
return this.submittedOnDate;
}
public LocalDate getActivationLocalDate() {
public LocalDate getActivationDate() {
return this.activationDate;
}
@@ -494,7 +490,7 @@ public final class Group extends AbstractPersistableCustom {
}
public boolean isChildGroup() {
return this.parent == null ? false : true;
return this.parent != null;
}
@@ -503,18 +499,17 @@ public final class Group extends AbstractPersistableCustom {
}
public void close(final AppUser currentUser, final CodeValue closureReason, final LocalDate closureDate) {
if (isClosed()) {
final String errorMessage = "Group with identifier " + getId() + " is alread closed.";
throw new InvalidGroupStateTransitionException(this.groupLevel.getLevelName(), "close", "already.closed", errorMessage,
getId());
}
if (isNotPending() && getActivationLocalDate().isAfter(closureDate)) {
if (isNotPending() && DateUtils.isAfter(getActivationDate(), closureDate)) {
final String errorMessage = "The Group closure Date " + closureDate + " cannot be before the group Activation Date "
+ getActivationLocalDate() + ".";
+ getActivationDate() + ".";
throw new InvalidGroupStateTransitionException(this.groupLevel.getLevelName(), "close",
"date.cannot.before.group.actvation.date", errorMessage, closureDate, getActivationLocalDate());
"date.cannot.before.group.actvation.date", errorMessage, closureDate, getActivationDate());
}
this.closureReason = closureReason;
@@ -644,9 +639,7 @@ public final class Group extends AbstractPersistableCustom {
}
private void validateActivationDate(final List<ApiParameterError> dataValidationErrors) {
if (getSubmittedOnDate() != null && isDateInTheFuture(getSubmittedOnDate())) {
if (getSubmittedOnDate() != null && DateUtils.isDateInTheFuture(getSubmittedOnDate())) {
final String defaultUserMessage = "Submitted on date cannot be in the future.";
final String globalisationMessageCode = "error.msg.group.submittedOnDate.in.the.future";
final ApiParameterError error = ApiParameterError.parameterError(globalisationMessageCode, defaultUserMessage,
@@ -654,31 +647,26 @@ public final class Group extends AbstractPersistableCustom {
dataValidationErrors.add(error);
}
if (getActivationLocalDate() != null && getSubmittedOnDate() != null && getSubmittedOnDate().isAfter(getActivationLocalDate())) {
if (getActivationDate() != null && DateUtils.isAfter(getSubmittedOnDate(), getActivationDate())) {
final String defaultUserMessage = "Submitted on date cannot be after the activation date";
final ApiParameterError error = ApiParameterError.parameterError("error.msg.group.submittedOnDate.after.activation.date",
defaultUserMessage, GroupingTypesApiConstants.submittedOnDateParamName, this.submittedOnDate);
dataValidationErrors.add(error);
}
if (getActivationLocalDate() != null && isDateInTheFuture(getActivationLocalDate())) {
if (getActivationDate() != null && DateUtils.isDateInTheFuture(getActivationDate())) {
final String defaultUserMessage = "Activation date cannot be in the future.";
final ApiParameterError error = ApiParameterError.parameterError("error.msg.group.activationDate.in.the.future",
defaultUserMessage, GroupingTypesApiConstants.activationDateParamName, getActivationLocalDate());
defaultUserMessage, GroupingTypesApiConstants.activationDateParamName, getActivationDate());
dataValidationErrors.add(error);
}
if (getActivationLocalDate() != null) {
if (this.office.isOpeningDateAfter(getActivationLocalDate())) {
if (getActivationDate() != null) {
if (this.office.isOpeningDateAfter(getActivationDate())) {
final String defaultUserMessage = "Activation date cannot be a date before the office opening date.";
final ApiParameterError error = ApiParameterError.parameterError(
"error.msg.group.activationDate.cannot.be.before.office.activation.date", defaultUserMessage,
GroupingTypesApiConstants.activationDateParamName, getActivationLocalDate());
GroupingTypesApiConstants.activationDateParamName, getActivationDate());
dataValidationErrors.add(error);
}
}
@@ -402,7 +402,7 @@ public final class SavingsAccountTransactionData implements Serializable {
}
public boolean occursOn(final LocalDate occursOnDate) {
return getTransactionDate().isEqual(occursOnDate);
return DateUtils.isEqual(occursOnDate, getTransactionDate());
}
public EndOfDayBalance toEndOfDayBalanceBoundedBy(final Money openingBalance, final LocalDateInterval boundedBy,
@@ -416,7 +416,7 @@ public final class SavingsAccountTransactionData implements Serializable {
LocalDate balanceStartDate = getTransactionDate();
LocalDate balanceEndDate = getEndOfBalanceLocalDate();
if (boundedBy.startDate().isAfter(balanceStartDate)) {
if (DateUtils.isAfter(boundedBy.startDate(), balanceStartDate)) {
balanceStartDate = boundedBy.startDate();
final LocalDateInterval spanOfBalance = LocalDateInterval.create(balanceStartDate, balanceEndDate);
numberOfDaysOfBalance = spanOfBalance.daysInPeriodInclusiveOfEndDate();
@@ -432,7 +432,7 @@ public final class SavingsAccountTransactionData implements Serializable {
}
}
if (balanceEndDate.isAfter(boundedBy.endDate())) {
if (DateUtils.isAfter(balanceEndDate, boundedBy.endDate())) {
balanceEndDate = boundedBy.endDate();
final LocalDateInterval spanOfBalance = LocalDateInterval.create(balanceStartDate, balanceEndDate);
numberOfDaysOfBalance = spanOfBalance.daysInPeriodInclusiveOfEndDate();
@@ -479,7 +479,7 @@ public final class SavingsAccountTransactionData implements Serializable {
public void updateCumulativeBalanceAndDates(final MonetaryCurrency currency, final LocalDate endOfBalanceDate) {
// balance end date should not be before transaction date
if (endOfBalanceDate != null && endOfBalanceDate.isBefore(this.transactionDate)) {
if (endOfBalanceDate != null && DateUtils.isBefore(endOfBalanceDate, this.transactionDate)) {
this.balanceEndDate = this.transactionDate;
} else if (endOfBalanceDate != null) {
this.balanceEndDate = endOfBalanceDate;
@@ -501,7 +501,7 @@ public final class SavingsAccountTransactionData implements Serializable {
public boolean isFeeCharge() {
final SavingsAccountChargesPaidByData chargePaidBy = getSavingsAccountChargePaidBy();
return (isPayCharge() && chargePaidBy != null) ? chargePaidBy.isFeeCharge() : false;
return isPayCharge() && chargePaidBy != null && chargePaidBy.isFeeCharge();
}
public void setChargesPaidByData(final SavingsAccountChargesPaidByData savingsAccountChargesPaidByData) {
@@ -518,7 +518,7 @@ public final class SavingsAccountTransactionData implements Serializable {
public boolean isPenaltyCharge() {
final SavingsAccountChargesPaidByData chargePaidBy = getSavingsAccountChargePaidBy();
return (isPayCharge() && chargePaidBy != null) ? chargePaidBy.isPenaltyCharge() : false;
return isPayCharge() && chargePaidBy != null && chargePaidBy.isPenaltyCharge();
}
public boolean isWaiveFeeChargeAndNotReversed() {
@@ -527,7 +527,7 @@ public final class SavingsAccountTransactionData implements Serializable {
public boolean isWaiveFeeCharge() {
final SavingsAccountChargesPaidByData chargePaidBy = getSavingsAccountChargePaidBy();
return (isWaiveCharge() && chargePaidBy != null) ? chargePaidBy.isFeeCharge() : false;
return isWaiveCharge() && chargePaidBy != null && chargePaidBy.isFeeCharge();
}
public boolean isWaiveCharge() {
@@ -540,7 +540,7 @@ public final class SavingsAccountTransactionData implements Serializable {
public boolean isWaivePenaltyCharge() {
final SavingsAccountChargesPaidByData chargePaidBy = getSavingsAccountChargePaidBy();
return (isWaiveCharge() && chargePaidBy != null) ? chargePaidBy.isPenaltyCharge() : false;
return isWaiveCharge() && chargePaidBy != null && chargePaidBy.isPenaltyCharge();
}
private SavingsAccountChargesPaidByData getSavingsAccountChargePaidBy() {
@@ -572,7 +572,7 @@ public final class SavingsAccountTransactionData implements Serializable {
thisTransactionData.put("id", getId());
thisTransactionData.put("officeId", officeId);
thisTransactionData.put("type", transactionType);
thisTransactionData.put("reversed", Boolean.valueOf(isReversed()));
thisTransactionData.put("reversed", isReversed());
thisTransactionData.put("date", getTransactionDate());
thisTransactionData.put("currency", currencyData);
thisTransactionData.put("amount", this.amount);
@@ -582,10 +582,8 @@ public final class SavingsAccountTransactionData implements Serializable {
thisTransactionData.put("paymentTypeId", this.paymentDetailData.getPaymentType().getId());
}
/***
* Sending data in a map, though in savings we currently expect a transaction to always repay a single charge
* (or may repay a part of a single charge too)
***/
// Sending data in a map, though in savings we currently expect a transaction to always repay a single charge
// (or may repay a part of a single charge too)
if (!this.chargesPaidByData.isEmpty()) {
final List<Map<String, Object>> savingsChargesPaidData = new ArrayList<>();
for (final SavingsAccountChargesPaidByData chargePaidBy : this.chargesPaidByData) {
@@ -25,6 +25,7 @@ import java.util.Collection;
import java.util.Collections;
import java.util.List;
import org.apache.fineract.infrastructure.core.domain.LocalDateInterval;
import org.apache.fineract.infrastructure.core.service.DateUtils;
import org.apache.fineract.organisation.monetary.domain.MonetaryCurrency;
import org.apache.fineract.organisation.monetary.domain.Money;
import org.apache.fineract.portfolio.account.service.AccountTransfersReadPlatformService;
@@ -55,8 +56,7 @@ public final class SavingsHelper {
LocalDate periodEndDate = periodStartDate;
LocalDate actualPeriodStartDate = periodStartDate;
while (!periodStartDate.isAfter(interestPostingUpToDate) && !periodEndDate.isAfter(interestPostingUpToDate)) {
while (!DateUtils.isAfter(periodStartDate, interestPostingUpToDate) && !DateUtils.isAfter(periodEndDate, interestPostingUpToDate)) {
final LocalDate interestPostingLocalDate = determineInterestPostingPeriodEndDateFrom(periodStartDate, postingPeriodType,
interestPostingUpToDate, financialYearBeginningMonth);
@@ -64,8 +64,7 @@ public final class SavingsHelper {
if (!postInterestAsOn.isEmpty()) {
for (LocalDate transactiondate : postInterestAsOn) {
if (periodStartDate.isBefore(transactiondate)
&& (periodEndDate.isAfter(transactiondate) || periodEndDate.isEqual(transactiondate))) {
if (DateUtils.isAfter(transactiondate, periodStartDate) && !DateUtils.isAfter(transactiondate, periodEndDate)) {
periodEndDate = transactiondate.minusDays(1);
actualPeriodStartDate = periodEndDate;
break;
@@ -75,7 +74,7 @@ public final class SavingsHelper {
postingPeriods.add(LocalDateInterval.create(periodStartDate, periodEndDate));
if (actualPeriodStartDate.isEqual(periodEndDate)) {
if (DateUtils.isEqual(actualPeriodStartDate, periodEndDate)) {
periodEndDate = actualPeriodStartDate.plusDays(1);
periodStartDate = actualPeriodStartDate.plusDays(1);
} else {
@@ -128,7 +127,7 @@ public final class SavingsHelper {
break;
case QUATERLY:
for (LocalDate quarterlyDate : quarterlyDates) {
if (quarterlyDate.isAfter(periodStartDate)) {
if (DateUtils.isAfter(quarterlyDate, periodStartDate)) {
periodEndDate = quarterlyDate;
isEndDateSet = true;
break;
@@ -141,7 +140,7 @@ public final class SavingsHelper {
break;
case BIANNUAL:
for (LocalDate biannualDate : biannualDates) {
if (biannualDate.isAfter(periodStartDate)) {
if (DateUtils.isAfter(biannualDate, periodStartDate)) {
periodEndDate = biannualDate;
isEndDateSet = true;
break;
@@ -21,6 +21,7 @@ package org.apache.fineract.portfolio.savings.domain.interest;
import java.math.BigDecimal;
import java.time.LocalDate;
import java.util.List;
import org.apache.fineract.infrastructure.core.service.DateUtils;
import org.apache.fineract.organisation.monetary.domain.MonetaryCurrency;
import org.apache.fineract.organisation.monetary.domain.Money;
@@ -59,7 +60,7 @@ public class CompoundInterestHelper {
// account and if already transfered then it includes in interest
// calculation.
if (!(postingPeriod.isInterestTransfered() || !interestTransferEnabled
|| (lockUntil != null && !postingPeriod.dateOfPostingTransaction().isAfter(lockUntil)))) {
|| (lockUntil != null && !DateUtils.isAfter(postingPeriod.dateOfPostingTransaction(), lockUntil)))) {
compoundInterestValues.setcompoundedInterest(BigDecimal.ZERO);
}
}
@@ -22,6 +22,7 @@ import java.math.BigDecimal;
import java.math.MathContext;
import java.time.LocalDate;
import org.apache.fineract.infrastructure.core.domain.LocalDateInterval;
import org.apache.fineract.infrastructure.core.service.DateUtils;
import org.apache.fineract.organisation.monetary.domain.Money;
import org.apache.fineract.organisation.monetary.domain.MoneyHelper;
@@ -136,7 +137,6 @@ public class EndOfDayBalance {
* @return
*/
public EndOfDayBalance upTo(final LocalDateInterval compoundingPeriodInterval, final LocalDate upToInterestCalculationDate) {
Money startingBalance = this.openingBalance;
LocalDate balanceStartDate = this.date;
@@ -144,7 +144,7 @@ public class EndOfDayBalance {
int daysOfBalance = this.numberOfDays;
if (this.date.isBefore(compoundingPeriodInterval.startDate())) {
if (DateUtils.isBefore(this.date, compoundingPeriodInterval.startDate())) {
balanceStartDate = compoundingPeriodInterval.startDate();
startingBalance = this.endOfDayBalance;
final LocalDateInterval balancePeriodInterval = LocalDateInterval.create(balanceStartDate, oldBalanceEndDate);
@@ -152,12 +152,12 @@ public class EndOfDayBalance {
}
LocalDate balanceEndDate = balanceStartDate.plusDays(daysOfBalance - 1);
if (balanceEndDate.isAfter(compoundingPeriodInterval.endDate())) {
if (DateUtils.isAfter(balanceEndDate, compoundingPeriodInterval.endDate())) {
balanceEndDate = compoundingPeriodInterval.endDate();
final LocalDateInterval balancePeriodInterval = LocalDateInterval.create(balanceStartDate, balanceEndDate);
daysOfBalance = balancePeriodInterval.daysInPeriodInclusiveOfEndDate();
}
if (balanceEndDate.isAfter(upToInterestCalculationDate)) {
if (DateUtils.isAfter(balanceEndDate, upToInterestCalculationDate)) {
balanceEndDate = upToInterestCalculationDate;
final LocalDateInterval balancePeriodInterval = LocalDateInterval.create(balanceStartDate, balanceEndDate);
daysOfBalance = balancePeriodInterval.daysInPeriodInclusiveOfEndDate();
@@ -167,7 +167,6 @@ public class EndOfDayBalance {
}
public boolean contains(final LocalDateInterval compoundingPeriodInterval) {
final LocalDate balanceUpToDate = this.date.plusDays(this.numberOfDays - 1);
final LocalDateInterval balanceInterval = LocalDateInterval.create(this.date, balanceUpToDate);
@@ -132,7 +132,7 @@ public final class PostingPeriod {
LocalDate balanceEndDate = periodInterval.endDate();
Integer numberOfDaysOfBalance = periodInterval.daysInPeriodInclusiveOfEndDate();
if (balanceEndDate.isAfter(upToInterestCalculationDate)) {
if (DateUtils.isAfter(balanceEndDate, upToInterestCalculationDate)) {
balanceEndDate = upToInterestCalculationDate;
final LocalDateInterval spanOfBalance = LocalDateInterval.create(balanceStartDate, balanceEndDate);
numberOfDaysOfBalance = spanOfBalance.daysInPeriodInclusiveOfEndDate();
@@ -206,7 +206,7 @@ public final class PostingPeriod {
LocalDate balanceEndDate = periodInterval.endDate();
Integer numberOfDaysOfBalance = periodInterval.daysInPeriodInclusiveOfEndDate();
if (balanceEndDate.isAfter(upToInterestCalculationDate)) {
if (DateUtils.isAfter(balanceEndDate, upToInterestCalculationDate)) {
balanceEndDate = upToInterestCalculationDate;
final LocalDateInterval spanOfBalance = LocalDateInterval.create(balanceStartDate, balanceEndDate);
numberOfDaysOfBalance = spanOfBalance.daysInPeriodInclusiveOfEndDate();
@@ -328,23 +328,21 @@ public final class PostingPeriod {
compoundingPeriods.add(compoundingPeriod);
break;
case MONTHLY:
final LocalDate postingPeriodEndDate = postingPeriodInterval.endDate();
LocalDate periodStartDate = postingPeriodInterval.startDate();
LocalDate periodEndDate = periodStartDate;
while (!periodStartDate.isAfter(postingPeriodEndDate) && !periodEndDate.isAfter(postingPeriodEndDate)) {
while (!DateUtils.isAfter(periodStartDate, postingPeriodEndDate)
&& !DateUtils.isAfter(periodEndDate, postingPeriodEndDate)) {
periodEndDate = determineInterestPeriodEndDateFrom(periodStartDate, interestPeriodType, upToInterestCalculationDate,
financialYearBeginningMonth);
if (periodEndDate.isAfter(postingPeriodEndDate)) {
if (DateUtils.isAfter(periodEndDate, postingPeriodEndDate)) {
periodEndDate = postingPeriodEndDate;
}
final LocalDateInterval compoundingPeriodInterval = LocalDateInterval.create(periodStartDate, periodEndDate);
if (postingPeriodInterval.contains(compoundingPeriodInterval)) {
compoundingPeriod = MonthlyCompoundingPeriod.create(compoundingPeriodInterval, allEndOfDayBalances,
upToInterestCalculationDate);
compoundingPeriods.add(compoundingPeriod);
@@ -364,17 +362,16 @@ public final class PostingPeriod {
periodStartDate = postingPeriodInterval.startDate();
periodEndDate = periodStartDate;
while (!periodStartDate.isAfter(qPostingPeriodEndDate) && !periodEndDate.isAfter(qPostingPeriodEndDate)) {
while (!DateUtils.isAfter(periodStartDate, qPostingPeriodEndDate)
&& !DateUtils.isAfter(periodEndDate, qPostingPeriodEndDate)) {
periodEndDate = determineInterestPeriodEndDateFrom(periodStartDate, interestPeriodType, upToInterestCalculationDate,
financialYearBeginningMonth);
if (periodEndDate.isAfter(qPostingPeriodEndDate)) {
if (DateUtils.isAfter(periodEndDate, qPostingPeriodEndDate)) {
periodEndDate = qPostingPeriodEndDate;
}
final LocalDateInterval compoundingPeriodInterval = LocalDateInterval.create(periodStartDate, periodEndDate);
if (postingPeriodInterval.contains(compoundingPeriodInterval)) {
compoundingPeriod = QuarterlyCompoundingPeriod.create(compoundingPeriodInterval, allEndOfDayBalances,
upToInterestCalculationDate);
compoundingPeriods.add(compoundingPeriod);
@@ -390,11 +387,11 @@ public final class PostingPeriod {
periodStartDate = postingPeriodInterval.startDate();
periodEndDate = periodStartDate;
while (!periodStartDate.isAfter(bPostingPeriodEndDate) && !periodEndDate.isAfter(bPostingPeriodEndDate)) {
while (!DateUtils.isAfter(periodStartDate, bPostingPeriodEndDate)
&& !DateUtils.isAfter(periodEndDate, bPostingPeriodEndDate)) {
periodEndDate = determineInterestPeriodEndDateFrom(periodStartDate, interestPeriodType, upToInterestCalculationDate,
financialYearBeginningMonth);
if (periodEndDate.isAfter(bPostingPeriodEndDate)) {
if (DateUtils.isAfter(periodEndDate, bPostingPeriodEndDate)) {
periodEndDate = bPostingPeriodEndDate;
}
@@ -416,11 +413,12 @@ public final class PostingPeriod {
periodStartDate = postingPeriodInterval.startDate();
periodEndDate = periodStartDate;
while (!periodStartDate.isAfter(aPostingPeriodEndDate) && !periodEndDate.isAfter(aPostingPeriodEndDate)) {
while (!DateUtils.isAfter(periodStartDate, aPostingPeriodEndDate)
&& !DateUtils.isAfter(periodEndDate, aPostingPeriodEndDate)) {
periodEndDate = determineInterestPeriodEndDateFrom(periodStartDate, interestPeriodType, upToInterestCalculationDate,
financialYearBeginningMonth);
if (periodEndDate.isAfter(aPostingPeriodEndDate)) {
if (DateUtils.isAfter(periodEndDate, aPostingPeriodEndDate)) {
periodEndDate = aPostingPeriodEndDate;
}
@@ -483,7 +481,7 @@ public final class PostingPeriod {
case ANNUAL:
periodEndDate = periodStartDate.withMonth(previousMonth);
periodEndDate = periodEndDate.with(TemporalAdjusters.lastDayOfMonth());
if (periodEndDate.isBefore(periodStartDate)) {
if (DateUtils.isBefore(periodEndDate, periodStartDate)) {
periodEndDate = periodEndDate.plusYears(1);
}
break;
@@ -23,6 +23,7 @@ import java.time.LocalDate;
import lombok.Getter;
import lombok.RequiredArgsConstructor;
import org.apache.fineract.infrastructure.core.domain.LocalDateInterval;
import org.apache.fineract.infrastructure.core.service.DateUtils;
import org.apache.fineract.organisation.monetary.domain.MonetaryCurrency;
import org.apache.fineract.organisation.monetary.domain.Money;
@@ -54,7 +55,7 @@ public class SavingsAccountTransactionDetailsForPostingPeriod {
}
public boolean occursOn(final LocalDate occursOnDate) {
return getTransactionDate().isEqual(occursOnDate);
return DateUtils.isEqual(occursOnDate, getTransactionDate());
}
public EndOfDayBalance toEndOfDayBalance(final Money openingBalance) {
@@ -92,7 +93,6 @@ public class SavingsAccountTransactionDetailsForPostingPeriod {
}
public EndOfDayBalance toEndOfDayBalanceBoundedBy(final Money openingBalance, final LocalDateInterval boundedBy) {
final MonetaryCurrency currency = openingBalance.getCurrency();
Money endOfDayBalance = openingBalance.copy();
@@ -101,7 +101,7 @@ public class SavingsAccountTransactionDetailsForPostingPeriod {
LocalDate balanceStartDate = getTransactionDate();
LocalDate balanceEndDate = getEndOfBalanceDate();
if (boundedBy.startDate().isAfter(balanceStartDate)) {
if (DateUtils.isAfter(boundedBy.startDate(), balanceStartDate)) {
balanceStartDate = boundedBy.startDate();
final LocalDateInterval spanOfBalance = LocalDateInterval.create(balanceStartDate, balanceEndDate);
numberOfDaysOfBalance = spanOfBalance.daysInPeriodInclusiveOfEndDate();
@@ -121,7 +121,7 @@ public class SavingsAccountTransactionDetailsForPostingPeriod {
}
}
if (balanceEndDate.isAfter(boundedBy.endDate())) {
if (DateUtils.isAfter(balanceEndDate, boundedBy.endDate())) {
balanceEndDate = boundedBy.endDate();
final LocalDateInterval spanOfBalance = LocalDateInterval.create(balanceStartDate, balanceEndDate);
numberOfDaysOfBalance = spanOfBalance.daysInPeriodInclusiveOfEndDate();
@@ -1609,7 +1609,7 @@ public class Loan extends AbstractAuditableWithUTCDateTimeCustom {
final String errorMessage = "The date on which a loan is submitted cannot be earlier than client's activation date.";
throw new InvalidLoanStateTransitionException("submittal", "cannot.be.before.client.activation.date", errorMessage,
getSubmittedOnDate());
} else if (this.group != null && DateUtils.isBefore(getSubmittedOnDate(), this.group.getActivationLocalDate())) {
} else if (this.group != null && DateUtils.isBefore(getSubmittedOnDate(), this.group.getActivationDate())) {
final String errorMessage = "The date on which a loan is submitted cannot be earlier than groups's activation date.";
throw new InvalidLoanStateTransitionException("submittal", "cannot.be.before.group.activation.date", errorMessage,
getSubmittedOnDate());
@@ -2124,7 +2124,7 @@ public class Loan extends AbstractAuditableWithUTCDateTimeCustom {
if (this.group != null && this.group.isActivatedAfter(submittedOn)) {
final String errorMessage = "The date on which a loan is submitted cannot be earlier than groups's activation date.";
throw new InvalidLoanStateTransitionException("submittal", "cannot.be.before.group.activation.date", errorMessage, submittedOn,
group.getActivationLocalDate());
group.getActivationDate());
}
if (DateUtils.isAfter(submittedOn, getExpectedDisbursedOnLocalDate())) {
@@ -850,6 +850,7 @@ public class LoanTransaction extends AbstractAuditableWithUTCDateTimeCustom {
this.manuallyAdjustedOrReversed = true;
}
@Override
public OffsetDateTime getCreatedDateTime() {
return (this.getCreatedDate().isPresent() ? this.getCreatedDate().get() : DateUtils.getOffsetDateTimeOfTenantWithMostPrecision());
}
@@ -119,7 +119,7 @@ public class SmsCampaign extends AbstractPersistableCustom {
private SmsCampaign(final String campaignName, final Integer campaignType, final Integer triggerType, final Report businessRuleId,
final Long providerId, final String paramValue, final String message, final LocalDate submittedOnDate,
final AppUser submittedBy, final String recurrence, final LocalDateTime localDateTime, final boolean isNotification) {
final AppUser submittedBy, final String recurrence, final LocalDateTime recurrenceStartDate, final boolean isNotification) {
this.campaignName = campaignName;
this.campaignType = campaignType;
this.triggerType = SmsCampaignTriggerType.fromInt(triggerType).getValue();
@@ -131,18 +131,12 @@ public class SmsCampaign extends AbstractPersistableCustom {
this.submittedOnDate = submittedOnDate;
this.submittedBy = submittedBy;
this.recurrence = recurrence;
LocalDateTime recurrenceStartDate = LocalDateTime.now(DateUtils.getDateTimeZoneOfTenant());
this.isVisible = true;
if (localDateTime != null) {
this.recurrenceStartDate = localDateTime;
} else {
this.recurrenceStartDate = recurrenceStartDate;
}
this.recurrenceStartDate = recurrenceStartDate;
this.isNotification = isNotification;
}
public static SmsCampaign instance(final AppUser submittedBy, final Report report, final JsonCommand command) {
final String campaignName = command.stringValueOfParameterNamed(SmsCampaignValidator.campaignName);
final Long campaignType = command.longValueOfParameterNamed(SmsCampaignValidator.campaignType);
final Long triggerType = command.longValueOfParameterNamed(SmsCampaignValidator.triggerType);
@@ -164,10 +158,11 @@ public class SmsCampaign extends AbstractPersistableCustom {
}
String recurrence = null;
LocalDateTime recurrenceStartDate = LocalDateTime.now(DateUtils.getDateTimeZoneOfTenant());
LocalDateTime recurrenceStartDate = null;
if (SmsCampaignTriggerType.fromInt(triggerType.intValue()).isSchedule()) {
final Locale locale = command.extractLocale();
String dateTimeFormat;
recurrenceStartDate = DateUtils.getLocalDateTimeOfTenant();
if (command.hasParameter(SmsCampaignValidator.dateTimeFormat)) {
dateTimeFormat = command.stringValueOfParameterNamed(SmsCampaignValidator.dateTimeFormat);
final DateTimeFormatter fmt = DateTimeFormatter.ofPattern(dateTimeFormat).withLocale(locale);
@@ -177,8 +172,6 @@ public class SmsCampaign extends AbstractPersistableCustom {
}
recurrence = constructRecurrence(command);
}
} else {
recurrenceStartDate = null;
}
return new SmsCampaign(campaignName, campaignType.intValue(), triggerType.intValue(), report, providerId, paramValue, message,
@@ -186,7 +179,6 @@ public class SmsCampaign extends AbstractPersistableCustom {
}
public Map<String, Object> update(JsonCommand command) {
final Map<String, Object> actualChanges = new LinkedHashMap<>(5);
if (command.isChangeInStringParameterNamed(SmsCampaignValidator.campaignName, this.campaignName)) {
@@ -255,7 +247,6 @@ public class SmsCampaign extends AbstractPersistableCustom {
}
public void activate(final AppUser currentUser, final DateTimeFormatter formatter, final LocalDate activationLocalDate) {
if (isActive()) {
// handle errors if already activated
final String defaultUserMessage = "Cannot activate campaign. Campaign is already active.";
@@ -297,7 +288,6 @@ public class SmsCampaign extends AbstractPersistableCustom {
}
public void reactivate(final AppUser currentUser, final DateTimeFormatter dateTimeFormat, final LocalDate reactivateLocalDate) {
if (!isClosed()) {
// handle errors if already activated
final String defaultUserMessage = "Cannot reactivate campaign. Campaign must be in closed state.";
@@ -384,66 +374,55 @@ public class SmsCampaign extends AbstractPersistableCustom {
}
private void validateActivationDate(final List<ApiParameterError> dataValidationErrors) {
if (getSubmittedOnDate() != null && isDateInTheFuture(getSubmittedOnDate())) {
if (DateUtils.isDateInTheFuture(getSubmittedOnDate())) {
final String defaultUserMessage = "submitted date cannot be in the future.";
final ApiParameterError error = ApiParameterError.parameterError("error.msg.campaign.submittedOnDate.in.the.future",
defaultUserMessage, SmsCampaignValidator.submittedOnDateParamName, this.submittedOnDate);
dataValidationErrors.add(error);
}
if (getActivationLocalDate() != null && getSubmittedOnDate() != null && getSubmittedOnDate().isAfter(getActivationLocalDate())) {
if (getActivationDate() != null && DateUtils.isAfter(getSubmittedOnDate(), getActivationDate())) {
final String defaultUserMessage = "submitted date cannot be after the activation date";
final ApiParameterError error = ApiParameterError.parameterError("error.msg.campaign.submittedOnDate.after.activation.date",
defaultUserMessage, SmsCampaignValidator.submittedOnDateParamName, this.submittedOnDate);
dataValidationErrors.add(error);
}
if (getActivationLocalDate() != null && isDateInTheFuture(getActivationLocalDate())) {
if (DateUtils.isDateInTheFuture(getActivationDate())) {
final String defaultUserMessage = "Activation date cannot be in the future.";
final ApiParameterError error = ApiParameterError.parameterError("error.msg.campaign.activationDate.in.the.future",
defaultUserMessage, SmsCampaignValidator.activationDateParamName, getActivationLocalDate());
defaultUserMessage, SmsCampaignValidator.activationDateParamName, getActivationDate());
dataValidationErrors.add(error);
}
}
private void validateReactivationDate(final List<ApiParameterError> dataValidationErrors) {
if (getActivationLocalDate() != null && isDateInTheFuture(getActivationLocalDate())) {
if (DateUtils.isDateInTheFuture(getActivationDate())) {
final String defaultUserMessage = "Activation date cannot be in the future.";
final ApiParameterError error = ApiParameterError.parameterError("error.msg.campaign.activationDate.in.the.future",
defaultUserMessage, SmsCampaignValidator.activationDateParamName, getActivationLocalDate());
defaultUserMessage, SmsCampaignValidator.activationDateParamName, getActivationDate());
dataValidationErrors.add(error);
}
if (getActivationLocalDate() != null && getSubmittedOnDate() != null && getSubmittedOnDate().isAfter(getActivationLocalDate())) {
if (getActivationDate() != null && DateUtils.isAfter(getSubmittedOnDate(), getActivationDate())) {
final String defaultUserMessage = "submitted date cannot be after the activation date";
final ApiParameterError error = ApiParameterError.parameterError("error.msg.campaign.submittedOnDate.after.activation.date",
defaultUserMessage, SmsCampaignValidator.submittedOnDateParamName, this.submittedOnDate);
dataValidationErrors.add(error);
}
if (getSubmittedOnDate() != null && isDateInTheFuture(getSubmittedOnDate())) {
if (DateUtils.isDateInTheFuture(getSubmittedOnDate())) {
final String defaultUserMessage = "submitted date cannot be in the future.";
final ApiParameterError error = ApiParameterError.parameterError("error.msg.campaign.submittedOnDate.in.the.future",
defaultUserMessage, SmsCampaignValidator.submittedOnDateParamName, this.submittedOnDate);
dataValidationErrors.add(error);
}
}
private void validateClosureDate(final List<ApiParameterError> dataValidationErrors) {
if (getClosureDate() != null && isDateInTheFuture(getClosureDate())) {
if (DateUtils.isDateInTheFuture(getClosureDate())) {
final String defaultUserMessage = "closure date cannot be in the future.";
final ApiParameterError error = ApiParameterError.parameterError("error.msg.campaign.closureDate.in.the.future",
defaultUserMessage, SmsCampaignValidator.closureDateParamName, this.closureDate);
@@ -461,14 +440,10 @@ public class SmsCampaign extends AbstractPersistableCustom {
return this.closureDate;
}
public LocalDate getActivationLocalDate() {
public LocalDate getActivationDate() {
return this.approvedOnDate;
}
private boolean isDateInTheFuture(final LocalDate localDate) {
return localDate.isAfter(DateUtils.getBusinessLocalDate());
}
public Report getBusinessRuleId() {
return this.businessRuleId;
}
@@ -365,7 +365,7 @@ public class SmsCampaignDomainServiceImpl implements SmsCampaignDomainService {
smsParams.put("depositAmount", savingsAccountTransaction.getAmount(savingsAccount.getCurrency()));
smsParams.put("balance", savingsAccount.getWithdrawableBalance());
smsParams.put("officeId", client.getOffice().getId());
smsParams.put("transactionDate", savingsAccountTransaction.getTransactionLocalDate().format(dateFormatter));
smsParams.put("transactionDate", savingsAccountTransaction.getTransactionDate().format(dateFormatter));
smsParams.put("savingsTransactionId", savingsAccountTransaction.getId());
if (client.getStaff() != null) {
@@ -30,7 +30,6 @@ import java.io.StringReader;
import java.io.StringWriter;
import java.time.LocalDate;
import java.time.LocalDateTime;
import java.time.ZoneId;
import java.time.format.DateTimeFormatter;
import java.util.ArrayList;
import java.util.Collection;
@@ -54,12 +53,10 @@ import org.apache.fineract.infrastructure.core.api.JsonCommand;
import org.apache.fineract.infrastructure.core.api.JsonQuery;
import org.apache.fineract.infrastructure.core.data.CommandProcessingResult;
import org.apache.fineract.infrastructure.core.data.CommandProcessingResultBuilder;
import org.apache.fineract.infrastructure.core.domain.FineractPlatformTenant;
import org.apache.fineract.infrastructure.core.exception.GeneralPlatformDomainRuleException;
import org.apache.fineract.infrastructure.core.exception.PlatformDataIntegrityException;
import org.apache.fineract.infrastructure.core.serialization.FromJsonHelper;
import org.apache.fineract.infrastructure.core.service.DateUtils;
import org.apache.fineract.infrastructure.core.service.ThreadLocalContextUtil;
import org.apache.fineract.infrastructure.dataqueries.data.GenericResultsetData;
import org.apache.fineract.infrastructure.dataqueries.domain.Report;
import org.apache.fineract.infrastructure.dataqueries.domain.ReportRepository;
@@ -107,16 +104,16 @@ public class SmsCampaignWritePlatformServiceJpaImpl implements SmsCampaignWriteP
@Transactional
@Override
public CommandProcessingResult create(JsonCommand command) {
final AppUser currentUser = this.context.authenticatedUser();
this.smsCampaignValidator.validateCreate(command.json());
final Long runReportId = command.longValueOfParameterNamed(SmsCampaignValidator.runReportId);
Report report = this.reportRepository.findById(runReportId).orElseThrow(() -> new ReportNotFoundException(runReportId));
LocalDateTime tenantDateTime = DateUtils.getLocalDateTimeOfTenant();
SmsCampaign smsCampaign = SmsCampaign.instance(currentUser, report, command);
if (smsCampaign.getRecurrenceStartDate() != null
&& smsCampaign.getRecurrenceStartDate().isBefore(DateUtils.getLocalDateTimeOfTenant())) {
LocalDateTime recurrenceStartDate = smsCampaign.getRecurrenceStartDate();
if (recurrenceStartDate != null && DateUtils.isBefore(recurrenceStartDate, tenantDateTime)) {
throw new GeneralPlatformDomainRuleException("error.msg.campaign.recurrenceStartDate.in.the.past",
"Recurrence start date cannot be the past date.", smsCampaign.getRecurrenceStartDate());
"Recurrence start date cannot be the past date.", recurrenceStartDate);
}
this.smsCampaignRepository.saveAndFlush(smsCampaign);
@@ -380,17 +377,15 @@ public class SmsCampaignWritePlatformServiceJpaImpl implements SmsCampaignWriteP
if (smsCampaign.isDirect()) {
insertDirectCampaignIntoSmsOutboundTable(smsCampaign);
} else if (smsCampaign.isSchedule()) {
/**
* if recurrence start date is in the future calculate next trigger date if not use recurrence start date us
* next trigger date when activating
*/
// if recurrence start date is in the future calculate next trigger date if not use recurrence start date us
// next trigger date when activating
LocalDateTime nextTriggerDate = null;
if (smsCampaign.getRecurrenceStartDateTime().isBefore(tenantDateTime())) {
nextTriggerDate = CalendarUtils.getNextRecurringDate(smsCampaign.getRecurrence(), smsCampaign.getRecurrenceStartDate(),
DateUtils.getLocalDateTimeOfTenant());
LocalDateTime tenantDateTime = DateUtils.getLocalDateTimeOfTenant();
LocalDateTime recurrenceStartDate = smsCampaign.getRecurrenceStartDate();
if (DateUtils.isBefore(recurrenceStartDate, tenantDateTime)) {
nextTriggerDate = CalendarUtils.getNextRecurringDate(smsCampaign.getRecurrence(), recurrenceStartDate, tenantDateTime);
} else {
nextTriggerDate = smsCampaign.getRecurrenceStartDate();
nextTriggerDate = recurrenceStartDate;
}
smsCampaign.setNextTriggerDate(nextTriggerDate);
@@ -517,7 +512,6 @@ public class SmsCampaignWritePlatformServiceJpaImpl implements SmsCampaignWriteP
@Transactional
@Override
public CommandProcessingResult reactivateSmsCampaign(final Long campaignId, JsonCommand command) {
this.smsCampaignValidator.validateActivation(command.json());
final AppUser currentUser = this.context.authenticatedUser();
@@ -532,21 +526,16 @@ public class SmsCampaignWritePlatformServiceJpaImpl implements SmsCampaignWriteP
if (smsCampaign.isDirect()) {
insertDirectCampaignIntoSmsOutboundTable(smsCampaign);
} else if (smsCampaign.isSchedule()) {
/**
* if recurrence start date is in the future calculate next trigger date if not use recurrence start date us
* next trigger date when activating
*/
// if recurrence start date is in the past, calculate next trigger date, otherwise use recurrence start date
// as next trigger date when activating
LocalDateTime nextTriggerDate = null;
if (smsCampaign.getRecurrenceStartDateTime().isBefore(tenantDateTime())) {
nextTriggerDate = CalendarUtils.getNextRecurringDate(smsCampaign.getRecurrence(), smsCampaign.getRecurrenceStartDate(),
DateUtils.getLocalDateTimeOfTenant());
LocalDateTime tenantDateTime = DateUtils.getLocalDateTimeOfTenant();
LocalDateTime recurrenceStartDate = smsCampaign.getRecurrenceStartDate();
if (DateUtils.isBefore(recurrenceStartDate, tenantDateTime)) {
nextTriggerDate = CalendarUtils.getNextRecurringDate(smsCampaign.getRecurrence(), recurrenceStartDate, tenantDateTime);
} else {
nextTriggerDate = smsCampaign.getRecurrenceStartDate();
nextTriggerDate = recurrenceStartDate;
}
// to get time of tenant
final LocalDateTime getTime = smsCampaign.getRecurrenceStartDateTime();
smsCampaign.setNextTriggerDate(nextTriggerDate);
}
this.smsCampaignRepository.saveAndFlush(smsCampaign);
@@ -555,21 +544,7 @@ public class SmsCampaignWritePlatformServiceJpaImpl implements SmsCampaignWriteP
}
private void handleDataIntegrityIssues(final JsonCommand command, final Throwable realCause) {
throw new PlatformDataIntegrityException("error.msg.sms.campaign.unknown.data.integrity.issue",
"Unknown data integrity issue with resource: " + realCause.getMessage());
}
private LocalDateTime tenantDateTime() {
LocalDateTime today = LocalDateTime.now(DateUtils.getDateTimeZoneOfTenant());
final FineractPlatformTenant tenant = ThreadLocalContextUtil.getTenant();
if (tenant != null) {
final ZoneId zone = ZoneId.of(tenant.getTimezoneId());
if (zone != null) {
today = LocalDateTime.now(zone);
}
}
return today;
}
}
@@ -61,7 +61,7 @@ public class CustomAuditingHandler extends AuditingHandler {
private DateTimeProvider fetchDateTimeProvider(Object bean) {
if (bean instanceof AbstractAuditableWithUTCDateTimeCustom) {
return CustomDateTimeProvider.TENANT;
return CustomDateTimeProvider.UTC;
} else {
return CustomDateTimeProvider.INSTANCE;
}
@@ -18,9 +18,6 @@
*/
package org.apache.fineract.infrastructure.core.auditing;
import java.time.LocalDateTime;
import java.time.OffsetDateTime;
import java.time.ZoneId;
import java.time.temporal.TemporalAccessor;
import java.util.Optional;
import org.apache.fineract.infrastructure.core.service.DateUtils;
@@ -29,7 +26,7 @@ import org.springframework.data.auditing.DateTimeProvider;
public enum CustomDateTimeProvider implements DateTimeProvider {
INSTANCE, TENANT;
INSTANCE, UTC;
/*
* (non-Javadoc)
@@ -42,10 +39,10 @@ public enum CustomDateTimeProvider implements DateTimeProvider {
switch (this) {
case INSTANCE -> {
return Optional.of(LocalDateTime.now(ZoneId.systemDefault()));
return Optional.of(DateUtils.getLocalDateTimeOfSystem());
}
case TENANT -> {
return Optional.of(OffsetDateTime.now(DateUtils.getDateTimeZoneOfTenant()));
case UTC -> {
return Optional.of(DateUtils.getAuditOffsetDateTime());
}
}
throw new UnsupportedOperationException(this + " is not supported!");
@@ -113,7 +113,7 @@ public class InteropAccountData extends CommandProcessingResult {
return new InteropAccountData(account.getExternalId().getValue(), product.getId().toString(), product.getName(),
product.getShortName(), account.getCurrency().getCode(), account.getAccountBalance(), account.getWithdrawableBalance(),
account.getStatus(), subStatus, account.getAccountType(), account.depositAccountType(), account.getActivationLocalDate(),
account.getStatus(), subStatus, account.getAccountType(), account.depositAccountType(), account.getActivationDate(),
calcStatusUpdateOn(account), account.getWithdrawnOnDate(), account.retrieveLastTransactionDate(), ids,
account.getClient().getId());
}
@@ -125,8 +125,8 @@ public class InteropAccountData extends CommandProcessingResult {
if (account.getWithdrawnOnDate() != null) {
return account.getWithdrawnOnDate();
}
if (account.getActivationLocalDate() != null) {
return account.getActivationLocalDate();
if (account.getActivationDate() != null) {
return account.getActivationDate();
}
if (account.getRejectedOnDate() != null) {
return account.getRejectedOnDate();
@@ -112,8 +112,8 @@ public class InteropTransactionData extends CommandProcessingResult {
String currency = savingsAccount.getCurrency().getCode();
BigDecimal runningBalance = transaction.getRunningBalance(savingsAccount.getCurrency()).getAmount();
LocalDate bookingDateTime = transaction.getTransactionLocalDate();
LocalDate endOfBalanceLocalDate = transaction.getEndOfBalanceLocalDate();
LocalDate bookingDateTime = transaction.getTransactionDate();
LocalDate endOfBalanceLocalDate = transaction.getEndOfBalanceDate();
LocalDate valueDateTime = endOfBalanceLocalDate == null ? bookingDateTime : endOfBalanceLocalDate;
StringBuilder sb = new StringBuilder();
@@ -30,6 +30,7 @@ import jakarta.validation.constraints.NotNull;
import java.time.LocalDateTime;
import java.util.Objects;
import org.apache.fineract.infrastructure.core.domain.AbstractPersistableCustom;
import org.apache.fineract.infrastructure.core.service.DateUtils;
import org.apache.fineract.portfolio.savings.domain.SavingsAccount;
@Entity
@@ -67,18 +68,17 @@ public class InteropIdentifier extends AbstractPersistableCustom {
protected InteropIdentifier() {}
public InteropIdentifier(@NotNull SavingsAccount account, @NotNull InteropIdentifierType type, @NotNull String value, String subType,
@NotNull String createdBy, @NotNull LocalDateTime createdOn) {
@NotNull String createdBy) {
this.account = account;
this.type = type;
this.value = value;
this.subType = subType;
this.createdBy = createdBy;
this.createdOn = createdOn;
this.createdOn = DateUtils.getAuditLocalDateTime();
}
public InteropIdentifier(@NotNull SavingsAccount account, @NotNull InteropIdentifierType type, @NotNull String createdBy,
@NotNull LocalDateTime createdOn) {
this(account, type, null, null, createdBy, createdOn);
public InteropIdentifier(@NotNull SavingsAccount account, @NotNull InteropIdentifierType type, @NotNull String createdBy) {
this(account, type, null, null, createdBy);
}
public SavingsAccount getAccount() {
@@ -243,7 +243,7 @@ public class InteropServiceImpl implements InteropService {
return true;
}
java.time.LocalDateTime transactionDate = t.getTransactionLocalDate().atStartOfDay(ZoneId.systemDefault()).toLocalDateTime();
java.time.LocalDateTime transactionDate = t.getTransactionDate().atStartOfDay(ZoneId.systemDefault()).toLocalDateTime();
return (transactionsTo == null || transactionsTo.compareTo(transactionDate) > 0) && (transactionsFrom == null
|| transactionsFrom.compareTo(transactionDate.withHour(23).withMinute(59).withSecond(59)) <= 0);
};
@@ -276,16 +276,15 @@ public class InteropServiceImpl implements InteropService {
@Override
public InteropIdentifierAccountResponseData registerAccountIdentifier(@NotNull InteropIdentifierType idType, @NotNull String idValue,
String subIdOrType, @NotNull JsonCommand command) {
InteropIdentifierRequestData request = dataValidator.validateAndParseCreateIdentifier(idType, idValue, subIdOrType, command);
// TODO: error handling
SavingsAccount savingsAccount = validateAndGetSavingAccount(request.getAccountId());
try {
AppUser createdBy = getLoginUser();
AppUser createdBy = securityContext.authenticatedUser();
InteropIdentifier identifier = new InteropIdentifier(savingsAccount, request.getIdType(), request.getIdValue(),
request.getSubIdOrType(), createdBy.getUsername(), DateUtils.getLocalDateTimeOfTenant());
request.getSubIdOrType(), createdBy.getUsername());
identifierRepository.saveAndFlush(identifier);
@@ -401,10 +400,9 @@ public class InteropServiceImpl implements InteropService {
PaymentDetail paymentDetail = instance(findPaymentType(), savingsAccount.getExternalId().getValue(), null, getRoutingCode(),
transferCode, null);
SavingsAccountTransaction holdTransaction = SavingsAccountTransaction.holdAmount(savingsAccount, savingsAccount.office(),
paymentDetail, transactionDate, Money.of(savingsAccount.getCurrency(), total), DateUtils.getLocalDateTimeOfTenant(),
getLoginUser(), false);
paymentDetail, transactionDate, Money.of(savingsAccount.getCurrency(), total), false);
MonetaryCurrency accountCurrency = savingsAccount.getCurrency().copy();
holdTransaction.updateRunningBalance(
holdTransaction.setRunningBalance(
Money.of(accountCurrency, savingsAccount.getWithdrawableBalance().subtract(holdTransaction.getAmount())));
holdTransaction.updateCumulativeBalanceAndDates(accountCurrency, transactionDate);
@@ -454,8 +452,8 @@ public class InteropServiceImpl implements InteropService {
}
if (holdTransaction.getReleaseIdOfHoldAmountTransaction() == null) {
SavingsAccountTransaction releaseTransaction = savingsAccountTransactionRepository.saveAndFlush(
releaseAmount(holdTransaction, transactionDate, DateUtils.getLocalDateTimeOfSystem(), getLoginUser()));
SavingsAccountTransaction releaseTransaction = savingsAccountTransactionRepository
.saveAndFlush(releaseAmount(holdTransaction, transactionDate));
holdTransaction.updateReleaseId(releaseTransaction.getId());
savingsAccount.releaseOnHoldAmount(holdTransaction.getAmount());
savingsAccount.addTransaction(releaseTransaction);
@@ -493,11 +491,10 @@ public class InteropServiceImpl implements InteropService {
SavingsAccountTransaction holdTransaction = findTransaction(savingsAccount, request.getTransferCode(), AMOUNT_HOLD.getValue());
if (holdTransaction != null && holdTransaction.getReleaseIdOfHoldAmountTransaction() == null) {
SavingsAccountTransaction releaseTransaction = releaseAmount(holdTransaction, transactionDate,
DateUtils.getLocalDateTimeOfSystem(), getLoginUser());
SavingsAccountTransaction releaseTransaction = releaseAmount(holdTransaction, transactionDate);
MonetaryCurrency accountCurrency = savingsAccount.getCurrency().copy();
releaseTransaction.updateRunningBalance(
Money.of(accountCurrency, savingsAccount.getWithdrawableBalance().add(holdTransaction.getAmount())));
releaseTransaction
.setRunningBalance(Money.of(accountCurrency, savingsAccount.getWithdrawableBalance().add(holdTransaction.getAmount())));
releaseTransaction.updateCumulativeBalanceAndDates(accountCurrency, transactionDate);
releaseTransaction = savingsAccountTransactionRepository.saveAndFlush(releaseTransaction);
holdTransaction.updateReleaseId(releaseTransaction.getId());
@@ -652,10 +649,6 @@ public class InteropServiceImpl implements InteropService {
return identifierRepository.findOneByTypeAndValueAndSubType(idType, idValue, subIdOrType);
}
private AppUser getLoginUser() {
return securityContext.getAuthenticatedUserIfPresent();
}
/*
* Guaranteed to throw an exception no matter what the data integrity issue is.
*/
@@ -34,6 +34,7 @@ import org.apache.fineract.infrastructure.core.data.CommandProcessingResult;
import org.apache.fineract.infrastructure.core.data.CommandProcessingResultBuilder;
import org.apache.fineract.infrastructure.core.data.DataValidatorBuilder;
import org.apache.fineract.infrastructure.core.exception.PlatformApiDataValidationException;
import org.apache.fineract.infrastructure.core.service.DateUtils;
import org.apache.fineract.portfolio.calendar.CalendarConstants.CalendarSupportedParameters;
import org.apache.fineract.portfolio.calendar.domain.Calendar;
import org.apache.fineract.portfolio.calendar.domain.CalendarEntityType;
@@ -78,7 +79,7 @@ public class CalendarWritePlatformServiceJpaRepositoryImpl implements CalendarWr
Group centerOrGroup = null;
if (command.getGroupId() != null) {
centerOrGroup = this.groupRepository.findOneWithNotFoundDetection(command.getGroupId());
entityActivationDate = centerOrGroup.getActivationLocalDate();
entityActivationDate = centerOrGroup.getActivationDate();
entityType = centerOrGroup.isCenter() ? CalendarEntityType.CENTERS : CalendarEntityType.GROUPS;
entityId = command.getGroupId();
} else if (command.getLoanId() != null) {
@@ -88,7 +89,7 @@ public class CalendarWritePlatformServiceJpaRepositoryImpl implements CalendarWr
entityId = command.getLoanId();
} else if (command.getClientId() != null) {
final Client client = this.clientRepository.findOneWithNotFoundDetection(command.getClientId());
entityActivationDate = client.getActivationLocalDate();
entityActivationDate = client.getActivationDate();
entityType = CalendarEntityType.CLIENTS;
entityId = command.getClientId();
}
@@ -98,7 +99,7 @@ public class CalendarWritePlatformServiceJpaRepositoryImpl implements CalendarWr
final List<ApiParameterError> dataValidationErrors = new ArrayList<>();
final DataValidatorBuilder baseDataValidator = new DataValidatorBuilder(dataValidationErrors).resource("calendar");
if (entityActivationDate == null || newCalendar.getStartDateLocalDate().isBefore(entityActivationDate)) {
if (entityActivationDate == null || DateUtils.isBefore(newCalendar.getStartDateLocalDate(), entityActivationDate)) {
final DateTimeFormatter formatter = DateTimeFormatter.ofPattern(command.dateFormat()).withLocale(command.extractLocale());
String dateAsString = "";
if (entityActivationDate != null) {
@@ -230,8 +230,7 @@ public class InterestRateChart extends AbstractPersistableCustom {
if (!existingChart.equals(this)) {
if (this.chartFields.isOverlapping(existingChart.chartFields)) {
baseDataValidator.failWithCodeNoParameterAddedToErrorCode("chart.overlapping.from.and.end.dates",
existingChart.getFromDateAsLocalDate(), existingChart.getEndDateAsLocalDate(), this.getFromDateAsLocalDate(),
this.getEndDateAsLocalDate());
existingChart.getFromDate(), existingChart.getEndDate(), this.getFromDate(), this.getEndDate());
}
}
}
@@ -318,12 +317,12 @@ public class InterestRateChart extends AbstractPersistableCustom {
return chartSlabs.remove(chartSlab);
}
public LocalDate getFromDateAsLocalDate() {
return this.chartFields.getFromDateAsLocalDate();
public LocalDate getFromDate() {
return this.chartFields.getFromDate();
}
public LocalDate getEndDateAsLocalDate() {
return this.chartFields.getEndDateAsLocalDate();
public LocalDate getEndDate() {
return this.chartFields.getEndDate();
}
private void throwExceptionIfValidationWarningsExist(final List<ApiParameterError> dataValidationErrors) {
@@ -88,7 +88,7 @@ public class InterestRateChartFields {
final String localeAsInput = command.locale();
final String dateFormat = command.dateFormat();
if (command.isChangeInLocalDateParameterNamed(fromDateParamName, getFromDateAsLocalDate())) {
if (command.isChangeInLocalDateParameterNamed(fromDateParamName, getFromDate())) {
final String newValueAsString = command.stringValueOfParameterNamed(fromDateParamName);
actualChanges.put(fromDateParamName, newValueAsString);
actualChanges.put(localeParamName, localeAsInput);
@@ -96,7 +96,7 @@ public class InterestRateChartFields {
this.fromDate = command.localDateValueOfParameterNamed(fromDateParamName);
}
if (command.isChangeInLocalDateParameterNamed(endDateParamName, getEndDateAsLocalDate())) {
if (command.isChangeInLocalDateParameterNamed(endDateParamName, getEndDate())) {
final String newValueAsString = command.stringValueOfParameterNamed(endDateParamName);
actualChanges.put(endDateParamName, newValueAsString);
actualChanges.put(localeParamName, localeAsInput);
@@ -116,31 +116,27 @@ public class InterestRateChartFields {
}
public boolean isFromDateAfterToDate() {
return isFromDateAfter(getEndDateAsLocalDate());
return isFromDateAfter(getEndDate());
}
public boolean isFromDateAfter(LocalDate compare) {
final LocalDate fromDate = getFromDateAsLocalDate();
if (fromDate != null && compare != null) {
return fromDate.isAfter(compare);
}
return false;
return compare != null && DateUtils.isAfter(getFromDate(), compare);
}
public LocalDate getFromDateAsLocalDate() {
public LocalDate getFromDate() {
return this.fromDate;
}
public LocalDate getEndDateAsLocalDate() {
public LocalDate getEndDate() {
return this.endDate;
}
public boolean isOverlapping(InterestRateChartFields that) {
final LocalDate thisFromDate = this.getFromDateAsLocalDate();
LocalDate thisEndDate = this.getEndDateAsLocalDate();
final LocalDate thisFromDate = this.getFromDate();
LocalDate thisEndDate = this.getEndDate();
thisEndDate = thisEndDate == null ? DateUtils.getBusinessLocalDate() : thisEndDate;
final LocalDate thatFromDate = that.getFromDateAsLocalDate();
LocalDate thatEndDate = that.getEndDateAsLocalDate();
final LocalDate thatFromDate = that.getFromDate();
LocalDate thatEndDate = that.getEndDate();
thatEndDate = thatEndDate == null ? DateUtils.getBusinessLocalDate() : thatEndDate;
final LocalDateInterval thisInterval = LocalDateInterval.create(thisFromDate, thisEndDate);
@@ -153,8 +149,8 @@ public class InterestRateChartFields {
}
public boolean isApplicableChartFor(final LocalDate target) {
final LocalDate endDate = this.endDate == null ? DateUtils.getBusinessLocalDate() : this.getEndDateAsLocalDate();
final LocalDateInterval interval = LocalDateInterval.create(getFromDateAsLocalDate(), endDate);
final LocalDate endDate = this.endDate == null ? DateUtils.getBusinessLocalDate() : this.getEndDate();
final LocalDateInterval interval = LocalDateInterval.create(getFromDate(), endDate);
return interval.contains(target);
}
@@ -327,7 +327,7 @@ public class GuarantorDomainServiceImpl implements GuarantorDomainService {
if (loan.isApproved() && !loan.isDisbursed()) {
final List<SavingsAccountTransaction> transactions = new ArrayList<>();
for (final SavingsAccountTransaction transaction : savingsAccount.getTransactions()) {
if (!transaction.getTransactionLocalDate().isAfter(loan.getApprovedOnDate())) {
if (!transaction.getTransactionDate().isAfter(loan.getApprovedOnDate())) {
transactions.add(transaction);
}
}
@@ -187,12 +187,12 @@ public class GuarantorWritePlatformServiceJpaRepositoryIImpl implements Guaranto
private void validateGuarantorSavingsAccountActivationDateWithLoanSubmittedOnDate(final Loan loan,
final SavingsAccount savingsAccount) {
if (loan.getSubmittedOnDate().isBefore(savingsAccount.getActivationLocalDate())) {
if (loan.getSubmittedOnDate().isBefore(savingsAccount.getActivationDate())) {
throw new GeneralPlatformDomainRuleException(
"error.msg.guarantor.saving.account.activation.date.is.on.or.before.loan.submitted.on.date",
"Guarantor saving account activation date [" + savingsAccount.getActivationLocalDate()
"Guarantor saving account activation date [" + savingsAccount.getActivationDate()
+ "] is on or before the loan submitted on date [" + loan.getSubmittedOnDate() + "]",
savingsAccount.getActivationLocalDate(), loan.getSubmittedOnDate());
savingsAccount.getActivationDate(), loan.getSubmittedOnDate());
}
}
@@ -23,6 +23,7 @@ import java.util.ArrayList;
import java.util.Collection;
import org.apache.fineract.infrastructure.codes.data.CodeValueData;
import org.apache.fineract.infrastructure.core.data.EnumOptionData;
import org.apache.fineract.infrastructure.core.service.DateUtils;
import org.apache.fineract.portfolio.interestratechart.data.InterestRateChartData;
import org.apache.fineract.portfolio.interestratechart.data.InterestRateChartSlabData;
@@ -159,12 +160,11 @@ public final class DepositAccountInterestRateChartData {
if (this.chartSlabs == null) {
this.chartSlabs = new ArrayList<>();
}
this.chartSlabs.add(chartSlab);
}
public boolean isFromDateAfter(final LocalDate compareDate) {
return (compareDate == null) ? false : this.fromDate.isAfter(compareDate);
return compareDate != null && DateUtils.isAfter(this.fromDate, compareDate);
}
public LocalDate endDate() {
@@ -20,10 +20,8 @@ package org.apache.fineract.portfolio.savings.data;
import java.math.BigDecimal;
import java.time.LocalDate;
import java.time.LocalDateTime;
import java.time.format.DateTimeFormatter;
import org.apache.fineract.portfolio.paymentdetail.domain.PaymentDetail;
import org.apache.fineract.useradministration.domain.AppUser;
public class SavingsAccountTransactionDTO {
@@ -31,24 +29,9 @@ public class SavingsAccountTransactionDTO {
private final LocalDate transactionDate;
private final BigDecimal transactionAmount;
private final PaymentDetail paymentDetail;
private final LocalDateTime createdDate;
private final Long savingsAccountId;
private final AppUser appUser;
private final Integer depositAccountType;
public SavingsAccountTransactionDTO(final DateTimeFormatter formatter, final LocalDate transactionDate,
final BigDecimal transactionAmount, final PaymentDetail paymentDetail, final LocalDateTime createdDate, final AppUser appUser,
final Integer depositAccountType) {
this.formatter = formatter;
this.transactionDate = transactionDate;
this.transactionAmount = transactionAmount;
this.paymentDetail = paymentDetail;
this.createdDate = createdDate;
this.savingsAccountId = null;
this.appUser = appUser;
this.depositAccountType = depositAccountType;
}
/**
* This constructor is used for bulk deposit transactions
*
@@ -56,19 +39,15 @@ public class SavingsAccountTransactionDTO {
* @param transactionDate
* @param transactionAmount
* @param paymentDetail
* @param createdDate
* @param savingsAccountId
*/
public SavingsAccountTransactionDTO(DateTimeFormatter formatter, LocalDate transactionDate, BigDecimal transactionAmount,
PaymentDetail paymentDetail, LocalDateTime createdDate, Long savingsAccountId, AppUser appUser,
final Integer depositAccountType) {
PaymentDetail paymentDetail, Long savingsAccountId, final Integer depositAccountType) {
this.formatter = formatter;
this.transactionDate = transactionDate;
this.transactionAmount = transactionAmount;
this.paymentDetail = paymentDetail;
this.createdDate = createdDate;
this.savingsAccountId = savingsAccountId;
this.appUser = appUser;
this.depositAccountType = depositAccountType;
}
@@ -88,18 +67,10 @@ public class SavingsAccountTransactionDTO {
return this.paymentDetail;
}
public LocalDateTime getCreatedDate() {
return this.createdDate;
}
public Long getSavingsAccountId() {
return this.savingsAccountId;
}
public AppUser getAppUser() {
return this.appUser;
}
public Integer getAccountType() {
return this.depositAccountType;
}
@@ -37,7 +37,6 @@ import com.google.gson.reflect.TypeToken;
import java.lang.reflect.Type;
import java.math.BigDecimal;
import java.time.LocalDate;
import java.time.LocalDateTime;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.HashSet;
@@ -83,7 +82,6 @@ public class SavingsAccountTransactionDataValidator {
}
public void validateTransactionWithPivotDate(final LocalDate transactionDate, final SavingsAccount savingsAccount) {
final boolean backdatedTxnsAllowedTill = this.configurationDomainService.retrievePivotDateConfig();
final boolean isRelaxingDaysConfigOn = this.configurationDomainService.isRelaxingDaysConfigForPivotDateEnabled();
@@ -94,14 +92,13 @@ public class SavingsAccountTransactionDataValidator {
if (isRelaxingDaysConfigOn) {
pivotDate = pivotDate.minusDays(this.configurationDomainService.retrieveRelaxingDaysConfigForPivotDate());
}
if (pivotDate.isAfter(transactionDate)) {
if (DateUtils.isAfter(pivotDate, transactionDate)) {
throw new TransactionBeforePivotDateNotAllowed(transactionDate, pivotDate);
}
}
}
public void validate(final JsonCommand command) {
final String json = command.json();
if (StringUtils.isBlank(json)) {
@@ -296,7 +293,7 @@ public class SavingsAccountTransactionDataValidator {
}
// compare two dates now
if (lastTransactionDate != null && transactionDate.isBefore(lastTransactionDate)) {
if (DateUtils.isBefore(transactionDate, lastTransactionDate)) {
baseDataValidator.parameter(SavingsApiConstants.dateParamName).value(lastTransactionDate).failWithCode(
"validation.msg.date.can.not.be.before.last.transaction.date", "Amount can be put on hold only after last transaction");
}
@@ -304,8 +301,7 @@ public class SavingsAccountTransactionDataValidator {
throwExceptionIfValidationWarningsExist(dataValidationErrors);
}
public SavingsAccountTransaction validateReleaseAmountAndAssembleForm(final SavingsAccountTransaction holdTransaction,
final AppUser createdUser) {
public SavingsAccountTransaction validateReleaseAmountAndAssembleForm(final SavingsAccountTransaction holdTransaction) {
final List<ApiParameterError> dataValidationErrors = new ArrayList<>();
final DataValidatorBuilder baseDataValidator = new DataValidatorBuilder(dataValidationErrors)
.resource(SAVINGS_ACCOUNT_RESOURCE_NAME);
@@ -326,10 +322,8 @@ public class SavingsAccountTransactionDataValidator {
}
throwExceptionIfValidationWarningsExist(dataValidationErrors);
LocalDateTime createdDate = DateUtils.getLocalDateTimeOfSystem();
LocalDate transactionDate = DateUtils.getBusinessLocalDate();
SavingsAccountTransaction transaction = SavingsAccountTransaction.releaseAmount(holdTransaction, transactionDate, createdDate,
createdUser);
SavingsAccountTransaction transaction = SavingsAccountTransaction.releaseAmount(holdTransaction, transactionDate);
return transaction;
}
@@ -69,7 +69,6 @@ import org.apache.fineract.infrastructure.core.api.JsonCommand;
import org.apache.fineract.infrastructure.core.exception.InvalidJsonException;
import org.apache.fineract.infrastructure.core.exception.UnsupportedParameterException;
import org.apache.fineract.infrastructure.core.serialization.FromJsonHelper;
import org.apache.fineract.infrastructure.core.service.DateUtils;
import org.apache.fineract.infrastructure.core.service.ExternalIdFactory;
import org.apache.fineract.infrastructure.security.service.PlatformSecurityContext;
import org.apache.fineract.organisation.staff.domain.Staff;
@@ -358,7 +357,7 @@ public class DepositAccountAssembler {
if (account != null) {
account.setHelpers(this.savingsAccountTransactionSummaryWrapper, this.savingsHelper);
account.validateNewApplicationState(DateUtils.getBusinessLocalDate(), depositAccountType.resourceName());
account.validateNewApplicationState(depositAccountType.resourceName());
}
return account;
@@ -448,7 +447,6 @@ public class DepositAccountAssembler {
public Collection<SavingsAccountTransactionDTO> assembleBulkMandatorySavingsAccountTransactionDTOs(final JsonCommand command,
final PaymentDetail paymentDetail) {
AppUser user = getAppUserIfPresent();
final String json = command.json();
if (StringUtils.isBlank(json)) {
throw new InvalidJsonException();
@@ -478,7 +476,7 @@ public class DepositAccountAssembler {
detail = this.paymentDetailAssembler.fetchPaymentDetail(savingsTransactionElement);
}
final SavingsAccountTransactionDTO savingsAccountTransactionDTO = new SavingsAccountTransactionDTO(formatter,
transactionDate, dueAmount, detail, DateUtils.getLocalDateTimeOfSystem(), savingsId, user, depositAccountType);
transactionDate, dueAmount, detail, savingsId, depositAccountType);
savingsAccountTransactions.add(savingsAccountTransactionDTO);
}
}
@@ -486,13 +484,4 @@ public class DepositAccountAssembler {
return savingsAccountTransactions;
}
private AppUser getAppUserIfPresent() {
AppUser user = null;
if (this.context != null) {
user = this.context.getAuthenticatedUserIfPresent();
}
return user;
}
}
@@ -42,19 +42,18 @@ public interface DepositAccountDomainService {
BigDecimal transactionAmount, PaymentDetail paymentDetail, boolean isRegularTransaction);
Long handleFDAccountClosure(FixedDepositAccount account, PaymentDetail paymentDetail, AppUser user, JsonCommand command,
LocalDate tenantsTodayDate, Map<String, Object> changes);
@Transactional
Long handleFDAccountMaturityClosure(FixedDepositAccount account, PaymentDetail paymentDetail, AppUser user, LocalDate tenantsTodayDate,
DateTimeFormatter fmt, LocalDate closedDate, Integer onAccountClosureId, Long toSavingsId, String transferDescription,
Map<String, Object> changes);
@Transactional
Long handleFDAccountMaturityClosure(FixedDepositAccount account, PaymentDetail paymentDetail, AppUser user, DateTimeFormatter fmt,
LocalDate closedDate, Integer onAccountClosureId, Long toSavingsId, String transferDescription, Map<String, Object> changes);
Long handleRDAccountClosure(RecurringDepositAccount account, PaymentDetail paymentDetail, AppUser user, JsonCommand command,
LocalDate tenantsTodayDate, Map<String, Object> changes);
Map<String, Object> changes);
Long handleFDAccountPreMatureClosure(FixedDepositAccount account, PaymentDetail paymentDetail, AppUser user, JsonCommand command,
LocalDate tenantsTodayDate, Map<String, Object> changes);
Map<String, Object> changes);
Long handleRDAccountPreMatureClosure(RecurringDepositAccount account, PaymentDetail paymentDetail, AppUser user, JsonCommand command,
LocalDate tenantsTodayDate, Map<String, Object> changes);
Map<String, Object> changes);
}
@@ -40,8 +40,6 @@ import org.apache.fineract.infrastructure.core.api.JsonCommand;
import org.apache.fineract.infrastructure.core.domain.ExternalId;
import org.apache.fineract.infrastructure.core.exception.GeneralPlatformDomainRuleException;
import org.apache.fineract.infrastructure.core.service.DateUtils;
import org.apache.fineract.infrastructure.security.service.PlatformSecurityContext;
import org.apache.fineract.organisation.monetary.domain.ApplicationCurrencyRepositoryWrapper;
import org.apache.fineract.portfolio.account.PortfolioAccountType;
import org.apache.fineract.portfolio.account.data.AccountTransferDTO;
import org.apache.fineract.portfolio.account.domain.AccountTransferType;
@@ -69,9 +67,7 @@ import org.springframework.transaction.annotation.Transactional;
@Service
public class DepositAccountDomainServiceJpa implements DepositAccountDomainService {
private final PlatformSecurityContext context;
private final SavingsAccountRepositoryWrapper savingsAccountRepository;
private final ApplicationCurrencyRepositoryWrapper applicationCurrencyRepositoryWrapper;
private final JournalEntryWritePlatformService journalEntryWritePlatformService;
private final AccountNumberGenerator accountNumberGenerator;
private final DepositAccountAssembler depositAccountAssembler;
@@ -82,18 +78,14 @@ public class DepositAccountDomainServiceJpa implements DepositAccountDomainServi
private final CalendarInstanceRepository calendarInstanceRepository;
@Autowired
public DepositAccountDomainServiceJpa(final PlatformSecurityContext context,
final SavingsAccountRepositoryWrapper savingsAccountRepository,
final ApplicationCurrencyRepositoryWrapper applicationCurrencyRepositoryWrapper,
public DepositAccountDomainServiceJpa(final SavingsAccountRepositoryWrapper savingsAccountRepository,
final JournalEntryWritePlatformService journalEntryWritePlatformService, final AccountNumberGenerator accountNumberGenerator,
final DepositAccountAssembler depositAccountAssembler, final SavingsAccountDomainService savingsAccountDomainService,
final AccountTransfersWritePlatformService accountTransfersWritePlatformService,
final ConfigurationDomainService configurationDomainService,
final AccountNumberFormatRepositoryWrapper accountNumberFormatRepository,
final CalendarInstanceRepository calendarInstanceRepository) {
this.context = context;
this.savingsAccountRepository = savingsAccountRepository;
this.applicationCurrencyRepositoryWrapper = applicationCurrencyRepositoryWrapper;
this.journalEntryWritePlatformService = journalEntryWritePlatformService;
this.accountNumberGenerator = accountNumberGenerator;
this.depositAccountAssembler = depositAccountAssembler;
@@ -135,7 +127,6 @@ public class DepositAccountDomainServiceJpa implements DepositAccountDomainServi
public SavingsAccountTransaction handleRDDeposit(final RecurringDepositAccount account, final DateTimeFormatter fmt,
final LocalDate transactionDate, final BigDecimal transactionAmount, final PaymentDetail paymentDetail,
final boolean isRegularTransaction) {
AppUser user = getAppUserIfPresent();
final boolean isSavingsInterestPostingAtCurrentPeriodEnd = this.configurationDomainService
.isSavingsInterestPostingAtCurrentPeriodEnd();
final Integer financialYearBeginningMonth = this.configurationDomainService.retrieveFinancialYearBeginningMonth();
@@ -151,7 +142,7 @@ public class DepositAccountDomainServiceJpa implements DepositAccountDomainServi
final boolean isAnyActivationChargesDue = isAnyActivationChargesDue(account);
if (isAnyActivationChargesDue) {
updateExistingTransactionsDetails(account, existingTransactionIds, existingReversedTransactionIds);
account.processAccountUponActivation(isSavingsInterestPostingAtCurrentPeriodEnd, financialYearBeginningMonth, user);
account.processAccountUponActivation(isSavingsInterestPostingAtCurrentPeriodEnd, financialYearBeginningMonth);
this.savingsAccountRepository.saveAndFlush(account);
}
account.handleScheduleInstallments(deposit);
@@ -193,8 +184,7 @@ public class DepositAccountDomainServiceJpa implements DepositAccountDomainServi
@Transactional
@Override
public Long handleFDAccountClosure(final FixedDepositAccount account, final PaymentDetail paymentDetail, final AppUser user,
final JsonCommand command, final LocalDate tenantsTodayDate, final Map<String, Object> changes) {
final JsonCommand command, final Map<String, Object> changes) {
final boolean isSavingsInterestPostingAtCurrentPeriodEnd = this.configurationDomainService
.isSavingsInterestPostingAtCurrentPeriodEnd();
final Integer financialYearBeginningMonth = this.configurationDomainService.retrieveFinancialYearBeginningMonth();
@@ -204,9 +194,7 @@ public class DepositAccountDomainServiceJpa implements DepositAccountDomainServi
final boolean isPreMatureClosure = false;
final Set<Long> existingTransactionIds = new HashSet<>();
final Set<Long> existingReversedTransactionIds = new HashSet<>();
/***
* Update account transactionIds for post journal entries.
*/
// Update account transactionIds for post journal entries.
updateExistingTransactionsDetails(account, existingTransactionIds, existingReversedTransactionIds);
/*
* final SavingsAccountTransactionDTO transactionDTO = new SavingsAccountTransactionDTO(fmt, transactionDate,
@@ -254,7 +242,7 @@ public class DepositAccountDomainServiceJpa implements DepositAccountDomainServi
savingsTransactionId = withdrawal.getId();
}
account.close(user, command, tenantsTodayDate, changes);
account.close(user, command, changes);
this.savingsAccountRepository.save(account);
return savingsTransactionId;
@@ -263,8 +251,8 @@ public class DepositAccountDomainServiceJpa implements DepositAccountDomainServi
@Transactional
@Override
public Long handleFDAccountMaturityClosure(final FixedDepositAccount account, final PaymentDetail paymentDetail, final AppUser user,
final LocalDate tenantsTodayDate, final DateTimeFormatter fmt, final LocalDate closedDate, final Integer onAccountClosureId,
final Long toSavingsId, final String transferDescription, Map<String, Object> changes) {
final DateTimeFormatter fmt, final LocalDate closedDate, final Integer onAccountClosureId, final Long toSavingsId,
final String transferDescription, Map<String, Object> changes) {
final boolean isSavingsInterestPostingAtCurrentPeriodEnd = this.configurationDomainService
.isSavingsInterestPostingAtCurrentPeriodEnd();
@@ -329,7 +317,7 @@ public class DepositAccountDomainServiceJpa implements DepositAccountDomainServi
}
// if(!processMaturityInstructionOnly)
// account.close(user, command, tenantsTodayDate, changes);
// account.close(user, command, changes);
this.savingsAccountRepository.save(account);
@@ -341,7 +329,7 @@ public class DepositAccountDomainServiceJpa implements DepositAccountDomainServi
@Transactional
@Override
public Long handleRDAccountClosure(final RecurringDepositAccount account, final PaymentDetail paymentDetail, final AppUser user,
final JsonCommand command, final LocalDate tenantsTodayDate, final Map<String, Object> changes) {
final JsonCommand command, final Map<String, Object> changes) {
final boolean isSavingsInterestPostingAtCurrentPeriodEnd = this.configurationDomainService
.isSavingsInterestPostingAtCurrentPeriodEnd();
@@ -352,9 +340,7 @@ public class DepositAccountDomainServiceJpa implements DepositAccountDomainServi
final boolean isPreMatureClosure = false;
final Set<Long> existingTransactionIds = new HashSet<>();
final Set<Long> existingReversedTransactionIds = new HashSet<>();
/***
* Update account transactionIds for post journal entries.
*/
// Update account transactionIds for post journal entries.
updateExistingTransactionsDetails(account, existingTransactionIds, existingReversedTransactionIds);
final MathContext mc = MathContext.DECIMAL64;
@@ -383,7 +369,7 @@ public class DepositAccountDomainServiceJpa implements DepositAccountDomainServi
Integer frequency = CalendarUtils.getInterval(calendar.getRecurrence());
frequency = frequency == -1 ? 1 : frequency;
reinvestedDeposit.generateSchedule(frequencyType, frequency, calendar);
reinvestedDeposit.processAccountUponActivation(fmt, user, postReversals);
reinvestedDeposit.processAccountUponActivation(fmt, postReversals);
reinvestedDeposit.updateMaturityDateAndAmount(mc, isPreMatureClosure, isSavingsInterestPostingAtCurrentPeriodEnd,
financialYearBeginningMonth);
this.savingsAccountRepository.save(reinvestedDeposit);
@@ -411,7 +397,7 @@ public class DepositAccountDomainServiceJpa implements DepositAccountDomainServi
savingsTransactionId = withdrawal.getId();
}
account.close(user, command, tenantsTodayDate, changes);
account.close(user, command, changes);
this.savingsAccountRepository.save(account);
@@ -456,7 +442,7 @@ public class DepositAccountDomainServiceJpa implements DepositAccountDomainServi
@Transactional
@Override
public Long handleFDAccountPreMatureClosure(final FixedDepositAccount account, final PaymentDetail paymentDetail, final AppUser user,
final JsonCommand command, final LocalDate tenantsTodayDate, final Map<String, Object> changes) {
final JsonCommand command, final Map<String, Object> changes) {
final boolean isSavingsInterestPostingAtCurrentPeriodEnd = this.configurationDomainService
.isSavingsInterestPostingAtCurrentPeriodEnd();
@@ -467,9 +453,7 @@ public class DepositAccountDomainServiceJpa implements DepositAccountDomainServi
final boolean isPreMatureClosure = true;
final Set<Long> existingTransactionIds = new HashSet<>();
final Set<Long> existingReversedTransactionIds = new HashSet<>();
/***
* Update account transactionIds for post journal entries.
*/
// Update account transactionIds for post journal entries.
updateExistingTransactionsDetails(account, existingTransactionIds, existingReversedTransactionIds);
final LocalDate closedDate = command.localDateValueOfParameterNamed(SavingsApiConstants.closedOnDateParamName);
@@ -502,7 +486,7 @@ public class DepositAccountDomainServiceJpa implements DepositAccountDomainServi
savingsTransactionId = withdrawal.getId();
}
account.prematureClosure(user, command, tenantsTodayDate, changes);
account.prematureClosure(user, command, changes);
this.savingsAccountRepository.save(account);
@@ -513,7 +497,7 @@ public class DepositAccountDomainServiceJpa implements DepositAccountDomainServi
@Transactional
@Override
public Long handleRDAccountPreMatureClosure(final RecurringDepositAccount account, final PaymentDetail paymentDetail,
final AppUser user, final JsonCommand command, final LocalDate tenantsTodayDate, final Map<String, Object> changes) {
final AppUser user, final JsonCommand command, final Map<String, Object> changes) {
final boolean isSavingsInterestPostingAtCurrentPeriodEnd = this.configurationDomainService
.isSavingsInterestPostingAtCurrentPeriodEnd();
@@ -558,7 +542,7 @@ public class DepositAccountDomainServiceJpa implements DepositAccountDomainServi
savingsTransactionId = withdrawal.getId();
}
account.prematureClosure(user, command, tenantsTodayDate, changes);
account.prematureClosure(user, command, changes);
this.savingsAccountRepository.save(account);
postJournalEntries(account, existingTransactionIds, existingReversedTransactionIds, isAccountTransfer);
return savingsTransactionId;
@@ -592,12 +576,4 @@ public class DepositAccountDomainServiceJpa implements DepositAccountDomainServi
}
}
}
private AppUser getAppUserIfPresent() {
AppUser user = null;
if (this.context != null) {
user = this.context.getAuthenticatedUserIfPresent();
}
return user;
}
}
@@ -103,12 +103,12 @@ public class DepositAccountInterestRateChart extends AbstractPersistableCustom {
return null;
}
public LocalDate getFromDateAsLocalDate() {
return this.chartFields.getFromDateAsLocalDate();
public LocalDate getFromDate() {
return this.chartFields.getFromDate();
}
public LocalDate getEndDateAsLocalDate() {
return this.chartFields.getEndDateAsLocalDate();
public LocalDate getEndDate() {
return this.chartFields.getEndDate();
}
public Long savingsAccountId() {
@@ -18,6 +18,8 @@
*/
package org.apache.fineract.portfolio.savings.domain;
import static org.apache.fineract.infrastructure.core.service.DateUtils.getSystemZoneId;
import jakarta.persistence.CascadeType;
import jakarta.persistence.Column;
import jakarta.persistence.Entity;
@@ -28,8 +30,9 @@ import jakarta.persistence.Table;
import java.math.BigDecimal;
import java.time.LocalDate;
import java.time.LocalDateTime;
import org.apache.fineract.infrastructure.core.domain.AbstractPersistableCustom;
import org.apache.fineract.infrastructure.core.service.DateUtils;
import java.time.OffsetDateTime;
import java.util.Optional;
import org.apache.fineract.infrastructure.core.domain.AbstractAuditableWithUTCDateTimeCustom;
import org.apache.fineract.organisation.monetary.domain.MonetaryCurrency;
import org.apache.fineract.organisation.monetary.domain.Money;
import org.apache.fineract.portfolio.loanaccount.guarantor.domain.GuarantorFundingTransaction;
@@ -37,7 +40,7 @@ import org.apache.fineract.portfolio.savings.DepositAccountOnHoldTransactionType
@Entity
@Table(name = "m_deposit_account_on_hold_transaction")
public class DepositAccountOnHoldTransaction extends AbstractPersistableCustom {
public class DepositAccountOnHoldTransaction extends AbstractAuditableWithUTCDateTimeCustom {
@ManyToOne
@JoinColumn(name = "savings_account_id", nullable = true)
@@ -55,8 +58,9 @@ public class DepositAccountOnHoldTransaction extends AbstractPersistableCustom {
@Column(name = "is_reversed", nullable = false)
private boolean reversed;
@Column(name = "created_date", nullable = false)
private LocalDateTime createdDate;
@Deprecated
@Column(name = "created_date", nullable = true)
private LocalDateTime createdDateToRemove;
@OneToOne(cascade = CascadeType.ALL, mappedBy = "depositAccountOnHoldTransaction", optional = true, orphanRemoval = true)
private GuarantorFundingTransaction guarantorFundingTransaction;
@@ -69,7 +73,7 @@ public class DepositAccountOnHoldTransaction extends AbstractPersistableCustom {
this.amount = amount;
this.transactionType = transactionType.getValue();
this.transactionDate = transactionDate;
this.createdDate = DateUtils.getLocalDateTimeOfSystem();
this.createdDateToRemove = null; // #audit backward compatibility deprecated
this.reversed = reversed;
}
@@ -87,14 +91,30 @@ public class DepositAccountOnHoldTransaction extends AbstractPersistableCustom {
reversed);
}
public SavingsAccount getSavingsAccount() {
return savingsAccount;
}
public BigDecimal getAmount() {
return this.amount;
}
public Money getAmountMoney(final MonetaryCurrency currency) {
public Money getAmount(final MonetaryCurrency currency) {
return Money.of(currency, this.amount);
}
public DepositAccountOnHoldTransactionType getTransactionType() {
return DepositAccountOnHoldTransactionType.fromInt(this.transactionType);
}
public LocalDate getTransactionDate() {
return this.transactionDate;
}
public MonetaryCurrency getCurrency() {
return getSavingsAccount().getCurrency();
}
public void reverseTransaction() {
this.reversed = true;
if (this.getTransactionType().isHold()) {
@@ -104,12 +124,10 @@ public class DepositAccountOnHoldTransaction extends AbstractPersistableCustom {
}
}
public DepositAccountOnHoldTransactionType getTransactionType() {
return DepositAccountOnHoldTransactionType.fromInt(this.transactionType);
@Override
public Optional<OffsetDateTime> getCreatedDate() {
// #audit backward compatibility keep system datetime
return Optional.ofNullable(super.getCreatedDate()
.orElse(createdDateToRemove == null ? null : createdDateToRemove.atZone(getSystemZoneId()).toOffsetDateTime()));
}
public LocalDate getTransactionDate() {
return this.transactionDate;
}
}
@@ -224,7 +224,7 @@ public class DepositAccountTermAndPreClosure extends AbstractPersistableCustom {
this.depositAmount = depositAmount;
}
public LocalDate getMaturityLocalDate() {
public LocalDate getMaturityDate() {
return this.maturityDate;
}
@@ -247,7 +247,7 @@ public class DepositAccountTermAndPreClosure extends AbstractPersistableCustom {
}
Integer actualDepositPeriod = this.depositPeriod;
if (depositFromDate == null || getMaturityLocalDate() == null || interestPostingUpToDate.isEqual(getMaturityLocalDate())) {
if (depositFromDate == null || getMaturityDate() == null || DateUtils.isEqual(interestPostingUpToDate, getMaturityDate())) {
return actualDepositPeriod;
}
@@ -197,18 +197,8 @@ public class FixedDepositAccount extends SavingsAccount {
String refNo = null;
final Money transactionAmountMoney = Money.of(getCurrency(), this.accountTermAndPreClosure.depositAmount());
final SavingsAccountTransaction transaction = SavingsAccountTransaction.deposit(null, office(), null,
this.accountSubmittedOrActivationDate(), transactionAmountMoney, DateUtils.getLocalDateTimeOfSystem(), null, refNo); // TODO:
// verify
// if
// it
// is
// ok
// to
// pass
// null
// for
// AppUser
transaction.updateRunningBalance(transactionAmountMoney);
this.accountSubmittedOrActivationDate(), transactionAmountMoney, refNo);
transaction.setRunningBalance(transactionAmountMoney);
transaction.updateCumulativeBalanceAndDates(this.getCurrency(), interestCalculatedUpto());
allTransactions.add(transaction);
updateMaturityDateAndAmount(mc, allTransactions, isPreMatureClosure, isSavingsInterestPostingAtCurrentPeriodEnd,
@@ -260,8 +250,7 @@ public class FixedDepositAccount extends SavingsAccount {
}
}
final LocalDate todayDate = DateUtils.getBusinessLocalDate();
if (!this.maturityDate().isAfter(todayDate)) {
if (!DateUtils.isDateInTheFuture(maturityDate())) {
// update account status
this.status = SavingsAccountStatusType.MATURED.getValue();
postMaturityInterest(isSavingsInterestPostingAtCurrentPeriodEnd, financialYearBeginningMonth);
@@ -338,14 +327,12 @@ public class FixedDepositAccount extends SavingsAccount {
}
this.summary.updateFromInterestPeriodSummaries(this.currency, allPostingPeriods);
this.savingsHelper.calculateInterestForAllPostingPeriods(this.currency, allPostingPeriods, this.getLockedInUntilLocalDate(),
this.savingsHelper.calculateInterestForAllPostingPeriods(this.currency, allPostingPeriods, getLockedInUntilDate(),
isTransferInterestToOtherAccount());
return allPostingPeriods;
}
public void prematureClosure(final AppUser currentUser, final JsonCommand command, final LocalDate tenantsTodayDate,
final Map<String, Object> actualChanges) {
public void prematureClosure(final AppUser currentUser, final JsonCommand command, final Map<String, Object> actualChanges) {
final List<ApiParameterError> dataValidationErrors = new ArrayList<>();
final DataValidatorBuilder baseDataValidator = new DataValidatorBuilder(dataValidationErrors)
.resource(FIXED_DEPOSIT_ACCOUNT_RESOURCE_NAME + DepositsApiConstants.preMatureCloseAction);
@@ -362,14 +349,13 @@ public class FixedDepositAccount extends SavingsAccount {
final DateTimeFormatter fmt = DateTimeFormatter.ofPattern(command.dateFormat()).withLocale(locale);
final LocalDate closedDate = command.localDateValueOfParameterNamed(SavingsApiConstants.closedOnDateParamName);
if (closedDate.isBefore(getActivationLocalDate())) {
if (DateUtils.isBefore(closedDate, getActivationDate())) {
baseDataValidator.reset().parameter(SavingsApiConstants.closedOnDateParamName).value(closedDate)
.failWithCode("must.be.after.activation.date");
if (!dataValidationErrors.isEmpty()) {
throw new PlatformApiDataValidationException(dataValidationErrors);
}
}
if (isAccountLocked(closedDate)) {
baseDataValidator.reset().parameter(SavingsApiConstants.closedOnDateParamName).value(closedDate)
.failWithCode("must.be.after.lockin.period");
@@ -377,16 +363,14 @@ public class FixedDepositAccount extends SavingsAccount {
throw new PlatformApiDataValidationException(dataValidationErrors);
}
}
if (closedDate.isAfter(maturityDate())) {
if (maturityDate() != null && DateUtils.isAfter(closedDate, maturityDate())) {
baseDataValidator.reset().parameter(SavingsApiConstants.closedOnDateParamName).value(closedDate)
.failWithCode("must.be.before.maturity.date");
if (!dataValidationErrors.isEmpty()) {
throw new PlatformApiDataValidationException(dataValidationErrors);
}
}
if (closedDate.isAfter(tenantsTodayDate)) {
if (DateUtils.isAfterBusinessDate(closedDate)) {
baseDataValidator.reset().parameter(SavingsApiConstants.closedOnDateParamName).value(closedDate)
.failWithCode("cannot.be.a.future.date");
if (!dataValidationErrors.isEmpty()) {
@@ -437,9 +421,7 @@ public class FixedDepositAccount extends SavingsAccount {
return Money.of(this.currency, this.accountTermAndPreClosure.depositAmount());
}
public void close(final AppUser currentUser, final JsonCommand command, final LocalDate tenantsTodayDate,
final Map<String, Object> actualChanges) {
public void close(final AppUser currentUser, final JsonCommand command, final Map<String, Object> actualChanges) {
final List<ApiParameterError> dataValidationErrors = new ArrayList<>();
final DataValidatorBuilder baseDataValidator = new DataValidatorBuilder(dataValidationErrors)
.resource(FIXED_DEPOSIT_ACCOUNT_RESOURCE_NAME + SavingsApiConstants.closeAction);
@@ -456,21 +438,21 @@ public class FixedDepositAccount extends SavingsAccount {
final DateTimeFormatter fmt = DateTimeFormatter.ofPattern(command.dateFormat()).withLocale(locale);
final LocalDate closedDate = command.localDateValueOfParameterNamed(SavingsApiConstants.closedOnDateParamName);
if (closedDate.isBefore(getActivationLocalDate())) {
if (DateUtils.isBefore(closedDate, getActivationDate())) {
baseDataValidator.reset().parameter(SavingsApiConstants.closedOnDateParamName).value(closedDate)
.failWithCode("must.be.after.activation.date");
if (!dataValidationErrors.isEmpty()) {
throw new PlatformApiDataValidationException(dataValidationErrors);
}
}
if (closedDate.isBefore(maturityDate())) {
if (DateUtils.isBefore(closedDate, maturityDate())) {
baseDataValidator.reset().parameter(SavingsApiConstants.closedOnDateParamName).value(closedDate)
.failWithCode("must.be.after.account.maturity.date");
if (!dataValidationErrors.isEmpty()) {
throw new PlatformApiDataValidationException(dataValidationErrors);
}
}
if (closedDate.isAfter(tenantsTodayDate)) {
if (DateUtils.isAfterBusinessDate(closedDate)) {
baseDataValidator.reset().parameter(SavingsApiConstants.closedOnDateParamName).value(closedDate)
.failWithCode("cannot.be.a.future.date");
if (!dataValidationErrors.isEmpty()) {
@@ -548,7 +530,8 @@ public class FixedDepositAccount extends SavingsAccount {
LocalDate interestPostingTransactionDate = interestPostingPeriod.dateOfPostingTransaction();
interestPostingTransactionDate = interestPostingTransactionDate.isAfter(interestPostingUpToDate) ? interestPostingUpToDate
interestPostingTransactionDate = DateUtils.isAfter(interestPostingTransactionDate, interestPostingUpToDate)
? interestPostingUpToDate
: interestPostingTransactionDate;
final Money interestEarnedToBePostedForPeriod = interestPostingPeriod.getInterestEarned();
@@ -669,14 +652,14 @@ public class FixedDepositAccount extends SavingsAccount {
private LocalDate interestPostingUpToDate(final LocalDate interestPostingDate) {
LocalDate interestPostingUpToDate = interestPostingDate;
final LocalDate uptoMaturityDate = interestCalculatedUpto();
if (uptoMaturityDate != null && uptoMaturityDate.isBefore(interestPostingDate)) {
if (uptoMaturityDate != null && DateUtils.isBefore(uptoMaturityDate, interestPostingDate)) {
interestPostingUpToDate = uptoMaturityDate;
}
return interestPostingUpToDate;
}
public LocalDate maturityDate() {
return this.accountTermAndPreClosure.getMaturityLocalDate();
return this.accountTermAndPreClosure.getMaturityDate();
}
public BigDecimal maturityAmount() {
@@ -695,8 +678,8 @@ public class FixedDepositAccount extends SavingsAccount {
}
@Override
public Map<String, Object> activate(final AppUser currentUser, final JsonCommand command, final LocalDate tenantsTodayDate) {
final Map<String, Object> actualChanges = super.activate(currentUser, command, tenantsTodayDate);
public Map<String, Object> activate(final AppUser currentUser, final JsonCommand command) {
final Map<String, Object> actualChanges = super.activate(currentUser, command);
// if (isAccountLocked(calculateMaturityDate())) {
// final List<ApiParameterError> dataValidationErrors = new
@@ -770,8 +753,8 @@ public class FixedDepositAccount extends SavingsAccount {
}
if (this.chart != null) {
final LocalDate chartFromDate = this.chart.getFromDateAsLocalDate();
LocalDate chartEndDate = this.chart.getEndDateAsLocalDate();
final LocalDate chartFromDate = this.chart.getFromDate();
LocalDate chartEndDate = this.chart.getEndDate();
chartEndDate = chartEndDate == null ? DateUtils.getBusinessLocalDate() : chartEndDate;
final LocalDateInterval chartInterval = LocalDateInterval.create(chartFromDate, chartEndDate);
@@ -783,7 +766,7 @@ public class FixedDepositAccount extends SavingsAccount {
BigDecimal applicableInterestRate = this.chart.getApplicableInterestRate(depositAmount, depositStartDate(),
calculateMaturityDate(), this.client);
if (applicableInterestRate.compareTo(BigDecimal.ZERO) == 0 ? Boolean.TRUE : Boolean.FALSE) {
if (applicableInterestRate.compareTo(BigDecimal.ZERO) == 0) {
baseDataValidator.reset()
.failWithCodeNoParameterAddedToErrorCode("no.applicable.interest.rate.is.found.based.on.amount.and.deposit.period");
}
@@ -258,8 +258,8 @@ public class FixedDepositProduct extends SavingsProduct {
if (!existingChart.equals(comparingChart)) {
if (existingChart.chartFields().isOverlapping(comparingChart.chartFields())) {
baseDataValidator.failWithCodeNoParameterAddedToErrorCode("chart.overlapping.from.and.end.dates",
existingChart.getFromDateAsLocalDate(), existingChart.getEndDateAsLocalDate(),
comparingChart.getFromDateAsLocalDate(), comparingChart.getEndDateAsLocalDate());
existingChart.getFromDate(), existingChart.getEndDate(), comparingChart.getFromDate(),
comparingChart.getEndDate());
}
}
}
@@ -286,7 +286,7 @@ public class RecurringDepositAccount extends SavingsAccount {
}
final LocalDate todayDate = DateUtils.getBusinessLocalDate();
if (!this.maturityDate().isAfter(todayDate)) {
if (!DateUtils.isAfter(this.maturityDate(), todayDate)) {
// update account status
this.status = SavingsAccountStatusType.MATURED.getValue();
postMaturityInterest(isSavingsInterestPostingAtCurrentPeriodEnd, financialYearBeginningMonth, todayDate, postReversals);
@@ -368,7 +368,7 @@ public class RecurringDepositAccount extends SavingsAccount {
allPostingPeriods.add(postingPeriod);
}
this.savingsHelper.calculateInterestForAllPostingPeriods(this.currency, allPostingPeriods, this.getLockedInUntilLocalDate(),
this.savingsHelper.calculateInterestForAllPostingPeriods(this.currency, allPostingPeriods, this.getLockedInUntilDate(),
isTransferInterestToOtherAccount());
// this.summary.updateFromInterestPeriodSummaries(this.currency,
// allPostingPeriods);
@@ -381,8 +381,8 @@ public class RecurringDepositAccount extends SavingsAccount {
allTransactions.addAll(retreiveOrderedNonInterestPostingTransactions());
LocalDate latestTransactionDate = null;
for (final SavingsAccountTransaction installment : allTransactions) {
if (latestTransactionDate == null || latestTransactionDate.isBefore(installment.getTransactionLocalDate())) {
latestTransactionDate = installment.getTransactionLocalDate();
if (latestTransactionDate == null || DateUtils.isBefore(latestTransactionDate, installment.getTransactionDate())) {
latestTransactionDate = installment.getTransactionDate();
}
}
String refNo = null;
@@ -390,11 +390,11 @@ public class RecurringDepositAccount extends SavingsAccount {
for (RecurringDepositScheduleInstallment installment : depositScheduleInstallments()) {
if (installment.isPrincipalNotCompleted(getCurrency())) {
LocalDate dueDate = installment.dueDate();
if (latestTransactionDate != null && dueDate.isBefore(latestTransactionDate)) {
if (DateUtils.isBefore(dueDate, latestTransactionDate)) {
dueDate = latestTransactionDate;
}
final SavingsAccountTransaction transaction = SavingsAccountTransaction.deposit(null, office(), null, dueDate,
installment.getDepositAmountOutstanding(getCurrency()), DateUtils.getLocalDateTimeOfSystem(), null, refNo);
installment.getDepositAmountOutstanding(getCurrency()), refNo);
allTransactions.add(transaction);
}
}
@@ -414,7 +414,7 @@ public class RecurringDepositAccount extends SavingsAccount {
}
runningBalance = runningBalance.plus(transactionAmount);
transaction.updateRunningBalance(runningBalance);
transaction.setRunningBalance(runningBalance);
}
}
// loop over transactions in reverse
@@ -423,7 +423,7 @@ public class RecurringDepositAccount extends SavingsAccount {
final SavingsAccountTransaction transaction = allTransactions.get(i);
if (transaction.isNotReversed() && !transaction.isInterestPostingAndNotReversed()) {
transaction.updateCumulativeBalanceAndDates(this.currency, endOfBalanceDate);
endOfBalanceDate = transaction.transactionLocalDate().minusDays(1);
endOfBalanceDate = transaction.getTransactionDate().minusDays(1);
}
}
return allTransactions;
@@ -437,9 +437,7 @@ public class RecurringDepositAccount extends SavingsAccount {
return depositStartDate;
}
public void prematureClosure(final AppUser currentUser, final JsonCommand command, final LocalDate tenantsTodayDate,
final Map<String, Object> actualChanges) {
public void prematureClosure(final AppUser currentUser, final JsonCommand command, final Map<String, Object> actualChanges) {
final List<ApiParameterError> dataValidationErrors = new ArrayList<>();
final DataValidatorBuilder baseDataValidator = new DataValidatorBuilder(dataValidationErrors)
.resource(RECURRING_DEPOSIT_ACCOUNT_RESOURCE_NAME + DepositsApiConstants.preMatureCloseAction);
@@ -456,14 +454,13 @@ public class RecurringDepositAccount extends SavingsAccount {
final DateTimeFormatter fmt = DateTimeFormatter.ofPattern(command.dateFormat()).withLocale(locale);
final LocalDate closedDate = command.localDateValueOfParameterNamed(SavingsApiConstants.closedOnDateParamName);
if (closedDate.isBefore(getActivationLocalDate())) {
if (DateUtils.isBefore(closedDate, getActivationDate())) {
baseDataValidator.reset().parameter(SavingsApiConstants.closedOnDateParamName).value(closedDate)
.failWithCode("must.be.after.activation.date");
if (!dataValidationErrors.isEmpty()) {
throw new PlatformApiDataValidationException(dataValidationErrors);
}
}
if (isAccountLocked(closedDate)) {
baseDataValidator.reset().parameter(SavingsApiConstants.closedOnDateParamName).value(closedDate)
.failWithCode("must.be.after.lockin.period");
@@ -471,16 +468,14 @@ public class RecurringDepositAccount extends SavingsAccount {
throw new PlatformApiDataValidationException(dataValidationErrors);
}
}
if (closedDate.isAfter(maturityDate())) {
if (maturityDate() != null && DateUtils.isAfter(closedDate, maturityDate())) {
baseDataValidator.reset().parameter(SavingsApiConstants.closedOnDateParamName).value(closedDate)
.failWithCode("must.be.before.maturity.date");
if (!dataValidationErrors.isEmpty()) {
throw new PlatformApiDataValidationException(dataValidationErrors);
}
}
if (closedDate.isAfter(tenantsTodayDate)) {
if (DateUtils.isAfterBusinessDate(closedDate)) {
baseDataValidator.reset().parameter(SavingsApiConstants.closedOnDateParamName).value(closedDate)
.failWithCode("cannot.be.a.future.date");
if (!dataValidationErrors.isEmpty()) {
@@ -541,14 +536,14 @@ public class RecurringDepositAccount extends SavingsAccount {
return Money.of(this.currency, this.minRequiredOpeningBalance);
}
protected void processAccountUponActivation(final DateTimeFormatter fmt, final AppUser user, final boolean postReversals) {
protected void processAccountUponActivation(final DateTimeFormatter fmt, final boolean postReversals) {
final Money minRequiredOpeningBalance = Money.of(this.currency, this.minRequiredOpeningBalance);
final boolean backdatedTxnsAllowedTill = false;
String refNo = null;
final Long relaxingDaysConfigForPivotDate = this.configurationDomainService.retrieveRelaxingDaysConfigForPivotDate();
if (minRequiredOpeningBalance.isGreaterThanZero()) {
final SavingsAccountTransactionDTO transactionDTO = new SavingsAccountTransactionDTO(fmt, getActivationLocalDate(),
minRequiredOpeningBalance.getAmount(), null, DateUtils.getLocalDateTimeOfSystem(), user, accountType);
final SavingsAccountTransactionDTO transactionDTO = new SavingsAccountTransactionDTO(fmt, getActivationDate(),
minRequiredOpeningBalance.getAmount(), null, null, accountType);
deposit(transactionDTO, backdatedTxnsAllowedTill, relaxingDaysConfigForPivotDate, refNo);
// update existing transactions so derived balance fields are
@@ -557,9 +552,7 @@ public class RecurringDepositAccount extends SavingsAccount {
}
}
public void close(final AppUser currentUser, final JsonCommand command, final LocalDate tenantsTodayDate,
final Map<String, Object> actualChanges) {
public void close(final AppUser currentUser, final JsonCommand command, final Map<String, Object> actualChanges) {
final List<ApiParameterError> dataValidationErrors = new ArrayList<>();
final DataValidatorBuilder baseDataValidator = new DataValidatorBuilder(dataValidationErrors)
.resource(RECURRING_DEPOSIT_ACCOUNT_RESOURCE_NAME + SavingsApiConstants.closeAction);
@@ -576,21 +569,21 @@ public class RecurringDepositAccount extends SavingsAccount {
final DateTimeFormatter fmt = DateTimeFormatter.ofPattern(command.dateFormat()).withLocale(locale);
final LocalDate closedDate = command.localDateValueOfParameterNamed(SavingsApiConstants.closedOnDateParamName);
if (closedDate.isBefore(getActivationLocalDate())) {
if (DateUtils.isBefore(closedDate, getActivationDate())) {
baseDataValidator.reset().parameter(SavingsApiConstants.closedOnDateParamName).value(closedDate)
.failWithCode("must.be.after.activation.date");
if (!dataValidationErrors.isEmpty()) {
throw new PlatformApiDataValidationException(dataValidationErrors);
}
}
if (maturityDate() != null && closedDate.isBefore(maturityDate())) {
if (maturityDate() != null && DateUtils.isBefore(closedDate, maturityDate())) {
baseDataValidator.reset().parameter(SavingsApiConstants.closedOnDateParamName).value(closedDate)
.failWithCode("must.be.after.account.maturity.date");
if (!dataValidationErrors.isEmpty()) {
throw new PlatformApiDataValidationException(dataValidationErrors);
}
}
if (closedDate.isAfter(tenantsTodayDate)) {
if (DateUtils.isAfterBusinessDate(closedDate)) {
baseDataValidator.reset().parameter(SavingsApiConstants.closedOnDateParamName).value(closedDate)
.failWithCode("cannot.be.a.future.date");
if (!dataValidationErrors.isEmpty()) {
@@ -659,7 +652,8 @@ public class RecurringDepositAccount extends SavingsAccount {
for (final PostingPeriod interestPostingPeriod : postingPeriods) {
LocalDate interestPostingTransactionDate = interestPostingPeriod.dateOfPostingTransaction();
interestPostingTransactionDate = interestPostingTransactionDate.isAfter(interestPostingUpToDate) ? interestPostingUpToDate
interestPostingTransactionDate = DateUtils.isAfter(interestPostingTransactionDate, interestPostingUpToDate)
? interestPostingUpToDate
: interestPostingTransactionDate;
final Money interestEarnedToBePostedForPeriod = interestPostingPeriod.getInterestEarned();
@@ -777,14 +771,14 @@ public class RecurringDepositAccount extends SavingsAccount {
private LocalDate interestPostingUpToDate(final LocalDate interestPostingDate) {
LocalDate interestPostingUpToDate = interestPostingDate;
final LocalDate uptoMaturityDate = interestCalculatedUpto();
if (uptoMaturityDate != null && uptoMaturityDate.isBefore(interestPostingDate)) {
if (uptoMaturityDate != null && DateUtils.isBefore(uptoMaturityDate, interestPostingDate)) {
interestPostingUpToDate = uptoMaturityDate;
}
return interestPostingUpToDate;
}
public LocalDate maturityDate() {
return this.accountTermAndPreClosure.getMaturityLocalDate();
return this.accountTermAndPreClosure.getMaturityDate();
}
public BigDecimal maturityAmount() {
@@ -813,11 +807,10 @@ public class RecurringDepositAccount extends SavingsAccount {
}
@Override
public Map<String, Object> activate(final AppUser currentUser, final JsonCommand command, final LocalDate tenantsTodayDate) {
public Map<String, Object> activate(final AppUser currentUser, final JsonCommand command) {
final Map<String, Object> actualChanges = super.activate(currentUser, command);
final Map<String, Object> actualChanges = super.activate(currentUser, command, tenantsTodayDate);
if (accountTermAndPreClosure.isAfterExpectedFirstDepositDate(getActivationLocalDate())) {
if (accountTermAndPreClosure.isAfterExpectedFirstDepositDate(getActivationDate())) {
final List<ApiParameterError> dataValidationErrors = new ArrayList<>();
final DataValidatorBuilder baseDataValidator = new DataValidatorBuilder(dataValidationErrors)
.resource(RECURRING_DEPOSIT_ACCOUNT_RESOURCE_NAME);
@@ -889,13 +882,12 @@ public class RecurringDepositAccount extends SavingsAccount {
}
public void handleScheduleInstallments(final SavingsAccountTransaction transaction) {
final LocalDate transactionDate = transaction.transactionLocalDate();
final LocalDate transactionDate = transaction.getTransactionDate();
Money transactionAmountUnprocessed = transaction.getAmount(getCurrency());
for (RecurringDepositScheduleInstallment currentInstallment : depositScheduleInstallments()) {
if (currentInstallment.isNotFullyPaidOff() && transactionAmountUnprocessed.isGreaterThanZero()) {
if (!this.adjustAdvanceTowardsFuturePayments() && currentInstallment.dueDate().isAfter(transactionDate)) {
if (!this.adjustAdvanceTowardsFuturePayments() && DateUtils.isBefore(transactionDate, currentInstallment.dueDate())) {
transactionAmountUnprocessed = Money.zero(getCurrency());
}
transactionAmountUnprocessed = handleInstallmentTransaction(currentInstallment, transactionAmountUnprocessed,
@@ -906,7 +898,6 @@ public class RecurringDepositAccount extends SavingsAccount {
}
public void updateScheduleInstallments() {
// reset all installments to process from the beginning
for (RecurringDepositScheduleInstallment currentInstallment : depositScheduleInstallments()) {
currentInstallment.resetDerivedFields();
@@ -923,8 +914,7 @@ public class RecurringDepositAccount extends SavingsAccount {
// reset all installments to process from the beginning, also update
// deposit amount as necessary
for (RecurringDepositScheduleInstallment currentInstallment : depositScheduleInstallments()) {
if (currentInstallment.dueDate().isAfter(depositAmountupdatedFromDate)
|| currentInstallment.dueDate().isEqual(depositAmountupdatedFromDate)) {
if (!DateUtils.isAfter(depositAmountupdatedFromDate, currentInstallment.dueDate())) {
currentInstallment.updateDepositAmountAndResetDerivedFields(newDepositAmount);
} else {
currentInstallment.resetDerivedFields();
@@ -959,19 +949,14 @@ public class RecurringDepositAccount extends SavingsAccount {
*/
protected boolean isTransactionInAdvanceOfInstallment(final int currentInstallmentIndex,
final List<RecurringDepositScheduleInstallment> installments, final LocalDate transactionDate) {
final RecurringDepositScheduleInstallment currentInstallment = installments.get(currentInstallmentIndex);
return transactionDate.isBefore(currentInstallment.dueDate());
return DateUtils.isBefore(transactionDate, currentInstallment.dueDate());
}
private Money handleInstallmentTransaction(final RecurringDepositScheduleInstallment currentInstallment,
final Money transactionAmountUnprocessed, final LocalDate transactionDate) {
Money transactionAmountRemaining = transactionAmountUnprocessed;
Money depositAmountPortion = Money.zero(transactionAmountRemaining.getCurrency());
depositAmountPortion = currentInstallment.payInstallment(transactionDate, transactionAmountRemaining);
Money depositAmountPortion = currentInstallment.payInstallment(transactionDate, transactionAmountRemaining);
transactionAmountRemaining = transactionAmountRemaining.minus(depositAmountPortion);
return transactionAmountRemaining;
@@ -984,11 +969,11 @@ public class RecurringDepositAccount extends SavingsAccount {
private boolean isBeforeMaturityDate(final LocalDate compareDate) {
final LocalDate maturityDate = this.maturityDate();
return maturityDate == null ? true : compareDate.isBefore(maturityDate);
return maturityDate == null || DateUtils.isBefore(compareDate, maturityDate);
}
private boolean isBeforeDepositStartDate(LocalDate compareDate) {
return compareDate.isBefore(depositStartDate());
return DateUtils.isBefore(compareDate, depositStartDate());
}
public void validateDomainRules() {
@@ -1003,7 +988,6 @@ public class RecurringDepositAccount extends SavingsAccount {
}
private void validateDomainRules(final DataValidatorBuilder baseDataValidator) {
final boolean isMinTermGreaterThanMax = this.accountTermAndPreClosure.depositTermDetail()
.isMinDepositTermGreaterThanMaxDepositTerm();
// deposit period should be within min and max deposit term
@@ -1063,8 +1047,8 @@ public class RecurringDepositAccount extends SavingsAccount {
.resource(RECURRING_DEPOSIT_ACCOUNT_RESOURCE_NAME);
LocalDate maturityDate = calculateMaturityDate();
if (this.chart != null) {
final LocalDate chartFromDate = this.chart.getFromDateAsLocalDate();
LocalDate chartEndDate = this.chart.getEndDateAsLocalDate();
final LocalDate chartFromDate = this.chart.getFromDate();
LocalDate chartEndDate = this.chart.getEndDate();
chartEndDate = chartEndDate == null ? DateUtils.getBusinessLocalDate() : chartEndDate;
final LocalDateInterval chartInterval = LocalDateInterval.create(chartFromDate, chartEndDate);
@@ -1080,7 +1064,7 @@ public class RecurringDepositAccount extends SavingsAccount {
BigDecimal applicableInterestRate = this.chart.getApplicableInterestRate(maturityAmount, depositStartDate(), maturityDate,
this.client);
if (applicableInterestRate.compareTo(BigDecimal.ZERO) == 0 ? Boolean.TRUE : Boolean.FALSE) {
if (applicableInterestRate.compareTo(BigDecimal.ZERO) == 0) {
baseDataValidator.reset()
.failWithCodeNoParameterAddedToErrorCode("no.applicable.interest.rate.is.found.based.on.amount.and.deposit.period");
}
@@ -1092,13 +1076,13 @@ public class RecurringDepositAccount extends SavingsAccount {
if (!dataValidationErrors.isEmpty()) {
throw new PlatformApiDataValidationException(dataValidationErrors);
}
/**
/*
* final boolean recurringFrequencyBeforeDepositPeriod = recurringFrequencyBeforeDepositPeriod();
*
* if (!recurringFrequencyBeforeDepositPeriod) {
* baseDataValidator.reset().failWithCodeNoParameterAddedToErrorCode(
* "recurring.frequency.not.before.deposit.period"); }
**/
*/
}
public boolean isReinvestOnClosure() {
@@ -1151,10 +1135,8 @@ public class RecurringDepositAccount extends SavingsAccount {
private boolean firstDepositDateBeforeAccountSubmittedOrActivationDate() {
final LocalDate expectedFirstDepositLocalDate = accountTermAndPreClosure.getExpectedFirstDepositOnDate();
if (expectedFirstDepositLocalDate == null) {
return false;
}
return expectedFirstDepositLocalDate.isBefore(accountSubmittedOrActivationDate());
return expectedFirstDepositLocalDate != null
&& DateUtils.isBefore(expectedFirstDepositLocalDate, accountSubmittedOrActivationDate());
}
public void setDatesFrom(final LocalDate now) {
@@ -1192,7 +1174,7 @@ public class RecurringDepositAccount extends SavingsAccount {
int installmentNumber = 1;
final LocalDate maturityDate = calcualteScheduleTillDate(frequency, recurringEvery);
final BigDecimal depositAmount = this.recurringDetail.mandatoryRecommendedDepositAmount();
while (maturityDate.isAfter(installmentDate)) {
while (DateUtils.isBefore(installmentDate, maturityDate)) {
final RecurringDepositScheduleInstallment installment = RecurringDepositScheduleInstallment.installment(this, installmentNumber,
installmentDate, depositAmount);
addDepositScheduleInstallment(installment);
@@ -1226,7 +1208,7 @@ public class RecurringDepositAccount extends SavingsAccount {
public void updateOverduePayments(final LocalDate todayDate) {
LocalDate overdueUptoDate = this.maturityDate();
if (overdueUptoDate == null || overdueUptoDate.isAfter(todayDate)) {
if (overdueUptoDate == null || DateUtils.isAfter(overdueUptoDate, todayDate)) {
overdueUptoDate = todayDate;
}
@@ -1234,7 +1216,7 @@ public class RecurringDepositAccount extends SavingsAccount {
int noOfOverdueInstallments = 0;
Money totalOverdueAmount = Money.zero(getCurrency());
for (RecurringDepositScheduleInstallment installment : installments) {
if (installment.isNotFullyPaidOff() && overdueUptoDate.isAfter(installment.dueDate())) {
if (installment.isNotFullyPaidOff() && DateUtils.isAfter(overdueUptoDate, installment.dueDate())) {
noOfOverdueInstallments++;
totalOverdueAmount = totalOverdueAmount.plus(installment.getDepositAmountOutstanding(getCurrency()));
}
@@ -18,6 +18,8 @@
*/
package org.apache.fineract.portfolio.savings.domain;
import static org.apache.fineract.infrastructure.core.service.DateUtils.getSystemZoneId;
import jakarta.persistence.Column;
import jakarta.persistence.Entity;
import jakarta.persistence.JoinColumn;
@@ -25,13 +27,17 @@ import jakarta.persistence.ManyToOne;
import jakarta.persistence.Table;
import java.math.BigDecimal;
import java.time.LocalDate;
import org.apache.fineract.infrastructure.core.domain.AbstractAuditableCustom;
import java.time.LocalDateTime;
import java.time.OffsetDateTime;
import java.util.Optional;
import org.apache.fineract.infrastructure.core.domain.AbstractAuditableWithUTCDateTimeCustom;
import org.apache.fineract.infrastructure.core.service.DateUtils;
import org.apache.fineract.organisation.monetary.domain.MonetaryCurrency;
import org.apache.fineract.organisation.monetary.domain.Money;
@Entity
@Table(name = "m_mandatory_savings_schedule")
public class RecurringDepositScheduleInstallment extends AbstractAuditableCustom {
public class RecurringDepositScheduleInstallment extends AbstractAuditableWithUTCDateTimeCustom {
@ManyToOne(optional = false)
@JoinColumn(name = "savings_account_id")
@@ -64,15 +70,18 @@ public class RecurringDepositScheduleInstallment extends AbstractAuditableCustom
@Column(name = "obligations_met_on_date")
private LocalDate obligationsMetOnDate;
@Deprecated
@Column(name = "created_date")
private LocalDateTime createdDateToRemove;
@Deprecated
@Column(name = "lastmodified_date")
private LocalDateTime lastModifiedDateToRemove;
/**
*
*/
protected RecurringDepositScheduleInstallment() {
this.installmentNumber = null;
this.fromDate = null;
this.dueDate = null;
this.obligationsMet = false;
}
protected RecurringDepositScheduleInstallment() {}
/**
* @param account
@@ -165,6 +174,24 @@ public class RecurringDepositScheduleInstallment extends AbstractAuditableCustom
return this.dueDate;
}
public Integer installmentNumber() {
return this.installmentNumber;
}
@Override
public Optional<OffsetDateTime> getCreatedDate() {
// #audit backward compatibility keep system datetime
return Optional.ofNullable(super.getCreatedDate()
.orElse(createdDateToRemove == null ? null : createdDateToRemove.atZone(getSystemZoneId()).toOffsetDateTime()));
}
@Override
public Optional<OffsetDateTime> getLastModifiedDate() {
// #audit backward compatibility keep system datetime
return Optional.ofNullable(super.getLastModifiedDate()
.orElse(lastModifiedDateToRemove == null ? null : lastModifiedDateToRemove.atZone(getSystemZoneId()).toOffsetDateTime()));
}
public Money payInstallment(final LocalDate transactionDate, final Money transactionAmountRemaining) {
final MonetaryCurrency currency = transactionAmountRemaining.getCurrency();
@@ -209,11 +236,11 @@ public class RecurringDepositScheduleInstallment extends AbstractAuditableCustom
}
private boolean isInAdvance(final LocalDate transactionDate) {
return transactionDate.isBefore(dueDate());
return DateUtils.isBefore(transactionDate, dueDate());
}
private boolean isLatePayment(final LocalDate transactionDate) {
return transactionDate.isAfter(dueDate());
return DateUtils.isAfter(transactionDate, dueDate());
}
private Money asMoney(final BigDecimal decimal, final MonetaryCurrency currency) {
@@ -232,8 +259,4 @@ public class RecurringDepositScheduleInstallment extends AbstractAuditableCustom
this.depositAmount = newDepositAmount;
this.resetDerivedFields();
}
public Integer installmentNumber() {
return this.installmentNumber;
}
}
@@ -56,7 +56,6 @@ import org.apache.fineract.infrastructure.configuration.domain.ConfigurationDoma
import org.apache.fineract.infrastructure.core.api.JsonCommand;
import org.apache.fineract.infrastructure.core.exception.UnsupportedParameterException;
import org.apache.fineract.infrastructure.core.serialization.FromJsonHelper;
import org.apache.fineract.infrastructure.core.service.DateUtils;
import org.apache.fineract.infrastructure.core.service.ExternalIdFactory;
import org.apache.fineract.organisation.staff.domain.Staff;
import org.apache.fineract.organisation.staff.domain.StaffRepositoryWrapper;
@@ -333,7 +332,7 @@ public class SavingsAccountAssembler {
nominalAnnualInterestRateOverdraft, minOverdraftForInterestCalculation, withHoldTax);
account.setHelpers(this.savingsAccountTransactionSummaryWrapper, this.savingsHelper);
account.validateNewApplicationState(DateUtils.getBusinessLocalDate(), SAVINGS_ACCOUNT_RESOURCE_NAME);
account.validateNewApplicationState(SAVINGS_ACCOUNT_RESOURCE_NAME);
account.validateAccountValuesWithProduct();
@@ -349,7 +348,7 @@ public class SavingsAccountAssembler {
List<SavingsAccountTransaction> savingsAccountTransactions = null;
if (backdatedTxnsAllowedTill) {
LocalDate pivotDate = account.getSummary().getInterestPostedTillDate();
boolean isNotPresent = pivotDate == null ? true : false;
boolean isNotPresent = pivotDate == null;
if (!isNotPresent) {
// Get savings account transactions
if (isRelaxingDaysConfigForPivotDateEnabled()) {
@@ -468,7 +467,7 @@ public class SavingsAccountAssembler {
product.withHoldTax());
account.setHelpers(this.savingsAccountTransactionSummaryWrapper, this.savingsHelper);
account.validateNewApplicationState(DateUtils.getBusinessLocalDate(), SAVINGS_ACCOUNT_RESOURCE_NAME);
account.validateNewApplicationState(SAVINGS_ACCOUNT_RESOURCE_NAME);
account.validateAccountValuesWithProduct();
@@ -41,7 +41,9 @@ import java.util.LinkedHashMap;
import java.util.Map;
import java.util.Objects;
import org.apache.fineract.infrastructure.core.api.JsonCommand;
import org.apache.fineract.infrastructure.core.domain.AbstractPersistableCustom;
import org.apache.fineract.infrastructure.core.domain.AbstractAuditableWithUTCDateTimeCustom;
import org.apache.fineract.infrastructure.core.service.DateUtils;
import org.apache.fineract.infrastructure.core.service.MathUtil;
import org.apache.fineract.organisation.monetary.domain.MonetaryCurrency;
import org.apache.fineract.organisation.monetary.domain.Money;
import org.apache.fineract.organisation.monetary.domain.MoneyHelper;
@@ -58,7 +60,7 @@ import org.slf4j.LoggerFactory;
*/
@Entity
@Table(name = "m_savings_account_charge")
public class SavingsAccountCharge extends AbstractPersistableCustom {
public class SavingsAccountCharge extends AbstractAuditableWithUTCDateTimeCustom {
private static final Logger LOG = LoggerFactory.getLogger(SavingsAccountCharge.class);
@@ -448,7 +450,7 @@ public class SavingsAccountCharge extends AbstractPersistableCustom {
final String dateFormatAsInput = command.dateFormat();
final String localeAsInput = command.locale();
if (command.isChangeInLocalDateParameterNamed(dueAsOfDateParamName, getDueLocalDate())) {
if (command.isChangeInLocalDateParameterNamed(dueAsOfDateParamName, getDueDate())) {
final String valueAsInput = command.stringValueOfParameterNamed(dueAsOfDateParamName);
actualChanges.put(dueAsOfDateParamName, valueAsInput);
actualChanges.put(dateFormatParamName, dateFormatAsInput);
@@ -521,7 +523,7 @@ public class SavingsAccountCharge extends AbstractPersistableCustom {
return value.compareTo(BigDecimal.ZERO) > 0;
}
public LocalDate getDueLocalDate() {
public LocalDate getDueDate() {
return this.dueDate;
}
@@ -754,17 +756,13 @@ public class SavingsAccountCharge extends AbstractPersistableCustom {
SavingsAccountCharge that = (SavingsAccountCharge) o;
return (penaltyCharge == that.penaltyCharge) && (paid == that.paid) && (waived == that.waived) && (status == that.status)
&& Objects.equals(savingsAccount, that.savingsAccount) && Objects.equals(charge, that.charge)
&& Objects.equals(chargeTime, that.chargeTime) && dueDate.compareTo(that.dueDate) == 0
? Boolean.TRUE
: Boolean.FALSE && Objects.equals(feeOnMonth, that.feeOnMonth) && Objects.equals(feeOnDay, that.feeOnDay)
&& Objects.equals(feeInterval, that.feeInterval)
&& Objects.equals(chargeCalculation, that.chargeCalculation) && Objects.equals(percentage, that.percentage)
&& Objects.equals(amountPercentageAppliedTo, that.amountPercentageAppliedTo)
&& Objects.equals(amount, that.amount) && Objects.equals(amountPaid, that.amountPaid)
&& Objects.equals(amountWaived, that.amountWaived)
&& Objects.equals(amountWrittenOff, that.amountWrittenOff)
&& Objects.equals(amountOutstanding, that.amountOutstanding)
&& inactivationDate.compareTo(that.inactivationDate) == 0 ? Boolean.TRUE : Boolean.FALSE;
&& Objects.equals(chargeTime, that.chargeTime) && DateUtils.isEqual(dueDate, that.dueDate)
&& Objects.equals(feeOnMonth, that.feeOnMonth) && Objects.equals(feeOnDay, that.feeOnDay)
&& Objects.equals(feeInterval, that.feeInterval) && Objects.equals(chargeCalculation, that.chargeCalculation)
&& Objects.equals(percentage, that.percentage) && Objects.equals(amountPercentageAppliedTo, that.amountPercentageAppliedTo)
&& Objects.equals(amount, that.amount) && Objects.equals(amountPaid, that.amountPaid)
&& Objects.equals(amountWaived, that.amountWaived) && Objects.equals(amountWrittenOff, that.amountWrittenOff)
&& Objects.equals(amountOutstanding, that.amountOutstanding) && DateUtils.isEqual(inactivationDate, that.inactivationDate);
}
@Override
@@ -803,12 +801,12 @@ public class SavingsAccountCharge extends AbstractPersistableCustom {
if (isAnnualFee() || isMonthlyFee()) {
nextDueLocalDate = startingDate.withMonth(this.feeOnMonth);
nextDueLocalDate = setDayOfMonth(nextDueLocalDate);
while (startingDate.isAfter(nextDueLocalDate)) {
while (DateUtils.isBefore(nextDueLocalDate, startingDate)) {
nextDueLocalDate = calculateNextDueDate(nextDueLocalDate);
}
} else if (isWeeklyFee()) {
nextDueLocalDate = getDueLocalDate();
while (startingDate.isAfter(nextDueLocalDate)) {
nextDueLocalDate = getDueDate();
while (DateUtils.isBefore(nextDueLocalDate, startingDate)) {
nextDueLocalDate = calculateNextDueDate(nextDueLocalDate);
}
} else {
@@ -883,12 +881,11 @@ public class SavingsAccountCharge extends AbstractPersistableCustom {
}
public boolean isChargeIsDue(final LocalDate nextDueDate) {
return this.getDueLocalDate().isBefore(nextDueDate);
return DateUtils.isBefore(getDueDate(), nextDueDate);
}
public boolean isChargeIsOverPaid(final LocalDate nextDueDate) {
final BigDecimal amountPaid = this.amountPaid == null ? BigDecimal.ZERO : amountPaid();
return this.getDueLocalDate().isAfter(nextDueDate) && amountPaid.compareTo(BigDecimal.ZERO) > 0;
return DateUtils.isAfter(getDueDate(), nextDueDate) && MathUtil.isGreaterThanZero(amountPaid());
}
private BigDecimal amountPaid() {
@@ -25,7 +25,6 @@ import java.util.List;
import java.util.Set;
import org.apache.fineract.portfolio.paymentdetail.domain.PaymentDetail;
import org.apache.fineract.portfolio.savings.SavingsTransactionBooleanValues;
import org.apache.fineract.useradministration.domain.AppUser;
public interface SavingsAccountDomainService {
@@ -46,6 +45,5 @@ public interface SavingsAccountDomainService {
SavingsAccountTransaction handleReversal(SavingsAccount account, List<SavingsAccountTransaction> savingsAccountTransactions,
boolean backdatedTxnsAllowedTill);
SavingsAccountTransaction handleHold(SavingsAccount account, AppUser createdUser, BigDecimal amount, LocalDate transactionDate,
Boolean lienAllowed);
SavingsAccountTransaction handleHold(SavingsAccount account, BigDecimal amount, LocalDate transactionDate, Boolean lienAllowed);
}
@@ -43,7 +43,6 @@ import org.apache.fineract.portfolio.savings.SavingsAccountTransactionType;
import org.apache.fineract.portfolio.savings.SavingsTransactionBooleanValues;
import org.apache.fineract.portfolio.savings.data.SavingsAccountTransactionDTO;
import org.apache.fineract.portfolio.savings.exception.DepositAccountTransactionNotAllowedException;
import org.apache.fineract.useradministration.domain.AppUser;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
@@ -83,8 +82,7 @@ public class SavingsAccountDomainServiceJpa implements SavingsAccountDomainServi
public SavingsAccountTransaction handleWithdrawal(final SavingsAccount account, final DateTimeFormatter fmt,
final LocalDate transactionDate, final BigDecimal transactionAmount, final PaymentDetail paymentDetail,
final SavingsTransactionBooleanValues transactionBooleanValues, final boolean backdatedTxnsAllowedTill) {
AppUser user = getAppUserIfPresent();
context.authenticatedUser();
account.validateForAccountBlock();
account.validateForDebitBlock();
final boolean isSavingsInterestPostingAtCurrentPeriodEnd = this.configurationDomainService
@@ -107,7 +105,7 @@ public class SavingsAccountDomainServiceJpa implements SavingsAccountDomainServi
Integer accountType = null;
final SavingsAccountTransactionDTO transactionDTO = new SavingsAccountTransactionDTO(fmt, transactionDate, transactionAmount,
paymentDetail, DateUtils.getLocalDateTimeOfSystem(), user, accountType);
paymentDetail, null, accountType);
UUID refNo = UUID.randomUUID();
final SavingsAccountTransaction withdrawal = account.withdraw(transactionDTO, transactionBooleanValues.isApplyWithdrawFee(),
backdatedTxnsAllowedTill, relaxingDaysConfigForPivotDate, refNo.toString());
@@ -147,14 +145,6 @@ public class SavingsAccountDomainServiceJpa implements SavingsAccountDomainServi
return withdrawal;
}
private AppUser getAppUserIfPresent() {
AppUser user = null;
if (this.context != null) {
user = this.context.getAuthenticatedUserIfPresent();
}
return user;
}
@Transactional
@Override
public SavingsAccountTransaction handleDeposit(final SavingsAccount account, final DateTimeFormatter fmt,
@@ -169,7 +159,7 @@ public class SavingsAccountDomainServiceJpa implements SavingsAccountDomainServi
final LocalDate transactionDate, final BigDecimal transactionAmount, final PaymentDetail paymentDetail,
final boolean isAccountTransfer, final boolean isRegularTransaction,
final SavingsAccountTransactionType savingsAccountTransactionType, final boolean backdatedTxnsAllowedTill) {
AppUser user = getAppUserIfPresent();
context.authenticatedUser();
account.validateForAccountBlock();
account.validateForCreditBlock();
@@ -193,7 +183,7 @@ public class SavingsAccountDomainServiceJpa implements SavingsAccountDomainServi
Integer accountType = null;
final SavingsAccountTransactionDTO transactionDTO = new SavingsAccountTransactionDTO(fmt, transactionDate, transactionAmount,
paymentDetail, DateUtils.getLocalDateTimeOfSystem(), user, accountType);
paymentDetail, null, accountType);
UUID refNo = UUID.randomUUID();
final SavingsAccountTransaction deposit = account.deposit(transactionDTO, savingsAccountTransactionType, backdatedTxnsAllowedTill,
relaxingDaysConfigForPivotDate, refNo.toString());
@@ -226,13 +216,10 @@ public class SavingsAccountDomainServiceJpa implements SavingsAccountDomainServi
@Transactional
@Override
public SavingsAccountTransaction handleHold(final SavingsAccount account, final AppUser createdUser, BigDecimal amount,
LocalDate transactionDate, Boolean lienAllowed) {
final PaymentDetail paymentDetails = null;
SavingsAccountTransaction transaction = SavingsAccountTransaction.holdAmount(account, account.office(), paymentDetails,
transactionDate, Money.of(account.getCurrency(), amount), DateUtils.getLocalDateTimeOfSystem(), createdUser, lienAllowed);
return transaction;
public SavingsAccountTransaction handleHold(final SavingsAccount account, BigDecimal amount, LocalDate transactionDate,
Boolean lienAllowed) {
return SavingsAccountTransaction.holdAmount(account, account.office(), null, transactionDate,
Money.of(account.getCurrency(), amount), lienAllowed);
}
@Override
@@ -322,7 +309,7 @@ public class SavingsAccountDomainServiceJpa implements SavingsAccountDomainServi
final MathContext mc = new MathContext(15, MoneyHelper.getRoundingMode());
for (SavingsAccountTransaction savingsAccountTransaction : savingsAccountTransactions) {
if (savingsAccountTransaction.isPostInterestCalculationRequired()
&& account.isBeforeLastPostingPeriod(savingsAccountTransaction.transactionLocalDate(), backdatedTxnsAllowedTill)) {
&& account.isBeforeLastPostingPeriod(savingsAccountTransaction.getTransactionDate(), backdatedTxnsAllowedTill)) {
account.postInterest(mc, today, isInterestTransfer, isSavingsInterestPostingAtCurrentPeriodEnd, financialYearBeginningMonth,
postInterestOnDate, backdatedTxnsAllowedTill, postReversals);
@@ -330,7 +317,7 @@ public class SavingsAccountDomainServiceJpa implements SavingsAccountDomainServi
account.calculateInterestUsing(mc, today, isInterestTransfer, isSavingsInterestPostingAtCurrentPeriodEnd,
financialYearBeginningMonth, postInterestOnDate, backdatedTxnsAllowedTill, postReversals);
}
account.validatePivotDateTransaction(savingsAccountTransaction.getLastTransactionDate(), backdatedTxnsAllowedTill,
account.validatePivotDateTransaction(savingsAccountTransaction.getTransactionDate(), backdatedTxnsAllowedTill,
relaxingDaysConfigForPivotDate, "savingsaccount");
account.validateAccountBalanceDoesNotBecomeNegativeMinimal(savingsAccountTransaction.getAmount(), false);
account.activateAccountBasedOnBalance();
@@ -216,7 +216,7 @@ public final class SavingsAccountSummary {
final SavingsAccountTransaction savingsAccountTransaction = savingsAccountTransactions.get(i);
if (savingsAccountTransaction.isInterestPostingAndNotReversed() && !savingsAccountTransaction.isReversalTransaction()
&& !isUpdated) {
setInterestPostedTillDate(savingsAccountTransaction.getLastTransactionDate());
setInterestPostedTillDate(savingsAccountTransaction.getTransactionDate());
isUpdated = true;
if (!backdatedTxnsAllowedTill) {
break;
@@ -224,7 +224,7 @@ public final class SavingsAccountSummary {
}
if (savingsAccountTransaction.isOverdraftInterestAndNotReversed() && !savingsAccountTransaction.isReversalTransaction()
&& !isUpdated) {
setInterestPostedTillDate(savingsAccountTransaction.getLastTransactionDate());
setInterestPostedTillDate(savingsAccountTransaction.getTransactionDate());
isUpdated = true;
if (!backdatedTxnsAllowedTill) {
break;
@@ -18,6 +18,8 @@
*/
package org.apache.fineract.portfolio.savings.domain;
import static org.apache.fineract.infrastructure.core.service.DateUtils.getSystemZoneId;
import jakarta.persistence.CascadeType;
import jakarta.persistence.Column;
import jakarta.persistence.Entity;
@@ -29,14 +31,16 @@ import jakarta.persistence.Table;
import java.math.BigDecimal;
import java.time.LocalDate;
import java.time.LocalDateTime;
import java.time.OffsetDateTime;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.HashSet;
import java.util.LinkedHashMap;
import java.util.List;
import java.util.Map;
import java.util.Optional;
import java.util.Set;
import org.apache.fineract.infrastructure.core.domain.AbstractPersistableCustom;
import org.apache.fineract.infrastructure.core.domain.AbstractAuditableWithUTCDateTimeCustom;
import org.apache.fineract.infrastructure.core.domain.LocalDateInterval;
import org.apache.fineract.infrastructure.core.service.DateUtils;
import org.apache.fineract.organisation.monetary.domain.MonetaryCurrency;
@@ -50,7 +54,6 @@ import org.apache.fineract.portfolio.savings.domain.interest.EndOfDayBalance;
import org.apache.fineract.portfolio.savings.domain.interest.SavingsAccountTransactionDetailsForPostingPeriod;
import org.apache.fineract.portfolio.savings.service.SavingsEnumerations;
import org.apache.fineract.portfolio.tax.domain.TaxComponent;
import org.apache.fineract.useradministration.domain.AppUser;
import org.springframework.util.CollectionUtils;
/**
@@ -58,7 +61,7 @@ import org.springframework.util.CollectionUtils;
*/
@Entity
@Table(name = "m_savings_account_transaction")
public final class SavingsAccountTransaction extends AbstractPersistableCustom {
public final class SavingsAccountTransaction extends AbstractAuditableWithUTCDateTimeCustom {
@ManyToOne(optional = false)
@JoinColumn(name = "savings_account_id", referencedColumnName = "id", nullable = false)
@@ -102,16 +105,13 @@ public final class SavingsAccountTransaction extends AbstractPersistableCustom {
@Column(name = "overdraft_amount_derived", scale = 6, precision = 19, nullable = true)
private BigDecimal overdraftAmount;
@Column(name = "created_date", nullable = false)
private LocalDateTime createdDate;
@Deprecated
@Column(name = "created_date", nullable = true)
private LocalDateTime createdDateToRemove;
@Column(name = "submitted_on_date", nullable = false)
private LocalDate submittedOnDate;
@ManyToOne
@JoinColumn(name = "appuser_id", nullable = true)
private AppUser appUser;
@Column(name = "is_manual", length = 1, nullable = true)
private boolean isManualTransaction;
@@ -143,16 +143,11 @@ public final class SavingsAccountTransaction extends AbstractPersistableCustom {
@Column(name = "ref_no", nullable = true)
private String refNo;
SavingsAccountTransaction() {
this.dateOf = null;
this.typeOf = null;
this.createdDate = null;
}
SavingsAccountTransaction() {}
private SavingsAccountTransaction(final SavingsAccount savingsAccount, final Office office, final PaymentDetail paymentDetail,
final Integer typeOf, final LocalDate transactionLocalDate, final LocalDateTime createdDate, final BigDecimal amount,
final boolean isReversed, final AppUser appUser, final boolean isManualTransaction, final Boolean lienTransaction,
final String refNo) {
final Integer typeOf, final LocalDate transactionLocalDate, final BigDecimal amount, final boolean isReversed,
final boolean isManualTransaction, final Boolean lienTransaction, final String refNo) {
this.savingsAccount = savingsAccount;
this.office = office;
this.typeOf = typeOf;
@@ -160,42 +155,52 @@ public final class SavingsAccountTransaction extends AbstractPersistableCustom {
this.amount = amount;
this.reversed = isReversed;
this.paymentDetail = paymentDetail;
this.createdDate = createdDate;
this.createdDateToRemove = null; // #audit backward compatibility deprecated
this.submittedOnDate = DateUtils.getBusinessLocalDate();
this.appUser = appUser;
this.isManualTransaction = isManualTransaction;
this.lienTransaction = lienTransaction;
this.refNo = refNo;
}
private SavingsAccountTransaction(final SavingsAccount savingsAccount, final Office office, final Integer typeOf,
final LocalDate transactionLocalDate, final Money amount, final boolean isReversed, final boolean isManualTransaction,
final Boolean lienTransaction, final String refNo) {
this(savingsAccount, office, null, typeOf, transactionLocalDate, amount, isReversed, isManualTransaction, lienTransaction, refNo);
}
private SavingsAccountTransaction(final SavingsAccount savingsAccount, final Office office, final PaymentDetail paymentDetail,
final Integer typeOf, final LocalDate transactionLocalDate, final Money amount, final boolean isReversed,
final boolean isManualTransaction, final Boolean lienTransaction, final String refNo) {
this(savingsAccount, office, paymentDetail, typeOf, transactionLocalDate, amount.getAmount(), isReversed, isManualTransaction,
lienTransaction, refNo);
}
public static SavingsAccountTransaction deposit(final SavingsAccount savingsAccount, final Office office,
final PaymentDetail paymentDetail, final LocalDate date, final Money amount, LocalDateTime createdDate, final AppUser appUser,
final String refNo) {
final PaymentDetail paymentDetail, final LocalDate date, final Money amount, final String refNo) {
final boolean isReversed = false;
final boolean isManualTransaction = false;
final Boolean lienTransaction = false;
return new SavingsAccountTransaction(savingsAccount, office, paymentDetail, SavingsAccountTransactionType.DEPOSIT.getValue(), date,
createdDate, amount, isReversed, appUser, isManualTransaction, lienTransaction, refNo);
amount, isReversed, isManualTransaction, lienTransaction, refNo);
}
public static SavingsAccountTransaction deposit(final SavingsAccount savingsAccount, final Office office,
final PaymentDetail paymentDetail, final LocalDate date, final Money amount, LocalDateTime createdDate, final AppUser appUser,
final PaymentDetail paymentDetail, final LocalDate date, final Money amount,
final SavingsAccountTransactionType savingsAccountTransactionType, final String refNo) {
final boolean isReversed = false;
final boolean isManualTransaction = false;
final Boolean lienTransaction = false;
return new SavingsAccountTransaction(savingsAccount, office, paymentDetail, savingsAccountTransactionType.getValue(), date,
createdDate, amount, isReversed, appUser, isManualTransaction, lienTransaction, refNo);
return new SavingsAccountTransaction(savingsAccount, office, paymentDetail, savingsAccountTransactionType.getValue(), date, amount,
isReversed, isManualTransaction, lienTransaction, refNo);
}
public static SavingsAccountTransaction withdrawal(final SavingsAccount savingsAccount, final Office office,
final PaymentDetail paymentDetail, final LocalDate date, final Money amount, LocalDateTime createdDate, final AppUser appUser,
final String refNo) {
final PaymentDetail paymentDetail, final LocalDate date, final Money amount, final String refNo) {
final boolean isReversed = false;
final boolean isManualTransaction = false;
final Boolean lienTransaction = false;
return new SavingsAccountTransaction(savingsAccount, office, paymentDetail, SavingsAccountTransactionType.WITHDRAWAL.getValue(),
date, createdDate, amount, isReversed, appUser, isManualTransaction, lienTransaction, refNo);
date, amount, isReversed, isManualTransaction, lienTransaction, refNo);
}
public static SavingsAccountTransaction interestPosting(final SavingsAccount savingsAccount, final Office office, final LocalDate date,
@@ -204,7 +209,7 @@ public final class SavingsAccountTransaction extends AbstractPersistableCustom {
final Boolean lienTransaction = false;
final String refNo = null;
return new SavingsAccountTransaction(savingsAccount, office, SavingsAccountTransactionType.INTEREST_POSTING.getValue(), date,
amount, isReversed, null, isManualTransaction, lienTransaction, refNo);
amount, isReversed, isManualTransaction, lienTransaction, refNo);
}
public static SavingsAccountTransaction overdraftInterest(final SavingsAccount savingsAccount, final Office office,
@@ -213,82 +218,82 @@ public final class SavingsAccountTransaction extends AbstractPersistableCustom {
final Boolean lienTransaction = false;
final String refNo = null;
return new SavingsAccountTransaction(savingsAccount, office, SavingsAccountTransactionType.OVERDRAFT_INTEREST.getValue(), date,
amount, isReversed, null, isManualTransaction, lienTransaction, refNo);
amount, isReversed, isManualTransaction, lienTransaction, refNo);
}
public static SavingsAccountTransaction withdrawalFee(final SavingsAccount savingsAccount, final Office office, final LocalDate date,
final Money amount, final AppUser appUser, final String refNo) {
final Money amount, final String refNo) {
final boolean isReversed = false;
final boolean isManualTransaction = false;
final Boolean lienTransaction = false;
return new SavingsAccountTransaction(savingsAccount, office, SavingsAccountTransactionType.WITHDRAWAL_FEE.getValue(), date, amount,
isReversed, appUser, isManualTransaction, lienTransaction, refNo);
isReversed, isManualTransaction, lienTransaction, refNo);
}
public static SavingsAccountTransaction annualFee(final SavingsAccount savingsAccount, final Office office, final LocalDate date,
final Money amount, final AppUser appUser) {
final Money amount) {
final boolean isReversed = false;
final boolean isManualTransaction = false;
final Boolean lienTransaction = false;
final String refNo = null;
return new SavingsAccountTransaction(savingsAccount, office, SavingsAccountTransactionType.ANNUAL_FEE.getValue(), date, amount,
isReversed, appUser, isManualTransaction, lienTransaction, refNo);
isReversed, isManualTransaction, lienTransaction, refNo);
}
public static SavingsAccountTransaction charge(final SavingsAccount savingsAccount, final Office office, final LocalDate date,
final Money amount, final AppUser appUser) {
final Money amount) {
final boolean isReversed = false;
final boolean isManualTransaction = false;
final Boolean lienTransaction = false;
final String refNo = null;
return new SavingsAccountTransaction(savingsAccount, office, SavingsAccountTransactionType.PAY_CHARGE.getValue(), date, amount,
isReversed, appUser, isManualTransaction, lienTransaction, refNo);
isReversed, isManualTransaction, lienTransaction, refNo);
}
public static SavingsAccountTransaction waiver(final SavingsAccount savingsAccount, final Office office, final LocalDate date,
final Money amount, final AppUser appUser) {
final Money amount) {
final boolean isReversed = false;
final boolean isManualTransaction = false;
final Boolean lienTransaction = false;
final String refNo = null;
return new SavingsAccountTransaction(savingsAccount, office, SavingsAccountTransactionType.WAIVE_CHARGES.getValue(), date, amount,
isReversed, appUser, isManualTransaction, lienTransaction, refNo);
isReversed, isManualTransaction, lienTransaction, refNo);
}
public static SavingsAccountTransaction initiateTransfer(final SavingsAccount savingsAccount, final Office office, final LocalDate date,
final AppUser appUser) {
public static SavingsAccountTransaction initiateTransfer(final SavingsAccount savingsAccount, final Office office,
final LocalDate date) {
final boolean isReversed = false;
final boolean isManualTransaction = false;
final PaymentDetail paymentDetail = null;
final Boolean lienTransaction = false;
final String refNo = null;
return new SavingsAccountTransaction(savingsAccount, office, paymentDetail,
SavingsAccountTransactionType.INITIATE_TRANSFER.getValue(), date, DateUtils.getLocalDateTimeOfSystem(),
savingsAccount.getSummary().getAccountBalance(), isReversed, appUser, isManualTransaction, lienTransaction, refNo);
SavingsAccountTransactionType.INITIATE_TRANSFER.getValue(), date, savingsAccount.getSummary().getAccountBalance(),
isReversed, isManualTransaction, lienTransaction, refNo);
}
public static SavingsAccountTransaction approveTransfer(final SavingsAccount savingsAccount, final Office office, final LocalDate date,
final AppUser appUser) {
public static SavingsAccountTransaction approveTransfer(final SavingsAccount savingsAccount, final Office office,
final LocalDate date) {
final boolean isReversed = false;
final boolean isManualTransaction = false;
final PaymentDetail paymentDetail = null;
final Boolean lienTransaction = false;
final String refNo = null;
return new SavingsAccountTransaction(savingsAccount, office, paymentDetail,
SavingsAccountTransactionType.APPROVE_TRANSFER.getValue(), date, DateUtils.getLocalDateTimeOfSystem(),
savingsAccount.getSummary().getAccountBalance(), isReversed, appUser, isManualTransaction, lienTransaction, refNo);
SavingsAccountTransactionType.APPROVE_TRANSFER.getValue(), date, savingsAccount.getSummary().getAccountBalance(),
isReversed, isManualTransaction, lienTransaction, refNo);
}
public static SavingsAccountTransaction withdrawTransfer(final SavingsAccount savingsAccount, final Office office, final LocalDate date,
final AppUser appUser) {
public static SavingsAccountTransaction withdrawTransfer(final SavingsAccount savingsAccount, final Office office,
final LocalDate date) {
final boolean isReversed = false;
final boolean isManualTransaction = false;
final PaymentDetail paymentDetail = null;
final Boolean lienTransaction = false;
final String refNo = null;
return new SavingsAccountTransaction(savingsAccount, office, paymentDetail,
SavingsAccountTransactionType.WITHDRAW_TRANSFER.getValue(), date, DateUtils.getLocalDateTimeOfSystem(),
savingsAccount.getSummary().getAccountBalance(), isReversed, appUser, isManualTransaction, lienTransaction, refNo);
SavingsAccountTransactionType.WITHDRAW_TRANSFER.getValue(), date, savingsAccount.getSummary().getAccountBalance(),
isReversed, isManualTransaction, lienTransaction, refNo);
}
public static SavingsAccountTransaction withHoldTax(final SavingsAccount savingsAccount, final Office office, final LocalDate date,
@@ -298,21 +303,51 @@ public final class SavingsAccountTransaction extends AbstractPersistableCustom {
final Boolean lienTransaction = false;
final String refNo = null;
SavingsAccountTransaction accountTransaction = new SavingsAccountTransaction(savingsAccount, office,
SavingsAccountTransactionType.WITHHOLD_TAX.getValue(), date, amount, isReversed, null, isManualTransaction, lienTransaction,
SavingsAccountTransactionType.WITHHOLD_TAX.getValue(), date, amount, isReversed, isManualTransaction, lienTransaction,
refNo);
updateTaxDetails(taxDetails, accountTransaction);
return accountTransaction;
}
public static SavingsAccountTransaction escheat(final SavingsAccount savingsAccount, final LocalDate date, final AppUser appUser,
public static SavingsAccountTransaction escheat(final SavingsAccount savingsAccount, final LocalDate date,
final boolean accountTransaction) {
final boolean isReversed = false;
final PaymentDetail paymentDetail = null;
final Boolean lienTransaction = false;
final String refNo = null;
return new SavingsAccountTransaction(savingsAccount, savingsAccount.office(), paymentDetail,
SavingsAccountTransactionType.ESCHEAT.getValue(), date, DateUtils.getLocalDateTimeOfSystem(),
savingsAccount.getSummary().getAccountBalance(), isReversed, appUser, accountTransaction, lienTransaction, refNo);
SavingsAccountTransactionType.ESCHEAT.getValue(), date, savingsAccount.getSummary().getAccountBalance(), isReversed,
accountTransaction, lienTransaction, refNo);
}
public static SavingsAccountTransaction copyTransaction(SavingsAccountTransaction accountTransaction) {
return new SavingsAccountTransaction(accountTransaction.savingsAccount, accountTransaction.office, accountTransaction.paymentDetail,
accountTransaction.typeOf, accountTransaction.getTransactionDate(), accountTransaction.amount, accountTransaction.reversed,
accountTransaction.isManualTransaction, accountTransaction.lienTransaction, accountTransaction.refNo);
}
public static SavingsAccountTransaction holdAmount(final SavingsAccount savingsAccount, final Office office,
final PaymentDetail paymentDetail, final LocalDate date, final Money amount, final Boolean lienTransaction) {
final boolean isReversed = false;
final boolean isManualTransaction = false;
final String refNo = null;
return new SavingsAccountTransaction(savingsAccount, office, paymentDetail, SavingsAccountTransactionType.AMOUNT_HOLD.getValue(),
date, amount, isReversed, isManualTransaction, lienTransaction, refNo);
}
public static SavingsAccountTransaction releaseAmount(SavingsAccountTransaction accountTransaction, LocalDate transactionDate) {
return new SavingsAccountTransaction(accountTransaction.savingsAccount, accountTransaction.office, accountTransaction.paymentDetail,
SavingsAccountTransactionType.AMOUNT_RELEASE.getValue(), transactionDate, accountTransaction.amount,
accountTransaction.reversed, accountTransaction.isManualTransaction, accountTransaction.lienTransaction,
accountTransaction.refNo);
}
public static SavingsAccountTransaction reversal(SavingsAccountTransaction accountTransaction) {
SavingsAccountTransaction sat = copyTransaction(accountTransaction);
sat.reversed = false;
sat.setReversalTransaction(true);
sat.originalTxnId = accountTransaction.getId();
return sat;
}
public static void updateTaxDetails(final Map<TaxComponent, BigDecimal> taxDetails,
@@ -325,71 +360,142 @@ public final class SavingsAccountTransaction extends AbstractPersistableCustom {
}
}
public static SavingsAccountTransaction copyTransaction(SavingsAccountTransaction accountTransaction) {
return new SavingsAccountTransaction(accountTransaction.savingsAccount, accountTransaction.office, accountTransaction.paymentDetail,
accountTransaction.typeOf, accountTransaction.transactionLocalDate(), DateUtils.getLocalDateTimeOfSystem(),
accountTransaction.amount, accountTransaction.reversed, accountTransaction.appUser, accountTransaction.isManualTransaction,
accountTransaction.lienTransaction, accountTransaction.refNo);
public SavingsAccount getSavingsAccount() {
return this.savingsAccount;
}
private SavingsAccountTransaction(final SavingsAccount savingsAccount, final Office office, final Integer typeOf,
final LocalDate transactionLocalDate, final Money amount, final boolean isReversed, final AppUser appUser,
final boolean isManualTransaction, final Boolean lienTransaction, final String refNo) {
this(savingsAccount, office, null, typeOf, transactionLocalDate, DateUtils.getLocalDateTimeOfSystem(), amount, isReversed, appUser,
isManualTransaction, lienTransaction, refNo);
}
private SavingsAccountTransaction(final SavingsAccount savingsAccount, final Office office, final PaymentDetail paymentDetail,
final Integer typeOf, final LocalDate transactionLocalDate, final LocalDateTime createdDate, final Money amount,
final boolean isReversed, final AppUser appUser, final boolean isManualTransaction, final Boolean lienTransaction,
final String refNo) {
this(savingsAccount, office, paymentDetail, typeOf, transactionLocalDate, createdDate, amount.getAmount(), isReversed, appUser,
isManualTransaction, lienTransaction, refNo);
}
public static SavingsAccountTransaction holdAmount(final SavingsAccount savingsAccount, final Office office,
final PaymentDetail paymentDetail, final LocalDate date, final Money amount, LocalDateTime createdDate, final AppUser appUser,
final Boolean lienTransaction) {
final boolean isReversed = false;
final boolean isManualTransaction = false;
final String refNo = null;
return new SavingsAccountTransaction(savingsAccount, office, paymentDetail, SavingsAccountTransactionType.AMOUNT_HOLD.getValue(),
date, createdDate, amount, isReversed, appUser, isManualTransaction, lienTransaction, refNo);
}
public static SavingsAccountTransaction releaseAmount(SavingsAccountTransaction accountTransaction, LocalDate transactionDate,
LocalDateTime createdDate, final AppUser appUser) {
return new SavingsAccountTransaction(accountTransaction.savingsAccount, accountTransaction.office, accountTransaction.paymentDetail,
SavingsAccountTransactionType.AMOUNT_RELEASE.getValue(), transactionDate, createdDate, accountTransaction.amount,
accountTransaction.reversed, appUser, accountTransaction.isManualTransaction, accountTransaction.lienTransaction,
accountTransaction.refNo);
}
public static SavingsAccountTransaction reversal(SavingsAccountTransaction accountTransaction) {
SavingsAccountTransaction sat = copyTransaction(accountTransaction);
sat.reversed = false;
sat.setReversalTransaction(true);
sat.originalTxnId = accountTransaction.getId();
return sat;
}
public LocalDate transactionLocalDate() {
public LocalDate getTransactionDate() {
return this.dateOf;
}
public LocalDate getEndOfBalanceDate() {
return balanceEndDate;
}
public boolean isReversed() {
return this.reversed;
}
public void reverse() {
this.reversed = true;
}
public BigDecimal getAmount() {
return this.amount;
}
public Money getAmount(final MonetaryCurrency currency) {
return Money.of(currency, this.amount);
}
public void setAmount(final Money amount) {
this.amount = amount == null ? null : amount.getAmount();
}
public BigDecimal getRunningBalance() {
return this.runningBalance;
}
public Money getRunningBalance(final MonetaryCurrency currency) {
return Money.of(currency, this.runningBalance);
}
public void setRunningBalance(Money balance) {
this.runningBalance = balance == null ? null : balance.getAmount();
}
public boolean isManualTransaction() {
return this.isManualTransaction;
}
public Set<SavingsAccountChargePaidBy> getSavingsAccountChargesPaid() {
return this.savingsAccountChargesPaid;
}
public BigDecimal getOverdraftAmount() {
return this.overdraftAmount;
}
public Money getOverdraftAmount(final MonetaryCurrency currency) {
return Money.of(currency, this.overdraftAmount);
}
void setOverdraftAmount(Money overdraftAmount) {
this.overdraftAmount = overdraftAmount == null ? null : overdraftAmount.getAmount();
}
public List<SavingsAccountTransactionTaxDetails> getTaxDetails() {
return this.taxDetails;
}
public List<Note> getNotes() {
return notes;
}
public Integer getTypeOf() {
return this.typeOf;
}
public SavingsAccountTransactionType getTransactionType() {
return SavingsAccountTransactionType.fromInt(this.typeOf);
}
public LocalDate getDateOf() {
return this.dateOf;
}
public String getRefNo() {
return this.refNo;
}
public PaymentDetail getPaymentDetail() {
return this.paymentDetail;
}
public void updateReleaseId(Long releaseId) {
this.releaseIdOfHoldAmountTransaction = releaseId;
}
public void updateReason(String reasonForBlock) {
this.reasonForBlock = reasonForBlock;
}
public Long getReleaseIdOfHoldAmountTransaction() {
return this.releaseIdOfHoldAmountTransaction;
}
public MonetaryCurrency getCurrency() {
return savingsAccount == null ? null : savingsAccount.getCurrency();
}
public Long getOfficeId() {
return this.office.getId();
}
public LocalDate getBalanceEndDate() {
return this.balanceEndDate;
}
public BigDecimal getCumulativeBalance() {
return this.cumulativeBalance;
}
public Integer getBalanceNumberOfDays() {
return this.balanceNumberOfDays;
}
public LocalDate getSubmittedOnDate() {
return submittedOnDate;
}
public boolean isReversalTransaction() {
return reversalTransaction;
}
void setReversalTransaction(boolean reversalTransaction) {
this.reversalTransaction = reversalTransaction;
}
public boolean isDeposit() {
return getTransactionType().isDeposit();
}
@@ -442,10 +548,6 @@ public final class SavingsAccountTransaction extends AbstractPersistableCustom {
return !isReversed();
}
public boolean isReversed() {
return this.reversed;
}
public boolean isTransferInitiation() {
return getTransactionType().isTransferInitiation();
}
@@ -466,14 +568,6 @@ public final class SavingsAccountTransaction extends AbstractPersistableCustom {
return isTransferInitiation() || isTransferApproval() || isTransferRejection() || isTransferWithdrawal();
}
public boolean occursOn(final LocalDate occursOnDate) {
return getTransactionLocalDate().isEqual(occursOnDate);
}
public void setLoanDisbursement(boolean isLoanDisbursement) {
this.isLoanDisbursement = isLoanDisbursement;
}
public void zeroBalanceFields() {
this.runningBalance = null;
this.cumulativeBalance = null;
@@ -481,35 +575,19 @@ public final class SavingsAccountTransaction extends AbstractPersistableCustom {
this.balanceNumberOfDays = null;
}
public void updateRunningBalance(final Money balance) {
this.runningBalance = balance.getAmount();
}
public void updateCumulativeBalanceAndDates(final MonetaryCurrency currency, final LocalDate endOfBalanceDate) {
// balance end date should not be before transaction date
if (endOfBalanceDate != null && endOfBalanceDate.isBefore(this.transactionLocalDate())) {
this.balanceEndDate = this.transactionLocalDate();
if (endOfBalanceDate != null && DateUtils.isBefore(endOfBalanceDate, this.getTransactionDate())) {
this.balanceEndDate = this.getTransactionDate();
} else {
this.balanceEndDate = endOfBalanceDate;
}
this.balanceNumberOfDays = LocalDateInterval.create(getTransactionLocalDate(), endOfBalanceDate).daysInPeriodInclusiveOfEndDate();
this.balanceNumberOfDays = LocalDateInterval.create(getTransactionDate(), endOfBalanceDate).daysInPeriodInclusiveOfEndDate();
this.cumulativeBalance = Money.of(currency, this.runningBalance).multipliedBy(this.balanceNumberOfDays).getAmount();
}
public LocalDate getTransactionLocalDate() {
return this.dateOf;
}
public LocalDate getLastTransactionDate() {
return this.dateOf;
}
public LocalDate getEndOfBalanceLocalDate() {
return balanceEndDate;
}
public boolean isAcceptableForDailyBalance(final LocalDateInterval interestPeriodInterval) {
return isNotReversed() && interestPeriodInterval.contains(getTransactionLocalDate()) && isABalanceForAtLeastOneDay();
return isNotReversed() && interestPeriodInterval.contains(getTransactionDate()) && isABalanceForAtLeastOneDay();
}
private boolean isABalanceForAtLeastOneDay() {
@@ -530,7 +608,7 @@ public final class SavingsAccountTransaction extends AbstractPersistableCustom {
thisTransactionData.put("officeId", this.office.getId());
thisTransactionData.put("type", transactionType);
thisTransactionData.put("reversed", isReversed());
thisTransactionData.put("date", getTransactionLocalDate());
thisTransactionData.put("date", getTransactionDate());
thisTransactionData.put("currencyCode", currencyCode);
thisTransactionData.put("amount", this.amount);
thisTransactionData.put("overdraftAmount", this.overdraftAmount);
@@ -573,29 +651,28 @@ public final class SavingsAccountTransaction extends AbstractPersistableCustom {
return thisTransactionData;
}
public boolean isAfter(final LocalDate transactionDate) {
return getTransactionLocalDate().isAfter(transactionDate);
public boolean isBefore(final LocalDate date) {
return DateUtils.isBefore(getTransactionDate(), date);
}
public boolean isManualTransaction() {
return this.isManualTransaction;
public boolean isAfter(final LocalDate date) {
return DateUtils.isAfter(getTransactionDate(), date);
}
public void setPostInterestAsOn(boolean isManualTransaction) {
this.isManualTransaction = isManualTransaction;
public boolean occursOn(final LocalDate date) {
return DateUtils.isEqual(getTransactionDate(), date);
}
public EndOfDayBalance toEndOfDayBalance(final LocalDateInterval periodInterval, final MonetaryCurrency currency) {
final Money endOfDayBalance = Money.of(currency, this.runningBalance);
final Money openingBalance = endOfDayBalance;
LocalDate balanceDate = periodInterval.startDate();
int numberOfDays = periodInterval.daysInPeriodInclusiveOfEndDate();
if (periodInterval.contains(getTransactionLocalDate())) {
balanceDate = getTransactionLocalDate();
final LocalDateInterval newInterval = LocalDateInterval.create(getTransactionLocalDate(), periodInterval.endDate());
if (periodInterval.contains(getTransactionDate())) {
balanceDate = getTransactionDate();
final LocalDateInterval newInterval = LocalDateInterval.create(getTransactionDate(), periodInterval.endDate());
numberOfDays = newInterval.daysInPeriodInclusiveOfEndDate();
}
@@ -603,7 +680,6 @@ public final class SavingsAccountTransaction extends AbstractPersistableCustom {
}
public EndOfDayBalance toEndOfDayBalance(final Money openingBalance, final LocalDate nextTransactionDate) {
final MonetaryCurrency currency = openingBalance.getCurrency();
Money endOfDayBalance = openingBalance.copy();
if (isDeposit() || isDividendPayoutAndNotReversed()) {
@@ -612,11 +688,11 @@ public final class SavingsAccountTransaction extends AbstractPersistableCustom {
endOfDayBalance = openingBalance.minus(getAmount(currency));
}
int numberOfDays = LocalDateInterval.create(getTransactionLocalDate(), nextTransactionDate).daysInPeriodInclusiveOfEndDate();
int numberOfDays = LocalDateInterval.create(getTransactionDate(), nextTransactionDate).daysInPeriodInclusiveOfEndDate();
if (!openingBalance.isEqualTo(endOfDayBalance) && numberOfDays > 1) {
numberOfDays = numberOfDays - 1;
}
return EndOfDayBalance.from(getTransactionLocalDate(), openingBalance, endOfDayBalance, numberOfDays);
return EndOfDayBalance.from(getTransactionDate(), openingBalance, endOfDayBalance, numberOfDays);
}
public EndOfDayBalance toEndOfDayBalance(final Money openingBalance) {
@@ -629,24 +705,23 @@ public final class SavingsAccountTransaction extends AbstractPersistableCustom {
if (openingBalance.isGreaterThanZero() || this.savingsAccount.allowOverdraft()) {
endOfDayBalance = openingBalance.minus(getAmount(currency));
} else {
endOfDayBalance = Money.of(currency, this.runningBalance);
endOfDayBalance = getRunningBalance(currency);
}
}
return EndOfDayBalance.from(getTransactionLocalDate(), openingBalance, endOfDayBalance, this.balanceNumberOfDays);
return EndOfDayBalance.from(getTransactionDate(), openingBalance, endOfDayBalance, this.balanceNumberOfDays);
}
public EndOfDayBalance toEndOfDayBalanceBoundedBy(final Money openingBalance, final LocalDateInterval boundedBy) {
final MonetaryCurrency currency = openingBalance.getCurrency();
Money endOfDayBalance = openingBalance.copy();
int numberOfDaysOfBalance = this.balanceNumberOfDays;
LocalDate balanceStartDate = getTransactionLocalDate();
LocalDate balanceEndDate = getEndOfBalanceLocalDate();
LocalDate balanceStartDate = getTransactionDate();
LocalDate balanceEndDate = getEndOfBalanceDate();
if (boundedBy.startDate().isAfter(balanceStartDate)) {
if (DateUtils.isBefore(balanceStartDate, boundedBy.startDate())) {
balanceStartDate = boundedBy.startDate();
final LocalDateInterval spanOfBalance = LocalDateInterval.create(balanceStartDate, balanceEndDate);
numberOfDaysOfBalance = spanOfBalance.daysInPeriodInclusiveOfEndDate();
@@ -661,12 +736,12 @@ public final class SavingsAccountTransaction extends AbstractPersistableCustom {
if (endOfDayBalance.isGreaterThanZero() || this.savingsAccount.allowOverdraft()) {
endOfDayBalance = endOfDayBalance.minus(getAmount(currency));
} else {
endOfDayBalance = Money.of(currency, this.runningBalance);
endOfDayBalance = getRunningBalance(currency);
}
}
}
if (balanceEndDate.isAfter(boundedBy.endDate())) {
if (DateUtils.isAfter(balanceEndDate, boundedBy.endDate())) {
balanceEndDate = boundedBy.endDate();
final LocalDateInterval spanOfBalance = LocalDateInterval.create(balanceStartDate, balanceEndDate);
numberOfDaysOfBalance = spanOfBalance.daysInPeriodInclusiveOfEndDate();
@@ -676,16 +751,16 @@ public final class SavingsAccountTransaction extends AbstractPersistableCustom {
}
public boolean isBalanceInExistencesForOneDayOrMore() {
return this.balanceNumberOfDays != null && this.balanceNumberOfDays.intValue() >= 1;
return this.balanceNumberOfDays != null && this.balanceNumberOfDays >= 1;
}
public boolean fallsWithin(final LocalDateInterval periodInterval) {
final LocalDateInterval balanceInterval = LocalDateInterval.create(getTransactionLocalDate(), getEndOfBalanceLocalDate());
final LocalDateInterval balanceInterval = LocalDateInterval.create(getTransactionDate(), getEndOfBalanceDate());
return periodInterval.contains(balanceInterval);
}
public boolean spansAnyPortionOf(final LocalDateInterval periodInterval) {
final LocalDateInterval balanceInterval = LocalDateInterval.create(getTransactionLocalDate(), getEndOfBalanceLocalDate());
final LocalDateInterval balanceInterval = LocalDateInterval.create(getTransactionDate(), getEndOfBalanceDate());
return balanceInterval.containsPortionOf(periodInterval);
}
@@ -793,123 +868,22 @@ public final class SavingsAccountTransaction extends AbstractPersistableCustom {
return null;
}
public Set<SavingsAccountChargePaidBy> getSavingsAccountChargesPaid() {
return this.savingsAccountChargesPaid;
}
public void updateOverdraftAmount(BigDecimal overdraftAmount) {
this.overdraftAmount = overdraftAmount;
}
public Money getOverdraftAmount(final MonetaryCurrency currency) {
return Money.of(currency, this.overdraftAmount);
}
public boolean isPaymentForCurrentCharge(final SavingsAccountCharge savingsAccountCharge) {
final SavingsAccountChargePaidBy chargePaidBy = getSavingsAccountChargePaidBy();
return chargePaidBy != null && chargePaidBy.getSavingsAccountCharge().equals(savingsAccountCharge);
}
public BigDecimal getAmount() {
return this.amount;
}
public List<SavingsAccountTransactionTaxDetails> getTaxDetails() {
return this.taxDetails;
}
public List<Note> getNotes() {
return notes;
}
public void updateAmount(final Money amount) {
this.amount = amount.getAmount();
}
public Integer getTypeOf() {
return this.typeOf;
}
public SavingsAccountTransactionType getTransactionType() {
return SavingsAccountTransactionType.fromInt(this.typeOf);
}
public SavingsAccount getSavingsAccount() {
return this.savingsAccount;
}
public void setSavingsAccount(SavingsAccount savingsAccount) {
this.savingsAccount = savingsAccount;
}
public LocalDate getDateOf() {
return this.dateOf;
}
public String getRefNo() {
return this.refNo;
}
public PaymentDetail getPaymentDetail() {
return this.paymentDetail;
}
public void updateReleaseId(Long releaseId) {
this.releaseIdOfHoldAmountTransaction = releaseId;
}
public void updateReason(String reasonForBlock) {
this.reasonForBlock = reasonForBlock;
}
public Long getReleaseIdOfHoldAmountTransaction() {
return this.releaseIdOfHoldAmountTransaction;
@Override
public Optional<OffsetDateTime> getCreatedDate() {
// #audit backward compatibility keep system datetime
return Optional.ofNullable(super.getCreatedDate()
.orElse(createdDateToRemove == null ? null : createdDateToRemove.atZone(getSystemZoneId()).toOffsetDateTime()));
}
public boolean isAmountOnHoldNotReleased() {
return (isAmountOnHold() && getReleaseIdOfHoldAmountTransaction() == null);
}
public Long getOfficeId() {
return this.office.getId();
}
public LocalDate getBalanceEndDate() {
return this.balanceEndDate;
}
public BigDecimal getCumulativeBalance() {
return this.cumulativeBalance;
}
public Integer getBalanceNumberOfDays() {
return this.balanceNumberOfDays;
}
public Long getAppUserId() {
return this.appUser.getId();
}
public LocalDateTime getCreatedDate() {
return this.createdDate;
}
public LocalDate getSubmittedOnDate() {
return submittedOnDate;
}
public boolean getIsManualTransaction() {
return this.isManualTransaction;
}
public void setReversalTransaction(boolean reversalTransaction) {
this.reversalTransaction = reversalTransaction;
}
public boolean isReversalTransaction() {
return reversalTransaction;
}
public SavingsAccountTransactionDetailsForPostingPeriod toSavingsAccountTransactionDetailsForPostingPeriod(MonetaryCurrency currency,
boolean isAllowOverDraft) {
return new SavingsAccountTransactionDetailsForPostingPeriod(getId(), this.dateOf, this.balanceEndDate, this.runningBalance,
@@ -19,6 +19,7 @@
package org.apache.fineract.portfolio.savings.domain;
import java.util.Comparator;
import org.apache.fineract.infrastructure.core.service.DateUtils;
/**
* Sort savings account transactions by transaction date and transaction type placing
@@ -27,18 +28,17 @@ public class SavingsAccountTransactionComparator implements Comparator<SavingsAc
@Override
public int compare(final SavingsAccountTransaction o1, final SavingsAccountTransaction o2) {
int compareResult = 0;
final int comparsion = o1.transactionLocalDate().compareTo(o2.transactionLocalDate());
if (comparsion == 0) {
compareResult = o1.getCreatedDate().compareTo(o2.getCreatedDate());
if (compareResult == 0 && o1.getId() != null && o2.getId() != null) {
compareResult = o1.getId().compareTo(o2.getId());
} else {
compareResult = comparsion;
}
} else {
compareResult = comparsion;
int result = DateUtils.compare(o1.getTransactionDate(), o2.getTransactionDate());
if (result != 0) {
return result;
}
return compareResult;
result = DateUtils.compare(o1.getCreatedDateTime(), o2.getCreatedDateTime());
if (result != 0) {
return result;
}
if (o1.getId() != null && o2.getId() != null) {
return o1.getId().compareTo(o2.getId());
}
return 0;
}
}
@@ -19,26 +19,25 @@
package org.apache.fineract.portfolio.savings.domain;
import java.util.Comparator;
import org.apache.fineract.infrastructure.core.service.DateUtils;
import org.apache.fineract.portfolio.savings.data.SavingsAccountTransactionData;
public class SavingsAccountTransactionDataComparator implements Comparator<SavingsAccountTransactionData> {
@Override
public int compare(final SavingsAccountTransactionData o1, final SavingsAccountTransactionData o2) {
int compareResult = 0;
final int comparsion = o1.getTransactionDate().compareTo(o2.getTransactionDate());
if (comparsion == 0) {
compareResult = o1.getSubmittedOnDate().compareTo(o2.getSubmittedOnDate());
if (compareResult == 0 && o1.getId() != null && o2.getId() != null) {
compareResult = o1.getId().compareTo(o2.getId());
} else {
compareResult = comparsion;
}
} else {
compareResult = comparsion;
int result = DateUtils.compare(o1.getTransactionDate(), o2.getTransactionDate());
if (result != 0) {
return result;
}
return compareResult;
result = DateUtils.compare(o1.getSubmittedOnDate(), o2.getSubmittedOnDate());
if (result != 0) {
return result;
}
if (o1.getId() != null && o2.getId() != null) {
return o1.getId().compareTo(o2.getId());
}
return 0;
}
}
@@ -18,18 +18,24 @@
*/
package org.apache.fineract.portfolio.savings.domain;
import static org.apache.fineract.infrastructure.core.service.DateUtils.getSystemZoneId;
import jakarta.persistence.Column;
import jakarta.persistence.Entity;
import jakarta.persistence.JoinColumn;
import jakarta.persistence.ManyToOne;
import jakarta.persistence.Table;
import java.time.LocalDate;
import org.apache.fineract.infrastructure.core.domain.AbstractAuditableCustom;
import java.time.LocalDateTime;
import java.time.OffsetDateTime;
import java.util.Optional;
import org.apache.fineract.infrastructure.core.domain.AbstractAuditableWithUTCDateTimeCustom;
import org.apache.fineract.infrastructure.core.service.DateUtils;
import org.apache.fineract.organisation.staff.domain.Staff;
@Entity
@Table(name = "m_savings_officer_assignment_history")
public class SavingsOfficerAssignmentHistory extends AbstractAuditableCustom {
public class SavingsOfficerAssignmentHistory extends AbstractAuditableWithUTCDateTimeCustom {
@ManyToOne
@JoinColumn(name = "account_id", nullable = false)
@@ -45,10 +51,13 @@ public class SavingsOfficerAssignmentHistory extends AbstractAuditableCustom {
@Column(name = "end_date")
private LocalDate endDate;
public static SavingsOfficerAssignmentHistory createNew(final SavingsAccount account, final Staff savingsOfficer,
final LocalDate assignmentDate) {
return new SavingsOfficerAssignmentHistory(account, savingsOfficer, assignmentDate, null);
}
@Deprecated
@Column(name = "created_date")
private LocalDateTime createdDateToRemove;
@Deprecated
@Column(name = "lastmodified_date")
private LocalDateTime lastModifiedDateToRemove;
protected SavingsOfficerAssignmentHistory() {
//
@@ -62,7 +71,12 @@ public class SavingsOfficerAssignmentHistory extends AbstractAuditableCustom {
this.endDate = endDate;
}
public void updateSavingsOfficer(final Staff savingsOfficer) {
public static SavingsOfficerAssignmentHistory createNew(final SavingsAccount account, final Staff savingsOfficer,
final LocalDate startDate) {
return new SavingsOfficerAssignmentHistory(account, savingsOfficer, startDate, null);
}
public void setSavingsOfficer(final Staff savingsOfficer) {
this.savingsOfficer = savingsOfficer;
}
@@ -70,28 +84,28 @@ public class SavingsOfficerAssignmentHistory extends AbstractAuditableCustom {
return this.savingsOfficer.identifiedBy(staff);
}
public void updateStartDate(final LocalDate startDate) {
this.startDate = startDate;
}
public void updateEndDate(final LocalDate endDate) {
this.endDate = endDate;
}
public boolean matchesStartDateOf(final LocalDate matchingDate) {
return getStartDate().isEqual(matchingDate);
}
public LocalDate getStartDate() {
return this.startDate;
}
public boolean hasStartDateBefore(final LocalDate matchingDate) {
return matchingDate.isBefore(getStartDate());
public void setStartDate(final LocalDate startDate) {
this.startDate = startDate;
}
public boolean isCurrentRecord() {
return this.endDate == null;
public LocalDate getEndDate() {
return this.endDate;
}
public void setEndDate(final LocalDate endDate) {
this.endDate = endDate;
}
public boolean matchesStartDateOf(final LocalDate matchingDate) {
return DateUtils.isEqual(matchingDate, getStartDate());
}
public boolean isBeforeStartDate(final LocalDate matchingDate) {
return DateUtils.isBefore(matchingDate, getStartDate());
}
/**
@@ -100,12 +114,25 @@ public class SavingsOfficerAssignmentHistory extends AbstractAuditableCustom {
* @param compareDate
* @return
*/
public boolean isEndDateAfter(final LocalDate compareDate) {
return this.endDate != null && this.endDate.isAfter(compareDate);
public boolean isBeforeEndDate(final LocalDate compareDate) {
return DateUtils.isBefore(compareDate, this.endDate);
}
public LocalDate getEndDate() {
return this.endDate;
public boolean isCurrentRecord() {
return this.endDate == null;
}
@Override
public Optional<OffsetDateTime> getCreatedDate() {
// #audit backward compatibility keep system datetime
return Optional.ofNullable(super.getCreatedDate()
.orElse(createdDateToRemove == null ? null : createdDateToRemove.atZone(getSystemZoneId()).toOffsetDateTime()));
}
@Override
public Optional<OffsetDateTime> getLastModifiedDate() {
// #audit backward compatibility keep system datetime
return Optional.ofNullable(super.getLastModifiedDate()
.orElse(lastModifiedDateToRemove == null ? null : lastModifiedDateToRemove.atZone(getSystemZoneId()).toOffsetDateTime()));
}
}
@@ -20,6 +20,7 @@ package org.apache.fineract.portfolio.savings.jobs.generaterdschedule;
import org.apache.fineract.infrastructure.core.service.database.RoutingDataSourceServiceFactory;
import org.apache.fineract.infrastructure.jobs.service.JobName;
import org.apache.fineract.infrastructure.security.service.PlatformSecurityContext;
import org.apache.fineract.portfolio.savings.service.DepositAccountReadPlatformService;
import org.springframework.batch.core.Job;
import org.springframework.batch.core.Step;
@@ -43,6 +44,8 @@ public class GenerateRdScheduleConfig {
private RoutingDataSourceServiceFactory dataSourceServiceFactory;
@Autowired
private DepositAccountReadPlatformService depositAccountReadPlatformService;
@Autowired
private PlatformSecurityContext securityContext;
@Bean
protected Step generateRdScheduleStep() {
@@ -58,6 +61,6 @@ public class GenerateRdScheduleConfig {
@Bean
public GenerateRdScheduleTasklet generateRdScheduleTasklet() {
return new GenerateRdScheduleTasklet(dataSourceServiceFactory, depositAccountReadPlatformService);
return new GenerateRdScheduleTasklet(dataSourceServiceFactory, depositAccountReadPlatformService, securityContext);
}
}
@@ -18,15 +18,23 @@
*/
package org.apache.fineract.portfolio.savings.jobs.generaterdschedule;
import static org.apache.fineract.infrastructure.core.domain.AuditableFieldsConstants.CREATED_BY_DB_FIELD;
import static org.apache.fineract.infrastructure.core.domain.AuditableFieldsConstants.CREATED_DATE_DB_FIELD;
import static org.apache.fineract.infrastructure.core.domain.AuditableFieldsConstants.LAST_MODIFIED_BY_DB_FIELD;
import static org.apache.fineract.infrastructure.core.domain.AuditableFieldsConstants.LAST_MODIFIED_DATE_DB_FIELD;
import java.math.BigDecimal;
import java.time.LocalDate;
import java.time.format.DateTimeFormatter;
import java.time.OffsetDateTime;
import java.util.ArrayList;
import java.util.Collection;
import java.util.List;
import java.util.Map;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.apache.fineract.infrastructure.core.service.DateUtils;
import org.apache.fineract.infrastructure.core.service.database.RoutingDataSourceServiceFactory;
import org.apache.fineract.infrastructure.security.service.PlatformSecurityContext;
import org.apache.fineract.portfolio.savings.DepositAccountUtils;
import org.apache.fineract.portfolio.savings.service.DepositAccountReadPlatformService;
import org.springframework.batch.core.StepContribution;
@@ -41,19 +49,20 @@ public class GenerateRdScheduleTasklet implements Tasklet {
private final RoutingDataSourceServiceFactory dataSourceServiceFactory;
private final DepositAccountReadPlatformService depositAccountReadPlatformService;
private final DateTimeFormatter formatter = DateTimeFormatter.ofPattern("yyyy-MM-dd");
private final DateTimeFormatter formatterWithTime = DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss");
private final PlatformSecurityContext securityContext;
@Override
public RepeatStatus execute(StepContribution contribution, ChunkContext chunkContext) throws Exception {
final JdbcTemplate jdbcTemplate = new JdbcTemplate(dataSourceServiceFactory.determineDataSourceService().retrieveDataSource());
final Collection<Map<String, Object>> scheduleDetails = depositAccountReadPlatformService.retriveDataForRDScheduleCreation();
String insertSql = "INSERT INTO m_mandatory_savings_schedule (savings_account_id, duedate, installment, deposit_amount, completed_derived, created_date, lastmodified_date) VALUES ";
StringBuilder sb = new StringBuilder();
String currentDate = DateUtils.getLocalDateTimeOfTenant().format(DateUtils.DEFAULT_DATETIME_FORMATTER);
String insertSql = "INSERT INTO m_mandatory_savings_schedule (savings_account_id, duedate, installment, deposit_amount, completed_derived, "
+ CREATED_DATE_DB_FIELD + ", " + CREATED_BY_DB_FIELD + ", " + LAST_MODIFIED_DATE_DB_FIELD + ", " + LAST_MODIFIED_BY_DB_FIELD
+ ") " + "VALUES (?, ?, ?, ?, ?, ?, ?)";
List<Object[]> params = new ArrayList<>();
Long userId = securityContext.authenticatedUser().getId();
int iterations = 0;
for (Map<String, Object> details : scheduleDetails) {
Long count = (Long) details.get("futureInstallemts");
Long count = (Long) details.get("futureInstallments");
if (count == null) {
count = 0L;
}
@@ -66,34 +75,20 @@ public class GenerateRdScheduleTasklet implements Tasklet {
count++;
installmentNumber++;
lastDepositDate = DepositAccountUtils.calculateNextDepositDate(lastDepositDate, recurrence);
if (sb.length() > 0) {
sb.append(", ");
}
sb.append("(");
sb.append(savingsId);
sb.append(",'");
sb.append(formatter.format(lastDepositDate));
sb.append("',");
sb.append(installmentNumber);
sb.append(",");
sb.append(amount);
sb.append(", b'0','");
sb.append(currentDate);
sb.append("','");
sb.append(currentDate);
sb.append("')");
OffsetDateTime auditTime = DateUtils.getAuditOffsetDateTime();
params.add(new Object[] { savingsId, lastDepositDate, installmentNumber, amount, false, auditTime, userId, auditTime,
userId });
iterations++;
if (iterations > 200) {
jdbcTemplate.update(insertSql + sb); // NOSONAR
sb = new StringBuilder();
}
}
if (iterations > 200) {
jdbcTemplate.batchUpdate(insertSql, params);
params.clear();
iterations = 0;
}
}
if (sb.length() > 0) {
jdbcTemplate.update(insertSql + sb); // NOSONAR
if (!params.isEmpty()) {
jdbcTemplate.batchUpdate(insertSql, params);
}
return RepeatStatus.FINISHED;
}
@@ -18,6 +18,8 @@
*/
package org.apache.fineract.portfolio.savings.service;
import static org.apache.fineract.infrastructure.core.domain.AuditableFieldsConstants.CREATED_BY_DB_FIELD;
import java.math.BigDecimal;
import java.sql.ResultSet;
import java.sql.SQLException;
@@ -524,7 +526,7 @@ public class DepositAccountReadPlatformServiceImpl implements DepositAccountRead
sb.append(" select rd.savings_account_id savingsId, rd.mandatory_recommended_deposit_amount as amount,");
sb.append(" mc.recurrence as recurrence ,");
sb.append(" max(ms.duedate) as dueDate , max(ms.installment) as installment,");
sb.append(" count(ms.installment) as futureInstallemts");
sb.append(" count(ms.installment) as futureInstallments");
sb.append(" from m_deposit_account_term_and_preclosure dat ");
sb.append(" inner join m_savings_account sa on sa.id = dat.savings_account_id and sa.status_enum = ?");
sb.append(" inner join m_deposit_account_recurring_detail rd on rd.savings_account_id = dat.savings_account_id ");
@@ -1163,7 +1165,7 @@ public class DepositAccountReadPlatformServiceImpl implements DepositAccountRead
sqlBuilder.append("left join m_account_transfer_transaction totran on totran.to_savings_transaction_id = tr.id ");
sqlBuilder.append("left join m_payment_detail pd on tr.payment_detail_id = pd.id ");
sqlBuilder.append("left join m_payment_type pt on pd.payment_type_id = pt.id ");
sqlBuilder.append("left join m_appuser au on au.id=tr.appuser_id ");
sqlBuilder.append("left join m_appuser au on au.id = tr." + CREATED_BY_DB_FIELD);
this.schemaSql = sqlBuilder.toString();
}
@@ -144,7 +144,7 @@ public class DepositAccountWritePlatformServiceJpaRepositoryImpl implements Depo
@Transactional
@Override
public CommandProcessingResult activateFDAccount(final Long savingsId, final JsonCommand command) {
final AppUser user = this.context.authenticatedUser();
final AppUser user = context.authenticatedUser();
final boolean isSavingsInterestPostingAtCurrentPeriodEnd = this.configurationDomainService
.isSavingsInterestPostingAtCurrentPeriodEnd();
@@ -160,7 +160,7 @@ public class DepositAccountWritePlatformServiceJpaRepositoryImpl implements Depo
final Set<Long> existingReversedTransactionIds = new HashSet<>();
updateExistingTransactionsDetails(account, existingTransactionIds, existingReversedTransactionIds);
final Map<String, Object> changes = account.activate(user, command, DateUtils.getBusinessLocalDate());
final Map<String, Object> changes = account.activate(user, command);
Money activationChargeAmount = getActivationCharge(account);
if (!changes.isEmpty()) {
final Locale locale = command.extractLocale();
@@ -172,13 +172,13 @@ public class DepositAccountWritePlatformServiceJpaRepositoryImpl implements Depo
if (portfolioAccountData == null) {
final PaymentDetail paymentDetail = null;
this.depositAccountDomainService.handleFDDeposit(account, fmt, account.getActivationLocalDate(),
this.depositAccountDomainService.handleFDDeposit(account, fmt, account.getActivationDate(),
amountForDeposit.getAmount(), paymentDetail);
} else {
final SavingsAccount fromSavingsAccount = null;
boolean isRegularTransaction = false;
final boolean isExceptionForBalanceCheck = false;
final AccountTransferDTO accountTransferDTO = new AccountTransferDTO(account.getActivationLocalDate(),
final AccountTransferDTO accountTransferDTO = new AccountTransferDTO(account.getActivationDate(),
amountForDeposit.getAmount(), PortfolioAccountType.SAVINGS, PortfolioAccountType.SAVINGS,
portfolioAccountData.getId(), account.getId(), "Account Transfer", locale, fmt, null, null, null, null, null,
AccountTransferType.ACCOUNT_TRANSFER.getValue(), null, null, ExternalId.empty(), null, account,
@@ -188,9 +188,9 @@ public class DepositAccountWritePlatformServiceJpaRepositoryImpl implements Depo
final boolean isInterestTransfer = false;
final LocalDate postInterestOnDate = null;
if (activationChargeAmount.isGreaterThanZero()) {
payActivationCharge(account, user);
payActivationCharge(account);
}
if (account.isBeforeLastPostingPeriod(account.getActivationLocalDate(), false)) {
if (account.isBeforeLastPostingPeriod(account.getActivationDate(), false)) {
final LocalDate today = DateUtils.getBusinessLocalDate();
account.postInterest(mc, today, isInterestTransfer, isSavingsInterestPostingAtCurrentPeriodEnd,
financialYearBeginningMonth, postInterestOnDate, false);
@@ -237,11 +237,11 @@ public class DepositAccountWritePlatformServiceJpaRepositoryImpl implements Depo
return activationChargeAmount;
}
private void payActivationCharge(final FixedDepositAccount account, AppUser user) {
private void payActivationCharge(final FixedDepositAccount account) {
for (SavingsAccountCharge savingsAccountCharge : account.charges()) {
if (savingsAccountCharge.isSavingsActivation()) {
account.payCharge(savingsAccountCharge, savingsAccountCharge.getAmount(account.getCurrency()),
account.getActivationLocalDate(), user, false, null);
account.payCharge(savingsAccountCharge, savingsAccountCharge.getAmount(account.getCurrency()), account.getActivationDate(),
false, null);
}
}
}
@@ -267,7 +267,7 @@ public class DepositAccountWritePlatformServiceJpaRepositoryImpl implements Depo
final Set<Long> existingReversedTransactionIds = new HashSet<>();
updateExistingTransactionsDetails(account, existingTransactionIds, existingReversedTransactionIds);
final Map<String, Object> changes = account.activate(user, command, DateUtils.getBusinessLocalDate());
final Map<String, Object> changes = account.activate(user, command);
if (!changes.isEmpty()) {
final Locale locale = command.extractLocale();
@@ -277,12 +277,12 @@ public class DepositAccountWritePlatformServiceJpaRepositoryImpl implements Depo
final PortfolioAccountData portfolioAccountData = this.accountAssociationsReadPlatformService
.retriveSavingsLinkedAssociation(savingsId);
if (portfolioAccountData == null) {
this.depositAccountDomainService.handleRDDeposit(account, fmt, account.getActivationLocalDate(),
this.depositAccountDomainService.handleRDDeposit(account, fmt, account.getActivationDate(),
amountForDeposit.getAmount(), null, isRegularTransaction);
} else {
final boolean isExceptionForBalanceCheck = false;
final SavingsAccount fromSavingsAccount = null;
final AccountTransferDTO accountTransferDTO = new AccountTransferDTO(account.getActivationLocalDate(),
final AccountTransferDTO accountTransferDTO = new AccountTransferDTO(account.getActivationDate(),
amountForDeposit.getAmount(), PortfolioAccountType.SAVINGS, PortfolioAccountType.SAVINGS,
portfolioAccountData.getId(), account.getId(), "Account Transfer", locale, fmt, null, null, null, null, null,
AccountTransferType.ACCOUNT_TRANSFER.getValue(), null, null, ExternalId.empty(), null, account,
@@ -314,7 +314,7 @@ public class DepositAccountWritePlatformServiceJpaRepositoryImpl implements Depo
account.updateOverduePayments(overdueUptoDate);
final boolean isInterestTransfer = false;
final LocalDate postInterestOnDate = null;
if (account.isBeforeLastPostingPeriod(account.getActivationLocalDate(), false)) {
if (account.isBeforeLastPostingPeriod(account.getActivationDate(), false)) {
final LocalDate today = DateUtils.getBusinessLocalDate();
account.postInterest(mc, today, isInterestTransfer, isSavingsInterestPostingAtCurrentPeriodEnd, financialYearBeginningMonth,
postInterestOnDate, false, postReversals);
@@ -571,7 +571,7 @@ public class DepositAccountWritePlatformServiceJpaRepositoryImpl implements Depo
checkClientOrGroupActive(account);
final boolean postReversals = false;
if (savingsAccountTransaction.isPostInterestCalculationRequired()
&& account.isBeforeLastPostingPeriod(savingsAccountTransaction.transactionLocalDate(), false)) {
&& account.isBeforeLastPostingPeriod(savingsAccountTransaction.getTransactionDate(), false)) {
account.postInterest(mc, today, isInterestTransfer, isSavingsInterestPostingAtCurrentPeriodEnd, financialYearBeginningMonth,
postInterestOnDate, false, postReversals);
} else {
@@ -620,7 +620,7 @@ public class DepositAccountWritePlatformServiceJpaRepositoryImpl implements Depo
@Override
public CommandProcessingResult adjustRDTransaction(final Long savingsId, final Long transactionId, final JsonCommand command) {
AppUser user = getAppUserIfPresent();
context.authenticatedUser();
final boolean isSavingsInterestPostingAtCurrentPeriodEnd = this.configurationDomainService
.isSavingsInterestPostingAtCurrentPeriodEnd();
@@ -671,11 +671,11 @@ public class DepositAccountWritePlatformServiceJpaRepositoryImpl implements Depo
UUID refNo = UUID.randomUUID();
if (savingsAccountTransaction.isDeposit()) {
final SavingsAccountTransactionDTO transactionDTO = new SavingsAccountTransactionDTO(fmt, transactionDate, transactionAmount,
paymentDetail, savingsAccountTransaction.getCreatedDate(), user, accountType);
paymentDetail, null, accountType);
transaction = account.deposit(transactionDTO, false, relaxingDaysConfigForPivotDate, refNo.toString());
} else {
final SavingsAccountTransactionDTO transactionDTO = new SavingsAccountTransactionDTO(fmt, transactionDate, transactionAmount,
paymentDetail, savingsAccountTransaction.getCreatedDate(), user, accountType);
paymentDetail, null, accountType);
transaction = account.withdraw(transactionDTO, true, false, relaxingDaysConfigForPivotDate, refNo.toString());
}
final Long newtransactionId = saveTransactionToGenerateTransactionId(transaction);
@@ -683,7 +683,7 @@ public class DepositAccountWritePlatformServiceJpaRepositoryImpl implements Depo
final LocalDate postInterestOnDate = null;
final boolean postReversals = false;
if (account.isBeforeLastPostingPeriod(transactionDate, false)
|| account.isBeforeLastPostingPeriod(savingsAccountTransaction.transactionLocalDate(), false)) {
|| account.isBeforeLastPostingPeriod(savingsAccountTransaction.getTransactionDate(), false)) {
account.postInterest(mc, today, isInterestTransfer, isSavingsInterestPostingAtCurrentPeriodEnd, financialYearBeginningMonth,
postInterestOnDate, false, postReversals);
} else {
@@ -757,8 +757,7 @@ public class DepositAccountWritePlatformServiceJpaRepositoryImpl implements Depo
DepositAccountType.FIXED_DEPOSIT);
checkClientOrGroupActive(account);
this.depositAccountDomainService.handleFDAccountClosure(account, paymentDetail, user, command, DateUtils.getBusinessLocalDate(),
changes);
this.depositAccountDomainService.handleFDAccountClosure(account, paymentDetail, user, command, changes);
final String noteText = command.stringValueOfParameterNamed("note");
if (StringUtils.isNotBlank(noteText)) {
@@ -791,8 +790,7 @@ public class DepositAccountWritePlatformServiceJpaRepositoryImpl implements Depo
DepositAccountType.RECURRING_DEPOSIT);
checkClientOrGroupActive(account);
this.depositAccountDomainService.handleRDAccountClosure(account, paymentDetail, user, command, DateUtils.getBusinessLocalDate(),
changes);
this.depositAccountDomainService.handleRDAccountClosure(account, paymentDetail, user, command, changes);
final String noteText = command.stringValueOfParameterNamed("note");
if (StringUtils.isNotBlank(noteText)) {
@@ -825,8 +823,7 @@ public class DepositAccountWritePlatformServiceJpaRepositoryImpl implements Depo
DepositAccountType.FIXED_DEPOSIT);
checkClientOrGroupActive(account);
this.depositAccountDomainService.handleFDAccountPreMatureClosure(account, paymentDetail, user, command,
DateUtils.getBusinessLocalDate(), changes);
this.depositAccountDomainService.handleFDAccountPreMatureClosure(account, paymentDetail, user, command, changes);
final String noteText = command.stringValueOfParameterNamed("note");
if (StringUtils.isNotBlank(noteText)) {
@@ -868,8 +865,7 @@ public class DepositAccountWritePlatformServiceJpaRepositoryImpl implements Depo
}
}
this.depositAccountDomainService.handleRDAccountPreMatureClosure(account, paymentDetail, user, command,
DateUtils.getBusinessLocalDate(), changes);
this.depositAccountDomainService.handleRDAccountPreMatureClosure(account, paymentDetail, user, command, changes);
final String noteText = command.stringValueOfParameterNamed("note");
if (StringUtils.isNotBlank(noteText)) {
@@ -892,7 +888,7 @@ public class DepositAccountWritePlatformServiceJpaRepositoryImpl implements Depo
@Override
public SavingsAccountTransaction initiateSavingsTransfer(final Long accountId, final LocalDate transferDate,
final DepositAccountType depositAccountType) {
AppUser user = getAppUserIfPresent();
context.authenticatedUser();
final boolean isSavingsInterestPostingAtCurrentPeriodEnd = this.configurationDomainService
.isSavingsInterestPostingAtCurrentPeriodEnd();
final Integer financialYearBeginningMonth = this.configurationDomainService.retrieveFinancialYearBeginningMonth();
@@ -904,7 +900,7 @@ public class DepositAccountWritePlatformServiceJpaRepositoryImpl implements Depo
updateExistingTransactionsDetails(savingsAccount, existingTransactionIds, existingReversedTransactionIds);
final SavingsAccountTransaction newTransferTransaction = SavingsAccountTransaction.initiateTransfer(savingsAccount,
savingsAccount.office(), transferDate, user);
savingsAccount.office(), transferDate);
savingsAccount.addTransaction(newTransferTransaction);
savingsAccount.setStatus(SavingsAccountStatusType.TRANSFER_IN_PROGRESS.getValue());
final MathContext mc = MathContext.DECIMAL64;
@@ -924,7 +920,7 @@ public class DepositAccountWritePlatformServiceJpaRepositoryImpl implements Depo
@Override
public SavingsAccountTransaction withdrawSavingsTransfer(final Long accountId, final LocalDate transferDate,
final DepositAccountType depositAccountType) {
AppUser user = getAppUserIfPresent();
context.authenticatedUser();
final boolean isSavingsInterestPostingAtCurrentPeriodEnd = this.configurationDomainService
.isSavingsInterestPostingAtCurrentPeriodEnd();
@@ -937,7 +933,7 @@ public class DepositAccountWritePlatformServiceJpaRepositoryImpl implements Depo
updateExistingTransactionsDetails(savingsAccount, existingTransactionIds, existingReversedTransactionIds);
final SavingsAccountTransaction withdrawtransferTransaction = SavingsAccountTransaction.withdrawTransfer(savingsAccount,
savingsAccount.office(), transferDate, user);
savingsAccount.office(), transferDate);
savingsAccount.addTransaction(withdrawtransferTransaction);
savingsAccount.setStatus(SavingsAccountStatusType.ACTIVE.getValue());
final boolean postReversals = false;
@@ -965,7 +961,7 @@ public class DepositAccountWritePlatformServiceJpaRepositoryImpl implements Depo
@Override
public SavingsAccountTransaction acceptSavingsTransfer(final Long accountId, final LocalDate transferDate,
final Office acceptedInOffice, final Staff fieldOfficer, final DepositAccountType depositAccountType) {
AppUser user = getAppUserIfPresent();
context.authenticatedUser();
final boolean isSavingsInterestPostingAtCurrentPeriodEnd = this.configurationDomainService
.isSavingsInterestPostingAtCurrentPeriodEnd();
@@ -978,7 +974,7 @@ public class DepositAccountWritePlatformServiceJpaRepositoryImpl implements Depo
updateExistingTransactionsDetails(savingsAccount, existingTransactionIds, existingReversedTransactionIds);
final SavingsAccountTransaction acceptTransferTransaction = SavingsAccountTransaction.approveTransfer(savingsAccount,
acceptedInOffice, transferDate, user);
acceptedInOffice, transferDate);
savingsAccount.addTransaction(acceptTransferTransaction);
savingsAccount.setStatus(SavingsAccountStatusType.ACTIVE.getValue());
if (fieldOfficer != null) {
@@ -1024,11 +1020,11 @@ public class DepositAccountWritePlatformServiceJpaRepositoryImpl implements Depo
final SavingsAccountCharge savingsAccountCharge = SavingsAccountCharge.createNewFromJson(savingsAccount, chargeDefinition, command);
if (savingsAccountCharge.getDueLocalDate() != null) {
if (savingsAccountCharge.getDueDate() != null) {
// transaction date should not be on a holiday or non working day
if (!this.configurationDomainService.allowTransactionsOnHolidayEnabled()
&& this.holidayRepository.isHoliday(savingsAccount.officeId(), savingsAccountCharge.getDueLocalDate())) {
baseDataValidator.reset().parameter(dueAsOfDateParamName).value(savingsAccountCharge.getDueLocalDate().format(fmt))
&& this.holidayRepository.isHoliday(savingsAccount.officeId(), savingsAccountCharge.getDueDate())) {
baseDataValidator.reset().parameter(dueAsOfDateParamName).value(savingsAccountCharge.getDueDate().format(fmt))
.failWithCodeNoParameterAddedToErrorCode("charge.due.date.is.on.holiday");
if (!dataValidationErrors.isEmpty()) {
throw new PlatformApiDataValidationException(dataValidationErrors);
@@ -1036,8 +1032,8 @@ public class DepositAccountWritePlatformServiceJpaRepositoryImpl implements Depo
}
if (!this.configurationDomainService.allowTransactionsOnNonWorkingDayEnabled()
&& !this.workingDaysRepository.isWorkingDay(savingsAccountCharge.getDueLocalDate())) {
baseDataValidator.reset().parameter(dueAsOfDateParamName).value(savingsAccountCharge.getDueLocalDate().format(fmt))
&& !this.workingDaysRepository.isWorkingDay(savingsAccountCharge.getDueDate())) {
baseDataValidator.reset().parameter(dueAsOfDateParamName).value(savingsAccountCharge.getDueDate().format(fmt))
.failWithCodeNoParameterAddedToErrorCode("charge.due.date.is.a.nonworking.day");
if (!dataValidationErrors.isEmpty()) {
throw new PlatformApiDataValidationException(dataValidationErrors);
@@ -1080,14 +1076,14 @@ public class DepositAccountWritePlatformServiceJpaRepositoryImpl implements Depo
final Map<String, Object> changes = savingsAccountCharge.update(command);
if (savingsAccountCharge.getDueLocalDate() != null) {
if (savingsAccountCharge.getDueDate() != null) {
final Locale locale = command.extractLocale();
final DateTimeFormatter fmt = DateTimeFormatter.ofPattern(command.dateFormat()).withLocale(locale);
// transaction date should not be on a holiday or non working day
if (!this.configurationDomainService.allowTransactionsOnHolidayEnabled()
&& this.holidayRepository.isHoliday(savingsAccount.officeId(), savingsAccountCharge.getDueLocalDate())) {
baseDataValidator.reset().parameter(dueAsOfDateParamName).value(savingsAccountCharge.getDueLocalDate().format(fmt))
&& this.holidayRepository.isHoliday(savingsAccount.officeId(), savingsAccountCharge.getDueDate())) {
baseDataValidator.reset().parameter(dueAsOfDateParamName).value(savingsAccountCharge.getDueDate().format(fmt))
.failWithCodeNoParameterAddedToErrorCode("charge.due.date.is.on.holiday");
if (!dataValidationErrors.isEmpty()) {
throw new PlatformApiDataValidationException(dataValidationErrors);
@@ -1095,8 +1091,8 @@ public class DepositAccountWritePlatformServiceJpaRepositoryImpl implements Depo
}
if (!this.configurationDomainService.allowTransactionsOnNonWorkingDayEnabled()
&& !this.workingDaysRepository.isWorkingDay(savingsAccountCharge.getDueLocalDate())) {
baseDataValidator.reset().parameter(dueAsOfDateParamName).value(savingsAccountCharge.getDueLocalDate().format(fmt))
&& !this.workingDaysRepository.isWorkingDay(savingsAccountCharge.getDueDate())) {
baseDataValidator.reset().parameter(dueAsOfDateParamName).value(savingsAccountCharge.getDueDate().format(fmt))
.failWithCodeNoParameterAddedToErrorCode("charge.due.date.is.a.nonworking.day");
if (!dataValidationErrors.isEmpty()) {
throw new PlatformApiDataValidationException(dataValidationErrors);
@@ -1120,7 +1116,7 @@ public class DepositAccountWritePlatformServiceJpaRepositoryImpl implements Depo
@Override
public CommandProcessingResult waiveCharge(final Long savingsAccountId, final Long savingsAccountChargeId,
@SuppressWarnings("unused") final DepositAccountType depositAccountType) {
AppUser user = getAppUserIfPresent();
context.authenticatedUser();
final boolean isSavingsInterestPostingAtCurrentPeriodEnd = this.configurationDomainService
.isSavingsInterestPostingAtCurrentPeriodEnd();
@@ -1137,12 +1133,12 @@ public class DepositAccountWritePlatformServiceJpaRepositoryImpl implements Depo
final Set<Long> existingReversedTransactionIds = new HashSet<>();
updateExistingTransactionsDetails(account, existingTransactionIds, existingReversedTransactionIds);
account.waiveCharge(savingsAccountChargeId, user, false);
account.waiveCharge(savingsAccountChargeId, false);
boolean isInterestTransfer = false;
LocalDate postInterestOnDate = null;
final MathContext mc = MathContext.DECIMAL64;
final boolean postReversals = false;
if (account.isBeforeLastPostingPeriod(savingsAccountCharge.getDueLocalDate(), false)) {
if (account.isBeforeLastPostingPeriod(savingsAccountCharge.getDueDate(), false)) {
final LocalDate today = DateUtils.getBusinessLocalDate();
account.postInterest(mc, today, isInterestTransfer, isSavingsInterestPostingAtCurrentPeriodEnd, financialYearBeginningMonth,
postInterestOnDate, false, postReversals);
@@ -1249,13 +1245,13 @@ public class DepositAccountWritePlatformServiceJpaRepositoryImpl implements Depo
@Override
public void applyChargeDue(final Long savingsAccountChargeId, final Long accountId,
@SuppressWarnings("unused") final DepositAccountType depositAccountType) {
// always use current date as transaction date for batch job
final LocalDate transactionDate = DateUtils.getBusinessLocalDate();
final SavingsAccountCharge savingsAccountCharge = this.savingsAccountChargeRepository
.findOneWithNotFoundDetection(savingsAccountChargeId, accountId);
// always use current date as transaction date for batch job
final LocalDate transactionDate = DateUtils.getBusinessLocalDate();
final DateTimeFormatter fmt = DateTimeFormatter.ofPattern("dd MM yyyy");
while (transactionDate.isAfter(savingsAccountCharge.getDueLocalDate())) {
while (DateUtils.isBefore(savingsAccountCharge.getDueDate(), transactionDate)) {
payCharge(savingsAccountCharge, transactionDate, savingsAccountCharge.amoutOutstanding(), fmt);
}
}
@@ -1263,7 +1259,7 @@ public class DepositAccountWritePlatformServiceJpaRepositoryImpl implements Depo
@Transactional
private void payCharge(final SavingsAccountCharge savingsAccountCharge, final LocalDate transactionDate, final BigDecimal amountPaid,
final DateTimeFormatter formatter) {
AppUser user = getAppUserIfPresent();
context.authenticatedUser();
final boolean isSavingsInterestPostingAtCurrentPeriodEnd = this.configurationDomainService
.isSavingsInterestPostingAtCurrentPeriodEnd();
@@ -1275,7 +1271,7 @@ public class DepositAccountWritePlatformServiceJpaRepositoryImpl implements Depo
final Set<Long> existingTransactionIds = new HashSet<>();
final Set<Long> existingReversedTransactionIds = new HashSet<>();
updateExistingTransactionsDetails(account, existingTransactionIds, existingReversedTransactionIds);
account.payCharge(savingsAccountCharge, amountPaid, transactionDate, formatter, user, false, null);
account.payCharge(savingsAccountCharge, amountPaid, transactionDate, formatter, false, null);
boolean isInterestTransfer = false;
LocalDate postInterestOnDate = null;
final MathContext mc = MathContext.DECIMAL64;
@@ -1323,10 +1319,10 @@ public class DepositAccountWritePlatformServiceJpaRepositoryImpl implements Depo
if (fdAccount.isMatured() && (fdAccount.isReinvestOnClosure() || fdAccount.isTransferToSavingsOnClosure())) {
DateTimeFormatter fmt = DateTimeFormatter.ofPattern("yyyy-MM-dd");
Map<String, Object> changes = new HashMap<>();
AppUser user = context.authenticatedUser();
final AppUser user = context.authenticatedUser();
Long toSavingsId = fdAccount.getTransferToSavingsAccountId();
this.depositAccountDomainService.handleFDAccountMaturityClosure(fdAccount, null, user, fdAccount.maturityDate(), fmt,
fdAccount.maturityDate(), fdAccount.getOnAccountClosureId(), toSavingsId, "Apply maturity instructions", changes);
this.depositAccountDomainService.handleFDAccountMaturityClosure(fdAccount, null, user, fmt, fdAccount.maturityDate(),
fdAccount.getOnAccountClosureId(), toSavingsId, "Apply maturity instructions", changes);
if (changes.get("reinvestedDepositId") != null) {
Long reinvestedDepositId = (Long) changes.get("reinvestedDepositId");
@@ -1335,7 +1331,7 @@ public class DepositAccountWritePlatformServiceJpaRepositoryImpl implements Depo
.assembleFrom(reinvestedDepositId, DepositAccountType.FIXED_DEPOSIT);
Money activationChargeAmount = getActivationCharge(reinvestAccount);
if (activationChargeAmount.isGreaterThanZero()) {
payActivationCharge(reinvestAccount, user);
payActivationCharge(reinvestAccount);
amountForDeposit = amountForDeposit.plus(activationChargeAmount);
}
this.depositAccountDomainService.handleFDDeposit(reinvestAccount, fmt, fdAccount.maturityDate(),
@@ -1393,13 +1389,4 @@ public class DepositAccountWritePlatformServiceJpaRepositoryImpl implements Depo
isRegularTransaction);
}
private AppUser getAppUserIfPresent() {
AppUser user = null;
if (this.context != null) {
user = this.context.getAuthenticatedUserIfPresent();
}
return user;
}
}
@@ -47,7 +47,6 @@ import org.apache.fineract.infrastructure.core.exception.GeneralPlatformDomainRu
import org.apache.fineract.infrastructure.core.exception.PlatformApiDataValidationException;
import org.apache.fineract.infrastructure.core.exception.PlatformDataIntegrityException;
import org.apache.fineract.infrastructure.core.serialization.FromJsonHelper;
import org.apache.fineract.infrastructure.core.service.DateUtils;
import org.apache.fineract.infrastructure.event.business.domain.deposit.FixedDepositAccountCreateBusinessEvent;
import org.apache.fineract.infrastructure.event.business.domain.deposit.RecurringDepositAccountCreateBusinessEvent;
import org.apache.fineract.infrastructure.event.business.service.BusinessEventNotifierService;
@@ -384,7 +383,7 @@ public class DepositApplicationProcessWritePlatformServiceJpaRepositoryImpl impl
DepositAccountType.FIXED_DEPOSIT);
checkClientOrGroupActive(account);
account.modifyApplication(command, changes);
account.validateNewApplicationState(DateUtils.getBusinessLocalDate(), DepositAccountType.FIXED_DEPOSIT.resourceName());
account.validateNewApplicationState(DepositAccountType.FIXED_DEPOSIT.resourceName());
if (!changes.isEmpty()) {
updateFDAndRDCommonChanges(changes, command, account);
@@ -474,7 +473,7 @@ public class DepositApplicationProcessWritePlatformServiceJpaRepositoryImpl impl
DepositAccountType.RECURRING_DEPOSIT);
checkClientOrGroupActive(account);
account.modifyApplication(command, changes);
account.validateNewApplicationState(DateUtils.getBusinessLocalDate(), DepositAccountType.RECURRING_DEPOSIT.resourceName());
account.validateNewApplicationState(DepositAccountType.RECURRING_DEPOSIT.resourceName());
if (!changes.isEmpty()) {
updateFDAndRDCommonChanges(changes, command, account);
@@ -638,7 +637,7 @@ public class DepositApplicationProcessWritePlatformServiceJpaRepositoryImpl impl
final SavingsAccount savingsAccount = this.depositAccountAssembler.assembleFrom(savingsId, depositAccountType);
checkClientOrGroupActive(savingsAccount);
final Map<String, Object> changes = savingsAccount.approveApplication(currentUser, command, DateUtils.getBusinessLocalDate());
final Map<String, Object> changes = savingsAccount.approveApplication(currentUser, command);
if (!changes.isEmpty()) {
this.savingAccountRepository.save(savingsAccount);
@@ -708,7 +707,7 @@ public class DepositApplicationProcessWritePlatformServiceJpaRepositoryImpl impl
final SavingsAccount savingsAccount = this.depositAccountAssembler.assembleFrom(savingsId, depositAccountType);
checkClientOrGroupActive(savingsAccount);
final Map<String, Object> changes = savingsAccount.rejectApplication(currentUser, command, DateUtils.getBusinessLocalDate());
final Map<String, Object> changes = savingsAccount.rejectApplication(currentUser, command);
if (!changes.isEmpty()) {
this.savingAccountRepository.save(savingsAccount);
@@ -742,8 +741,7 @@ public class DepositApplicationProcessWritePlatformServiceJpaRepositoryImpl impl
final SavingsAccount savingsAccount = this.depositAccountAssembler.assembleFrom(savingsId, depositAccountType);
checkClientOrGroupActive(savingsAccount);
final Map<String, Object> changes = savingsAccount.applicantWithdrawsFromApplication(currentUser, command,
DateUtils.getBusinessLocalDate());
final Map<String, Object> changes = savingsAccount.applicantWithdrawsFromApplication(currentUser, command);
if (!changes.isEmpty()) {
this.savingAccountRepository.save(savingsAccount);
@@ -94,7 +94,6 @@ public class SavingsAccountChargeReadPlatformServiceImpl implements SavingsAccou
@Override
public SavingsAccountChargeData mapRow(final ResultSet rs, @SuppressWarnings("unused") final int rowNum) throws SQLException {
final Long id = rs.getLong("id");
final Long chargeId = rs.getLong("chargeId");
final Long accountId = rs.getLong("accountId");
@@ -18,6 +18,7 @@
*/
package org.apache.fineract.portfolio.savings.service;
import jakarta.validation.constraints.NotNull;
import java.math.BigDecimal;
import java.math.MathContext;
import java.time.LocalDate;
@@ -30,6 +31,7 @@ import java.util.Map;
import java.util.Set;
import java.util.stream.Collectors;
import org.apache.fineract.infrastructure.core.domain.LocalDateInterval;
import org.apache.fineract.infrastructure.core.service.DateUtils;
import org.apache.fineract.organisation.monetary.domain.MonetaryCurrency;
import org.apache.fineract.organisation.monetary.domain.Money;
import org.apache.fineract.portfolio.savings.DepositAccountType;
@@ -62,7 +64,6 @@ public class SavingsAccountInterestPostingServiceImpl implements SavingsAccountI
public SavingsAccountData postInterest(final MathContext mc, final LocalDate interestPostingUpToDate, final boolean isInterestTransfer,
final boolean isSavingsInterestPostingAtCurrentPeriodEnd, final Integer financialYearBeginningMonth,
final LocalDate postInterestOnDate, final boolean backdatedTxnsAllowedTill, final SavingsAccountData savingsAccountData) {
Money interestPostedToDate = Money.zero(savingsAccountData.getCurrency());
LocalDate startInterestDate = getStartInterestCalculationDate(savingsAccountData);
@@ -84,13 +85,11 @@ public class SavingsAccountInterestPostingServiceImpl implements SavingsAccountI
withholdTransactions.addAll(findWithHoldSavingsTransactionsWithPivotConfig(savingsAccountData));
for (final PostingPeriod interestPostingPeriod : postingPeriods) {
final LocalDate interestPostingTransactionDate = interestPostingPeriod.dateOfPostingTransaction();
final Money interestEarnedToBePostedForPeriod = interestPostingPeriod.getInterestEarned();
if (!interestPostingTransactionDate.isAfter(interestPostingUpToDate)) {
if (!DateUtils.isAfter(interestPostingTransactionDate, interestPostingUpToDate)) {
interestPostedToDate = interestPostedToDate.plus(interestEarnedToBePostedForPeriod);
final SavingsAccountTransactionData postingTransaction = findInterestPostingTransactionFor(interestPostingTransactionDate,
savingsAccountData);
@@ -245,7 +244,7 @@ public class SavingsAccountInterestPostingServiceImpl implements SavingsAccountI
Money periodStartingBalance;
if (savingsAccountData.getStartInterestCalculationDate() != null
&& !savingsAccountData.getStartInterestCalculationDate().equals(savingsAccountData.getActivationLocalDate())) {
final SavingsAccountTransactionData transaction = retrieveLastTransactions(savingsAccountData);
final SavingsAccountTransactionData transaction = retrieveLastTransaction(savingsAccountData);
if (transaction == null) {
periodStartingBalance = Money.zero(savingsAccountData.getCurrency());
@@ -329,13 +328,8 @@ public class SavingsAccountInterestPostingServiceImpl implements SavingsAccountI
}
protected LocalDate getLockedInUntilLocalDate(final SavingsAccountData savingsAccount) {
LocalDate lockedInUntilLocalDate = null;
if (savingsAccount.getLockedInUntilDate() != null) {
lockedInUntilLocalDate = savingsAccount.getActivationLocalDate();
// lockedInUntilLocalDate = LocalDate.ofInstant(this.lockedInUntilDate.toInstant(),
// DateUtils.getDateTimeZoneOfTenant());
}
return lockedInUntilLocalDate;
LocalDate lockedInUntilLocalDate = savingsAccount.getLockedInUntilDate();
return lockedInUntilLocalDate == null ? savingsAccount.getActivationLocalDate() : lockedInUntilLocalDate;
}
private BigDecimal minBalanceForInterestCalculation(final SavingsAccountData savingsAccountData) {
@@ -358,20 +352,17 @@ public class SavingsAccountInterestPostingServiceImpl implements SavingsAccountI
return savingsAccountData.getSavingsAccountTransactionData();
}
private SavingsAccountTransactionData retrieveLastTransactions(final SavingsAccountData savingsAccountData) {
if (savingsAccountData.getSavingsAccountTransactionData() != null
&& savingsAccountData.getSavingsAccountTransactionData().size() == 1) {
return savingsAccountData.getSavingsAccountTransactionData().get(0);
private SavingsAccountTransactionData retrieveLastTransaction(@NotNull SavingsAccountData savingsAccountData) {
List<SavingsAccountTransactionData> transactions = savingsAccountData.getSavingsAccountTransactionData();
if (transactions == null || transactions.isEmpty()) {
return savingsAccountData.getLastSavingsAccountTransaction(); // what is this?
}
final List<SavingsAccountTransactionData> listOfTransactionsSorted = new ArrayList<>();
listOfTransactionsSorted.addAll(savingsAccountData.getSavingsAccountTransactionData());
if (!listOfTransactionsSorted.isEmpty()) {
final SavingsAccountTransactionDataComparator transactionComparator = new SavingsAccountTransactionDataComparator();
Collections.sort(listOfTransactionsSorted, transactionComparator);
} else {
listOfTransactionsSorted.add(savingsAccountData.getLastSavingsAccountTransaction());
if (transactions.size() == 1) {
return transactions.get(0);
}
return listOfTransactionsSorted.get(0);
final List<SavingsAccountTransactionData> listOfTransactionsSorted = new ArrayList<>(transactions);
listOfTransactionsSorted.sort(new SavingsAccountTransactionDataComparator());
return listOfTransactionsSorted.get(0); // this is the first transaction, not the last
}
public LocalDate getStartInterestCalculationDate(final SavingsAccountData savingsAccountData) {
@@ -18,6 +18,9 @@
*/
package org.apache.fineract.portfolio.savings.service;
import static org.apache.fineract.infrastructure.core.domain.AuditableFieldsConstants.CREATED_BY_DB_FIELD;
import static org.apache.fineract.infrastructure.core.domain.AuditableFieldsConstants.CREATED_DATE_DB_FIELD;
import java.math.BigDecimal;
import java.sql.ResultSet;
import java.sql.SQLException;
@@ -278,7 +281,8 @@ public class SavingsAccountReadPlatformServiceImpl implements SavingsAccountRead
}
sql = sql + " and (sa.interest_posted_till_date is null or sa.interest_posted_till_date <= ? ) ";
sql = sql + " order by sa.id, tr.transaction_date, tr.created_date, tr.id";
// #audit backward compatibility
sql = sql + " order by sa.id, tr.transaction_date, tr." + CREATED_DATE_DB_FIELD + ", tr.created_date, tr.id";
List<SavingsAccountData> savingsAccountDataList = this.jdbcTemplate.query(sql, this.savingAccountMapperForInterestPosting, // NOSONAR
new Object[] { maxSavingsId, status, pageSize, yesterday });
@@ -459,19 +463,19 @@ public class SavingsAccountReadPlatformServiceImpl implements SavingsAccountRead
Integer daysToDormancy = null;
Integer daysToEscheat = null;
LocalDate localTenantDate = DateUtils.getBusinessLocalDate();
LocalDate currentDate = DateUtils.getBusinessLocalDate();
if (isDormancyTrackingActive && statusEnum.equals(SavingsAccountStatusType.ACTIVE.getValue())) {
if (subStatusEnum < SavingsAccountSubStatusEnum.ESCHEAT.getValue()) {
daysToEscheat = Math.toIntExact(
ChronoUnit.DAYS.between(localTenantDate, lastActiveTransactionDate.plusDays(numDaysToEscheat)));
daysToEscheat = Math
.toIntExact(ChronoUnit.DAYS.between(currentDate, lastActiveTransactionDate.plusDays(numDaysToEscheat)));
}
if (subStatusEnum < SavingsAccountSubStatusEnum.DORMANT.getValue()) {
daysToDormancy = Math.toIntExact(
ChronoUnit.DAYS.between(localTenantDate, lastActiveTransactionDate.plusDays(numDaysToDormancy)));
ChronoUnit.DAYS.between(currentDate, lastActiveTransactionDate.plusDays(numDaysToDormancy)));
}
if (subStatusEnum < SavingsAccountSubStatusEnum.INACTIVE.getValue()) {
daysToInactive = Math.toIntExact(
ChronoUnit.DAYS.between(localTenantDate, lastActiveTransactionDate.plusDays(numDaysToInactive)));
ChronoUnit.DAYS.between(currentDate, lastActiveTransactionDate.plusDays(numDaysToInactive)));
}
}
final LocalDate approvedOnDate = JdbcSupport.getLocalDate(rs, "approvedOnDate");
@@ -896,19 +900,19 @@ public class SavingsAccountReadPlatformServiceImpl implements SavingsAccountRead
Integer daysToDormancy = null;
Integer daysToEscheat = null;
LocalDate localTenantDate = DateUtils.getBusinessLocalDate();
LocalDate currentDate = DateUtils.getBusinessLocalDate();
if (isDormancyTrackingActive && statusEnum.equals(SavingsAccountStatusType.ACTIVE.getValue())) {
if (subStatusEnum < SavingsAccountSubStatusEnum.ESCHEAT.getValue()) {
daysToEscheat = Math
.toIntExact(ChronoUnit.DAYS.between(localTenantDate, lastActiveTransactionDate.plusDays(numDaysToEscheat)));
.toIntExact(ChronoUnit.DAYS.between(currentDate, lastActiveTransactionDate.plusDays(numDaysToEscheat)));
}
if (subStatusEnum < SavingsAccountSubStatusEnum.DORMANT.getValue()) {
daysToDormancy = Math
.toIntExact(ChronoUnit.DAYS.between(localTenantDate, lastActiveTransactionDate.plusDays(numDaysToDormancy)));
.toIntExact(ChronoUnit.DAYS.between(currentDate, lastActiveTransactionDate.plusDays(numDaysToDormancy)));
}
if (subStatusEnum < SavingsAccountSubStatusEnum.INACTIVE.getValue()) {
daysToInactive = Math
.toIntExact(ChronoUnit.DAYS.between(localTenantDate, lastActiveTransactionDate.plusDays(numDaysToInactive)));
.toIntExact(ChronoUnit.DAYS.between(currentDate, lastActiveTransactionDate.plusDays(numDaysToInactive)));
}
}
@@ -1266,10 +1270,10 @@ public class SavingsAccountReadPlatformServiceImpl implements SavingsAccountRead
@Override
public Collection<SavingsAccountTransactionData> retrieveAllTransactions(final Long savingsId, DepositAccountType depositAccountType) {
// #audit backward compatibility
final String sql = "select " + this.transactionsMapper.schema()
+ " where sa.id = ? and sa.deposit_type_enum = ? order by tr.transaction_date DESC, tr.created_date DESC, tr.id DESC";
+ " where sa.id = ? and sa.deposit_type_enum = ? order by tr.transaction_date DESC," + " tr." + CREATED_DATE_DB_FIELD
+ " DESC, tr.created_date DESC, tr.id DESC";
return this.jdbcTemplate.query(sql, this.transactionsMapper, new Object[] { savingsId, depositAccountType.getValue() }); // NOSONAR
}
@@ -1352,8 +1356,8 @@ public class SavingsAccountReadPlatformServiceImpl implements SavingsAccountRead
+ "left join m_account_transfer_transaction fromtran on fromtran.from_savings_transaction_id = tr.id "
+ "left join m_account_transfer_transaction totran on totran.to_savings_transaction_id = tr.id "
+ "left join m_payment_detail pd on tr.payment_detail_id = pd.id "
+ "left join m_payment_type pt on pd.payment_type_id = pt.id left join m_appuser au on au.id=tr.appuser_id "
+ "left join m_note nt ON nt.savings_account_transaction_id=tr.id ";
+ "left join m_payment_type pt on pd.payment_type_id = pt.id left join m_appuser au on au.id= tr." + CREATED_BY_DB_FIELD
+ " left join m_note nt ON nt.savings_account_transaction_id=tr.id ";
}
public String schema() {
@@ -207,7 +207,7 @@ public class SavingsAccountWritePlatformServiceJpaRepositoryImpl implements Savi
updateExistingTransactionsDetails(account, existingTransactionIds, existingReversedTransactionIds);
final Map<String, Object> changes = account.activate(user, command, DateUtils.getBusinessLocalDate());
final Map<String, Object> changes = account.activate(user, command);
entityDatatableChecksWritePlatformService.runTheCheckForProduct(savingsId, EntityTables.SAVINGS.getName(),
StatusEnum.ACTIVATE.getCode().longValue(), EntityTables.SAVINGS.getForeignKeyColumnNameOnDatatable(), account.productId());
@@ -235,7 +235,7 @@ public class SavingsAccountWritePlatformServiceJpaRepositoryImpl implements Savi
@Override
public void processPostActiveActions(final SavingsAccount account, final DateTimeFormatter fmt, final Set<Long> existingTransactionIds,
final Set<Long> existingReversedTransactionIds) {
AppUser user = getAppUserIfPresent();
getAppUserIfPresent();
final boolean isSavingsInterestPostingAtCurrentPeriodEnd = this.configurationDomainService
.isSavingsInterestPostingAtCurrentPeriodEnd();
@@ -245,13 +245,13 @@ public class SavingsAccountWritePlatformServiceJpaRepositoryImpl implements Savi
boolean isRegularTransaction = false;
if (amountForDeposit.isGreaterThanZero()) {
boolean isAccountTransfer = false;
this.savingsAccountDomainService.handleDeposit(account, fmt, account.getActivationLocalDate(), amountForDeposit.getAmount(),
null, isAccountTransfer, isRegularTransaction, false);
this.savingsAccountDomainService.handleDeposit(account, fmt, account.getActivationDate(), amountForDeposit.getAmount(), null,
isAccountTransfer, isRegularTransaction, false);
updateExistingTransactionsDetails(account, existingTransactionIds, existingReversedTransactionIds);
}
account.processAccountUponActivation(isSavingsInterestPostingAtCurrentPeriodEnd, financialYearBeginningMonth, user);
account.processAccountUponActivation(isSavingsInterestPostingAtCurrentPeriodEnd, financialYearBeginningMonth);
List<DepositAccountOnHoldTransaction> depositAccountOnHoldTransactions = null;
if (account.getOnHoldFunds().compareTo(BigDecimal.ZERO) > 0) {
depositAccountOnHoldTransactions = this.depositAccountOnHoldTransactionRepository
@@ -417,16 +417,16 @@ public class SavingsAccountWritePlatformServiceJpaRepositoryImpl implements Savi
@Transactional
@Override
public CommandProcessingResult applyAnnualFee(final Long savingsAccountChargeId, final Long accountId) {
AppUser user = getAppUserIfPresent();
getAppUserIfPresent();
final SavingsAccountCharge savingsAccountCharge = this.savingsAccountChargeRepository
.findOneWithNotFoundDetection(savingsAccountChargeId, accountId);
final LocalDate todaysDate = DateUtils.getBusinessLocalDate();
final LocalDate currentDate = DateUtils.getBusinessLocalDate();
final DateTimeFormatter fmt = DateTimeFormatter.ofPattern("dd MM yyyy").withZone(DateUtils.getDateTimeZoneOfTenant());
while (todaysDate.isAfter(savingsAccountCharge.getDueLocalDate())) {
this.payCharge(savingsAccountCharge, savingsAccountCharge.getDueLocalDate(), savingsAccountCharge.amount(), fmt, user, false);
while (DateUtils.isBefore(savingsAccountCharge.getDueDate(), currentDate)) {
this.payCharge(savingsAccountCharge, savingsAccountCharge.getDueDate(), savingsAccountCharge.amount(), fmt, false);
}
return new CommandProcessingResultBuilder() //
@@ -681,7 +681,7 @@ public class SavingsAccountWritePlatformServiceJpaRepositoryImpl implements Savi
throw new SavingsAccountTransactionNotFoundException(savingsId, transactionId);
}
this.savingsAccountTransactionDataValidator.validateTransactionWithPivotDate(savingsAccountTransaction.getTransactionLocalDate(),
this.savingsAccountTransactionDataValidator.validateTransactionWithPivotDate(savingsAccountTransaction.getTransactionDate(),
account);
if (!allowAccountTransferModification
@@ -718,7 +718,7 @@ public class SavingsAccountWritePlatformServiceJpaRepositoryImpl implements Savi
boolean postReversals = false;
checkClientOrGroupActive(account);
if (savingsAccountTransaction.isPostInterestCalculationRequired()
&& account.isBeforeLastPostingPeriod(savingsAccountTransaction.transactionLocalDate(), false)) {
&& account.isBeforeLastPostingPeriod(savingsAccountTransaction.getTransactionDate(), false)) {
account.postInterest(mc, today, isInterestTransfer, isSavingsInterestPostingAtCurrentPeriodEnd, financialYearBeginningMonth,
postInterestOnDate, false, postReversals);
} else {
@@ -746,7 +746,7 @@ public class SavingsAccountWritePlatformServiceJpaRepositoryImpl implements Savi
@Override
public CommandProcessingResult adjustSavingsTransaction(final Long savingsId, final Long transactionId, final JsonCommand command) {
AppUser user = getAppUserIfPresent();
context.authenticatedUser();
final boolean isSavingsInterestPostingAtCurrentPeriodEnd = this.configurationDomainService
.isSavingsInterestPostingAtCurrentPeriodEnd();
@@ -808,7 +808,7 @@ public class SavingsAccountWritePlatformServiceJpaRepositoryImpl implements Savi
boolean isInterestTransfer = false;
Integer accountType = null;
final SavingsAccountTransactionDTO transactionDTO = new SavingsAccountTransactionDTO(fmt, transactionDate, transactionAmount,
paymentDetail, savingsAccountTransaction.getCreatedDate(), user, accountType);
paymentDetail, null, accountType);
UUID refNo = UUID.randomUUID();
if (savingsAccountTransaction.isDeposit()) {
transaction = account.deposit(transactionDTO, false, relaxingDaysConfigForPivotDate, refNo.toString());
@@ -819,7 +819,7 @@ public class SavingsAccountWritePlatformServiceJpaRepositoryImpl implements Savi
final LocalDate postInterestOnDate = null;
boolean postReversals = false;
if (account.isBeforeLastPostingPeriod(transactionDate, false)
|| account.isBeforeLastPostingPeriod(savingsAccountTransaction.transactionLocalDate(), false)) {
|| account.isBeforeLastPostingPeriod(savingsAccountTransaction.getTransactionDate(), false)) {
account.postInterest(mc, today, isInterestTransfer, isSavingsInterestPostingAtCurrentPeriodEnd, financialYearBeginningMonth,
postInterestOnDate, false, postReversals);
} else {
@@ -927,7 +927,7 @@ public class SavingsAccountWritePlatformServiceJpaRepositoryImpl implements Savi
List<SavingsAccountTransaction> savingTransactions = account.getTransactions();
for (SavingsAccountTransaction savingTransaction : savingTransactions) {
if (savingTransaction.isInterestPosting() && savingTransaction.isNotReversed()
&& DateUtils.isEqual(closedDate, savingTransaction.getTransactionLocalDate())) {
&& DateUtils.isEqual(closedDate, savingTransaction.getTransactionDate())) {
postInterestOnClosingDate = true;
break;
}
@@ -957,7 +957,7 @@ public class SavingsAccountWritePlatformServiceJpaRepositoryImpl implements Savi
}
final Map<String, Object> accountChanges = account.close(user, command, DateUtils.getBusinessLocalDate());
final Map<String, Object> accountChanges = account.close(user, command);
changes.putAll(accountChanges);
if (!changes.isEmpty()) {
this.savingAccountRepositoryWrapper.save(account);
@@ -985,7 +985,7 @@ public class SavingsAccountWritePlatformServiceJpaRepositoryImpl implements Savi
@Override
public SavingsAccountTransaction initiateSavingsTransfer(final SavingsAccount savingsAccount, final LocalDate transferDate) {
AppUser user = getAppUserIfPresent();
getAppUserIfPresent();
final boolean isSavingsInterestPostingAtCurrentPeriodEnd = this.configurationDomainService
.isSavingsInterestPostingAtCurrentPeriodEnd();
@@ -999,7 +999,7 @@ public class SavingsAccountWritePlatformServiceJpaRepositoryImpl implements Savi
updateExistingTransactionsDetails(savingsAccount, existingTransactionIds, existingReversedTransactionIds);
final SavingsAccountTransaction newTransferTransaction = SavingsAccountTransaction.initiateTransfer(savingsAccount,
savingsAccount.office(), transferDate, user);
savingsAccount.office(), transferDate);
savingsAccount.addTransaction(newTransferTransaction);
savingsAccount.setStatus(SavingsAccountStatusType.TRANSFER_IN_PROGRESS.getValue());
final MathContext mc = MathContext.DECIMAL64;
@@ -1019,7 +1019,7 @@ public class SavingsAccountWritePlatformServiceJpaRepositoryImpl implements Savi
@Override
public SavingsAccountTransaction withdrawSavingsTransfer(final SavingsAccount savingsAccount, final LocalDate transferDate) {
AppUser user = getAppUserIfPresent();
getAppUserIfPresent();
final boolean isSavingsInterestPostingAtCurrentPeriodEnd = this.configurationDomainService
.isSavingsInterestPostingAtCurrentPeriodEnd();
@@ -1030,7 +1030,7 @@ public class SavingsAccountWritePlatformServiceJpaRepositoryImpl implements Savi
updateExistingTransactionsDetails(savingsAccount, existingTransactionIds, existingReversedTransactionIds);
final SavingsAccountTransaction withdrawtransferTransaction = SavingsAccountTransaction.withdrawTransfer(savingsAccount,
savingsAccount.office(), transferDate, user);
savingsAccount.office(), transferDate);
savingsAccount.addTransaction(withdrawtransferTransaction);
savingsAccount.setStatus(SavingsAccountStatusType.ACTIVE.getValue());
final MathContext mc = MathContext.DECIMAL64;
@@ -1058,7 +1058,7 @@ public class SavingsAccountWritePlatformServiceJpaRepositoryImpl implements Savi
@Override
public SavingsAccountTransaction acceptSavingsTransfer(final SavingsAccount savingsAccount, final LocalDate transferDate,
final Office acceptedInOffice, final Staff fieldOfficer) {
AppUser user = getAppUserIfPresent();
getAppUserIfPresent();
final boolean isSavingsInterestPostingAtCurrentPeriodEnd = this.configurationDomainService
.isSavingsInterestPostingAtCurrentPeriodEnd();
@@ -1069,7 +1069,7 @@ public class SavingsAccountWritePlatformServiceJpaRepositoryImpl implements Savi
updateExistingTransactionsDetails(savingsAccount, existingTransactionIds, existingReversedTransactionIds);
final SavingsAccountTransaction acceptTransferTransaction = SavingsAccountTransaction.approveTransfer(savingsAccount,
acceptedInOffice, transferDate, user);
acceptedInOffice, transferDate);
savingsAccount.addTransaction(acceptTransferTransaction);
savingsAccount.setStatus(SavingsAccountStatusType.ACTIVE.getValue());
if (fieldOfficer != null) {
@@ -1126,17 +1126,17 @@ public class SavingsAccountWritePlatformServiceJpaRepositoryImpl implements Savi
savingsAccountCharge.setFreeWithdrawalCount(0);
}
if (savingsAccountCharge.getDueLocalDate() != null) {
if (savingsAccountCharge.getDueDate() != null) {
// transaction date should not be on a holiday or non working day
if (!this.configurationDomainService.allowTransactionsOnHolidayEnabled()
&& this.holidayRepository.isHoliday(savingsAccount.officeId(), savingsAccountCharge.getDueLocalDate())) {
baseDataValidator.reset().parameter(dueAsOfDateParamName).value(savingsAccountCharge.getDueLocalDate().format(fmt))
&& this.holidayRepository.isHoliday(savingsAccount.officeId(), savingsAccountCharge.getDueDate())) {
baseDataValidator.reset().parameter(dueAsOfDateParamName).value(savingsAccountCharge.getDueDate().format(fmt))
.failWithCodeNoParameterAddedToErrorCode("charge.due.date.is.on.holiday");
}
if (!this.configurationDomainService.allowTransactionsOnNonWorkingDayEnabled()
&& !this.workingDaysRepository.isWorkingDay(savingsAccountCharge.getDueLocalDate())) {
baseDataValidator.reset().parameter(dueAsOfDateParamName).value(savingsAccountCharge.getDueLocalDate().format(fmt))
&& !this.workingDaysRepository.isWorkingDay(savingsAccountCharge.getDueDate())) {
baseDataValidator.reset().parameter(dueAsOfDateParamName).value(savingsAccountCharge.getDueDate().format(fmt))
.failWithCodeNoParameterAddedToErrorCode("charge.due.date.is.a.nonworking.day");
}
}
@@ -1178,14 +1178,14 @@ public class SavingsAccountWritePlatformServiceJpaRepositoryImpl implements Savi
final Map<String, Object> changes = savingsAccountCharge.update(command);
if (savingsAccountCharge.getDueLocalDate() != null) {
if (savingsAccountCharge.getDueDate() != null) {
final Locale locale = command.extractLocale();
final DateTimeFormatter fmt = DateTimeFormatter.ofPattern(command.dateFormat()).withLocale(locale);
// transaction date should not be on a holiday or non working day
if (!this.configurationDomainService.allowTransactionsOnHolidayEnabled()
&& this.holidayRepository.isHoliday(savingsAccount.officeId(), savingsAccountCharge.getDueLocalDate())) {
baseDataValidator.reset().parameter(dueAsOfDateParamName).value(savingsAccountCharge.getDueLocalDate().format(fmt))
&& this.holidayRepository.isHoliday(savingsAccount.officeId(), savingsAccountCharge.getDueDate())) {
baseDataValidator.reset().parameter(dueAsOfDateParamName).value(savingsAccountCharge.getDueDate().format(fmt))
.failWithCodeNoParameterAddedToErrorCode("charge.due.date.is.on.holiday");
if (!dataValidationErrors.isEmpty()) {
throw new PlatformApiDataValidationException(dataValidationErrors);
@@ -1193,8 +1193,8 @@ public class SavingsAccountWritePlatformServiceJpaRepositoryImpl implements Savi
}
if (!this.configurationDomainService.allowTransactionsOnNonWorkingDayEnabled()
&& !this.workingDaysRepository.isWorkingDay(savingsAccountCharge.getDueLocalDate())) {
baseDataValidator.reset().parameter(dueAsOfDateParamName).value(savingsAccountCharge.getDueLocalDate().format(fmt))
&& !this.workingDaysRepository.isWorkingDay(savingsAccountCharge.getDueDate())) {
baseDataValidator.reset().parameter(dueAsOfDateParamName).value(savingsAccountCharge.getDueDate().format(fmt))
.failWithCodeNoParameterAddedToErrorCode("charge.due.date.is.a.nonworking.day");
if (!dataValidationErrors.isEmpty()) {
throw new PlatformApiDataValidationException(dataValidationErrors);
@@ -1217,7 +1217,7 @@ public class SavingsAccountWritePlatformServiceJpaRepositoryImpl implements Savi
@Transactional
@Override
public CommandProcessingResult waiveCharge(final Long savingsAccountId, final Long savingsAccountChargeId) {
AppUser user = getAppUserIfPresent();
context.authenticatedUser();
final boolean isSavingsInterestPostingAtCurrentPeriodEnd = this.configurationDomainService
.isSavingsInterestPostingAtCurrentPeriodEnd();
@@ -1242,13 +1242,13 @@ public class SavingsAccountWritePlatformServiceJpaRepositoryImpl implements Savi
updateExistingTransactionsDetails(account, existingTransactionIds, existingReversedTransactionIds);
}
account.waiveCharge(savingsAccountChargeId, user, backdatedTxnsAllowedTill);
account.waiveCharge(savingsAccountChargeId, backdatedTxnsAllowedTill);
boolean isInterestTransfer = false;
LocalDate postInterestOnDate = null;
final MathContext mc = MathContext.DECIMAL64;
boolean postReversals = false;
if (account.isBeforeLastPostingPeriod(savingsAccountCharge.getDueLocalDate(), backdatedTxnsAllowedTill)) {
if (account.isBeforeLastPostingPeriod(savingsAccountCharge.getDueDate(), backdatedTxnsAllowedTill)) {
final LocalDate today = DateUtils.getBusinessLocalDate();
account.postInterest(mc, today, isInterestTransfer, isSavingsInterestPostingAtCurrentPeriodEnd, financialYearBeginningMonth,
postInterestOnDate, backdatedTxnsAllowedTill, postReversals);
@@ -1308,7 +1308,7 @@ public class SavingsAccountWritePlatformServiceJpaRepositoryImpl implements Savi
@Override
public CommandProcessingResult payCharge(final Long savingsAccountId, final Long savingsAccountChargeId, final JsonCommand command) {
AppUser user = getAppUserIfPresent();
context.authenticatedUser();
this.savingsAccountChargeDataValidator.validatePayCharge(command.json());
final Locale locale = command.extractLocale();
@@ -1344,7 +1344,7 @@ public class SavingsAccountWritePlatformServiceJpaRepositoryImpl implements Savi
final boolean backdatedTxnsAllowedTill = false;
SavingsAccountTransaction chargeTransaction = this.payCharge(savingsAccountCharge, transactionDate, amountPaid, fmt, user,
SavingsAccountTransaction chargeTransaction = this.payCharge(savingsAccountCharge, transactionDate, amountPaid, fmt,
backdatedTxnsAllowedTill);
final String noteText = command.stringValueOfParameterNamed("note");
@@ -1367,16 +1367,14 @@ public class SavingsAccountWritePlatformServiceJpaRepositoryImpl implements Savi
@Override
public void applyChargeDue(final Long savingsAccountChargeId, final Long accountId) {
// always use current date as transaction date for batch job
AppUser user = null;
final LocalDate transactionDate = DateUtils.getBusinessLocalDate();
final SavingsAccountCharge savingsAccountCharge = this.savingsAccountChargeRepository
.findOneWithNotFoundDetection(savingsAccountChargeId, accountId);
final DateTimeFormatter fmt = DateTimeFormatter.ofPattern("dd MM yyyy").withZone(DateUtils.getDateTimeZoneOfTenant());
while (savingsAccountCharge.isNotFullyPaid() && DateUtils.isBeforeBusinessDate(savingsAccountCharge.getDueLocalDate())) {
payCharge(savingsAccountCharge, transactionDate, savingsAccountCharge.amoutOutstanding(), fmt, user, false);
while (savingsAccountCharge.isNotFullyPaid() && DateUtils.isBefore(savingsAccountCharge.getDueDate(), transactionDate)) {
payCharge(savingsAccountCharge, transactionDate, savingsAccountCharge.amoutOutstanding(), fmt, false);
}
}
@@ -1390,8 +1388,7 @@ public class SavingsAccountWritePlatformServiceJpaRepositoryImpl implements Savi
@Transactional
private SavingsAccountTransaction payCharge(final SavingsAccountCharge savingsAccountCharge, final LocalDate transactionDate,
final BigDecimal amountPaid, final DateTimeFormatter formatter, final AppUser user, final boolean backdatedTxnsAllowedTill) {
final BigDecimal amountPaid, final DateTimeFormatter formatter, final boolean backdatedTxnsAllowedTill) {
final boolean isSavingsInterestPostingAtCurrentPeriodEnd = this.configurationDomainService
.isSavingsInterestPostingAtCurrentPeriodEnd();
final Integer financialYearBeginningMonth = this.configurationDomainService.retrieveFinancialYearBeginningMonth();
@@ -1409,7 +1406,7 @@ public class SavingsAccountWritePlatformServiceJpaRepositoryImpl implements Savi
account.validateAccountBalanceDoesNotViolateOverdraft(savingsAccountTransaction, amountPaid);
updateExistingTransactionsDetails(account, existingTransactionIds, existingReversedTransactionIds);
SavingsAccountTransaction chargeTransaction = account.payCharge(savingsAccountCharge, amountPaid, transactionDate, formatter, user,
SavingsAccountTransaction chargeTransaction = account.payCharge(savingsAccountCharge, amountPaid, transactionDate, formatter,
backdatedTxnsAllowedTill, null);
boolean isInterestTransfer = false;
LocalDate postInterestOnDate = null;
@@ -1649,7 +1646,7 @@ public class SavingsAccountWritePlatformServiceJpaRepositoryImpl implements Savi
final Set<Long> existingTransactionIds = new HashSet<>();
final Set<Long> existingReversedTransactionIds = new HashSet<>();
updateExistingTransactionsDetails(account, existingTransactionIds, existingReversedTransactionIds);
account.setSubStatusInactive(appuserRepository.fetchSystemUser(), false);
account.setSubStatusInactive(false);
this.savingAccountRepositoryWrapper.saveAndFlush(account);
postJournalEntries(account, existingTransactionIds, existingReversedTransactionIds, false);
}
@@ -1767,16 +1764,15 @@ public class SavingsAccountWritePlatformServiceJpaRepositoryImpl implements Savi
this.savingsAccountTransactionDataValidator.validateHoldAndAssembleForm(command.json(), account, submittedBy,
backdatedTxnsAllowedTill);
SavingsAccountTransaction transaction = this.savingsAccountDomainService.handleHold(account, getAppUserIfPresent(), amount,
transactionDate, lienAllowed);
SavingsAccountTransaction transaction = this.savingsAccountDomainService.handleHold(account, amount, transactionDate, lienAllowed);
account.holdAmount(amount);
transaction.updateRunningBalance(runningBalance);
transaction.setRunningBalance(runningBalance);
final String reasonForBlock = command.stringValueOfParameterNamed(SavingsApiConstants.reasonForBlockParamName);
transaction.updateReason(reasonForBlock);
account.getAccountBalance();
this.savingsAccountTransactionDataValidator.validateTransactionWithPivotDate(transaction.getTransactionLocalDate(), account);
this.savingsAccountTransactionDataValidator.validateTransactionWithPivotDate(transaction.getTransactionDate(), account);
this.savingsAccountTransactionRepository.saveAndFlush(transaction);
@@ -1794,14 +1790,14 @@ public class SavingsAccountWritePlatformServiceJpaRepositoryImpl implements Savi
@Transactional
@Override
public CommandProcessingResult releaseAmount(final Long savingsId, final Long savingsTransactionId) {
final AppUser submittedBy = this.context.authenticatedUser();
context.authenticatedUser();
SavingsAccountTransaction holdTransaction = this.savingsAccountTransactionRepository
.findOneByIdAndSavingsAccountId(savingsTransactionId, savingsId);
holdTransaction.updateReason(null);
final SavingsAccountTransaction transaction = this.savingsAccountTransactionDataValidator
.validateReleaseAmountAndAssembleForm(holdTransaction, submittedBy);
.validateReleaseAmountAndAssembleForm(holdTransaction);
final boolean backdatedTxnsAllowedTill = this.savingAccountAssembler.getPivotConfigStatus();
final SavingsAccount account = this.savingAccountAssembler.assembleFrom(savingsId, backdatedTxnsAllowedTill);
@@ -1814,9 +1810,9 @@ public class SavingsAccountWritePlatformServiceJpaRepositoryImpl implements Savi
runningBalance = runningBalance.minus(savingsOnHold);
runningBalance = runningBalance.plus(transaction.getAmount());
transaction.updateRunningBalance(runningBalance);
transaction.setRunningBalance(runningBalance);
this.savingsAccountTransactionDataValidator.validateTransactionWithPivotDate(transaction.getTransactionLocalDate(), account);
this.savingsAccountTransactionDataValidator.validateTransactionWithPivotDate(transaction.getTransactionDate(), account);
account.releaseOnHoldAmount(transaction.getAmount());
this.savingsAccountTransactionRepository.saveAndFlush(transaction);
@@ -1914,11 +1910,11 @@ public class SavingsAccountWritePlatformServiceJpaRepositoryImpl implements Savi
private void validateTransactionsForTransfer(final SavingsAccount savingsAccount, final LocalDate transferDate) {
for (SavingsAccountTransaction transaction : savingsAccount.getTransactions()) {
if ((DateUtils.isEqual(transferDate, transaction.getTransactionLocalDate())
if ((DateUtils.isEqual(transferDate, transaction.getTransactionDate())
&& DateUtils.isEqual(transferDate, transaction.getSubmittedOnDate()))
|| DateUtils.isBefore(transferDate, transaction.getTransactionLocalDate())) {
|| DateUtils.isBefore(transferDate, transaction.getTransactionDate())) {
throw new GeneralPlatformDomainRuleException(TransferApiConstants.transferClientSavingsException,
TransferApiConstants.transferClientSavingsException, transaction.getCreatedDate(), transferDate);
TransferApiConstants.transferClientSavingsException, transaction.getCreatedDateTime(), transferDate);
}
}
}
@@ -47,7 +47,6 @@ import org.apache.fineract.infrastructure.core.data.CommandProcessingResultBuild
import org.apache.fineract.infrastructure.core.data.DataValidatorBuilder;
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.dataqueries.data.EntityTables;
import org.apache.fineract.infrastructure.dataqueries.data.StatusEnum;
import org.apache.fineract.infrastructure.dataqueries.service.EntityDatatableChecksWritePlatformService;
@@ -320,7 +319,7 @@ public class SavingsApplicationProcessWritePlatformServiceJpaRepositoryImpl impl
final SavingsAccount account = this.savingAccountAssembler.assembleFrom(savingsId, false);
checkClientOrGroupActive(account);
account.modifyApplication(command, changes);
account.validateNewApplicationState(DateUtils.getBusinessLocalDate(), SAVINGS_ACCOUNT_RESOURCE_NAME);
account.validateNewApplicationState(SAVINGS_ACCOUNT_RESOURCE_NAME);
account.validateAccountValuesWithProduct();
if (!changes.isEmpty()) {
@@ -480,7 +479,7 @@ public class SavingsApplicationProcessWritePlatformServiceJpaRepositoryImpl impl
StatusEnum.APPROVE.getCode().longValue(), EntityTables.SAVINGS.getForeignKeyColumnNameOnDatatable(),
savingsAccount.productId());
final Map<String, Object> changes = savingsAccount.approveApplication(currentUser, command, DateUtils.getBusinessLocalDate());
final Map<String, Object> changes = savingsAccount.approveApplication(currentUser, command);
if (!changes.isEmpty()) {
this.savingAccountRepository.save(savingsAccount);
@@ -603,7 +602,7 @@ public class SavingsApplicationProcessWritePlatformServiceJpaRepositoryImpl impl
StatusEnum.REJECTED.getCode().longValue(), EntityTables.SAVINGS.getForeignKeyColumnNameOnDatatable(),
savingsAccount.productId());
final Map<String, Object> changes = savingsAccount.rejectApplication(currentUser, command, DateUtils.getBusinessLocalDate());
final Map<String, Object> changes = savingsAccount.rejectApplication(currentUser, command);
if (!changes.isEmpty()) {
this.savingAccountRepository.save(savingsAccount);
@@ -640,8 +639,7 @@ public class SavingsApplicationProcessWritePlatformServiceJpaRepositoryImpl impl
StatusEnum.WITHDRAWN.getCode().longValue(), EntityTables.SAVINGS.getForeignKeyColumnNameOnDatatable(),
savingsAccount.productId());
final Map<String, Object> changes = savingsAccount.applicantWithdrawsFromApplication(currentUser, command,
DateUtils.getBusinessLocalDate());
final Map<String, Object> changes = savingsAccount.applicantWithdrawsFromApplication(currentUser, command);
if (!changes.isEmpty()) {
this.savingAccountRepository.save(savingsAccount);
@@ -18,12 +18,16 @@
*/
package org.apache.fineract.portfolio.savings.service;
import static org.apache.fineract.infrastructure.core.domain.AuditableFieldsConstants.CREATED_BY_DB_FIELD;
import static org.apache.fineract.infrastructure.core.domain.AuditableFieldsConstants.CREATED_DATE_DB_FIELD;
import static org.apache.fineract.infrastructure.core.domain.AuditableFieldsConstants.LAST_MODIFIED_BY_DB_FIELD;
import static org.apache.fineract.infrastructure.core.domain.AuditableFieldsConstants.LAST_MODIFIED_DATE_DB_FIELD;
import java.math.BigDecimal;
import java.time.LocalDate;
import java.time.LocalDateTime;
import java.time.OffsetDateTime;
import java.util.ArrayList;
import java.util.Collection;
import java.util.Date;
import java.util.HashMap;
import java.util.List;
import java.util.UUID;
@@ -64,7 +68,6 @@ public class SavingsSchedularInterestPoster {
@Transactional(isolation = Isolation.READ_UNCOMMITTED, rollbackFor = Exception.class)
public void postInterest() throws JobExecutionException {
if (!savingAccounts.isEmpty()) {
List<Throwable> errors = new ArrayList<>();
for (SavingsAccountData savingsAccountData : savingAccounts) {
@@ -114,14 +117,14 @@ public class SavingsSchedularInterestPoster {
savingsAccountTransactionData.setId(dataFromFetch.getId());
if (savingsAccountData.getGlAccountIdForSavingsControl() != 0
&& savingsAccountData.getGlAccountIdForInterestOnSavings() != 0) {
OffsetDateTime auditDatetime = DateUtils.getAuditOffsetDateTime();
paramsForGLInsertion.add(new Object[] { savingsAccountData.getGlAccountIdForSavingsControl(),
savingsAccountData.getOfficeId(), null, currencyCode,
SAVINGS_TRANSACTION_IDENTIFIER + savingsAccountTransactionData.getId().toString(),
savingsAccountTransactionData.getId(), null, false, null, false,
savingsAccountTransactionData.getTransactionDate(), JournalEntryType.CREDIT.getValue().longValue(),
savingsAccountTransactionData.getAmount(), null, JournalEntryType.CREDIT.getValue().longValue(),
savingsAccountData.getId(), DateUtils.getOffsetDateTimeOfTenantWithMostPrecision(),
DateUtils.getOffsetDateTimeOfTenantWithMostPrecision(), false, BigDecimal.ZERO, BigDecimal.ZERO, null,
savingsAccountData.getId(), auditDatetime, auditDatetime, false, BigDecimal.ZERO, BigDecimal.ZERO, null,
savingsAccountTransactionData.getTransactionDate(), null, userId, userId,
DateUtils.getBusinessLocalDate() });
@@ -131,8 +134,7 @@ public class SavingsSchedularInterestPoster {
savingsAccountTransactionData.getId(), null, false, null, false,
savingsAccountTransactionData.getTransactionDate(), JournalEntryType.DEBIT.getValue().longValue(),
savingsAccountTransactionData.getAmount(), null, JournalEntryType.DEBIT.getValue().longValue(),
savingsAccountData.getId(), DateUtils.getOffsetDateTimeOfTenantWithMostPrecision(),
DateUtils.getOffsetDateTimeOfTenantWithMostPrecision(), false, BigDecimal.ZERO, BigDecimal.ZERO, null,
savingsAccountData.getId(), auditDatetime, auditDatetime, false, BigDecimal.ZERO, BigDecimal.ZERO, null,
savingsAccountTransactionData.getTransactionDate(), null, userId, userId,
DateUtils.getBusinessLocalDate() });
}
@@ -147,16 +149,12 @@ public class SavingsSchedularInterestPoster {
}
private String batchQueryForJournalEntries() {
StringBuilder query = new StringBuilder(100);
query.append("INSERT INTO acc_gl_journal_entry(account_id,office_id,reversal_id,currency_code,transaction_id,");
query.append("savings_transaction_id,client_transaction_id,reversed,ref_num,manual_entry,entry_date,type_enum,");
query.append("amount,description,entity_type_enum,entity_id,created_on_utc,");
query.append("last_modified_on_utc,is_running_balance_calculated,office_running_balance,organization_running_balance,");
query.append("payment_details_id,transaction_date,share_transaction_id, created_by, last_modified_by, submitted_on_date) ");
query.append("VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)");
return query.toString();
return "INSERT INTO acc_gl_journal_entry(account_id,office_id,reversal_id,currency_code,transaction_id,"
+ "savings_transaction_id,client_transaction_id,reversed,ref_num,manual_entry,entry_date,type_enum,"
+ "amount,description,entity_type_enum,entity_id,created_on_utc,"
+ "last_modified_on_utc,is_running_balance_calculated,office_running_balance,organization_running_balance,"
+ "payment_details_id,transaction_date,share_transaction_id, created_by, last_modified_by, submitted_on_date) "
+ "VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)";
}
private List<SavingsAccountTransactionData> fetchTransactionsFromIds(final List<String> refNo) throws DataAccessException {
@@ -172,7 +170,10 @@ public class SavingsSchedularInterestPoster {
List<Object[]> paramsForSavingsSummary = new ArrayList<>();
List<Object[]> paramsForTransactionUpdate = new ArrayList<>();
List<String> transRefNo = new ArrayList<>();
LocalDate currentDate = DateUtils.getBusinessLocalDate();
Long userId = platformSecurityContext.authenticatedUser().getId();
for (SavingsAccountData savingsAccountData : savingsAccountDataList) {
OffsetDateTime auditTime = DateUtils.getAuditOffsetDateTime();
SavingsAccountSummaryData savingsAccountSummaryData = savingsAccountData.getSummary();
paramsForSavingsSummary.add(new Object[] { savingsAccountSummaryData.getTotalDeposits(),
savingsAccountSummaryData.getTotalWithdrawals(), savingsAccountSummaryData.getTotalInterestEarned(),
@@ -180,39 +181,30 @@ public class SavingsSchedularInterestPoster {
savingsAccountSummaryData.getTotalFeeCharge(), savingsAccountSummaryData.getTotalPenaltyCharge(),
savingsAccountSummaryData.getTotalAnnualFees(), savingsAccountSummaryData.getAccountBalance(),
savingsAccountSummaryData.getTotalOverdraftInterestDerived(), savingsAccountSummaryData.getTotalWithholdTax(),
Date.from(savingsAccountSummaryData.getLastInterestCalculationDate().atStartOfDay(DateUtils.getDateTimeZoneOfTenant())
.toInstant()),
savingsAccountSummaryData.getInterestPostedTillDate() != null
? Date.from(savingsAccountSummaryData.getInterestPostedTillDate()
.atStartOfDay(DateUtils.getDateTimeZoneOfTenant()).toInstant())
: Date.from(savingsAccountSummaryData.getLastInterestCalculationDate()
.atStartOfDay(DateUtils.getDateTimeZoneOfTenant()).toInstant()),
savingsAccountData.getId() });
savingsAccountSummaryData.getLastInterestCalculationDate(),
savingsAccountSummaryData.getInterestPostedTillDate() != null ? savingsAccountSummaryData.getInterestPostedTillDate()
: savingsAccountSummaryData.getLastInterestCalculationDate(),
auditTime, userId, savingsAccountData.getId() });
List<SavingsAccountTransactionData> savingsAccountTransactionDataList = savingsAccountData.getSavingsAccountTransactionData();
LocalDateTime currentDate = DateUtils.getLocalDateTimeOfTenant();
for (SavingsAccountTransactionData savingsAccountTransactionData : savingsAccountTransactionDataList) {
Date balanceEndDate = null;
if (savingsAccountTransactionData.getBalanceEndDate() != null) {
balanceEndDate = Date.from(savingsAccountTransactionData.getBalanceEndDate()
.atStartOfDay(DateUtils.getDateTimeZoneOfTenant()).toInstant());
}
if (savingsAccountTransactionData.getId() == null) {
UUID uuid = UUID.randomUUID();
savingsAccountTransactionData.setRefNo(uuid.toString());
transRefNo.add(uuid.toString());
paramsForTransactionInsertion.add(new Object[] { savingsAccountData.getId(), savingsAccountData.getOfficeId(),
savingsAccountTransactionData.isReversed(), savingsAccountTransactionData.getTransactionType().getId(),
savingsAccountTransactionData.getTransactionDate(), savingsAccountTransactionData.getAmount(), balanceEndDate,
savingsAccountTransactionData.getBalanceNumberOfDays(), savingsAccountTransactionData.getRunningBalance(),
savingsAccountTransactionData.getCumulativeBalance(), currentDate, 1,
savingsAccountTransactionData.isManualTransaction(), savingsAccountTransactionData.getRefNo(),
savingsAccountTransactionData.isReversalTransaction(), savingsAccountTransactionData.getOverdraftAmount(),
DateUtils.getBusinessLocalDate() });
savingsAccountTransactionData.getTransactionDate(), savingsAccountTransactionData.getAmount(),
savingsAccountTransactionData.getBalanceEndDate(), savingsAccountTransactionData.getBalanceNumberOfDays(),
savingsAccountTransactionData.getRunningBalance(), savingsAccountTransactionData.getCumulativeBalance(),
auditTime, userId, auditTime, userId, savingsAccountTransactionData.isManualTransaction(),
savingsAccountTransactionData.getRefNo(), savingsAccountTransactionData.isReversalTransaction(),
savingsAccountTransactionData.getOverdraftAmount(), currentDate });
} else {
paramsForTransactionUpdate.add(new Object[] { savingsAccountTransactionData.isReversed(),
savingsAccountTransactionData.getAmount(), savingsAccountTransactionData.getOverdraftAmount(), balanceEndDate,
savingsAccountTransactionData.getBalanceNumberOfDays(), savingsAccountTransactionData.getRunningBalance(),
savingsAccountTransactionData.getCumulativeBalance(), savingsAccountTransactionData.isReversalTransaction(),
savingsAccountTransactionData.getAmount(), savingsAccountTransactionData.getOverdraftAmount(),
savingsAccountTransactionData.getBalanceEndDate(), savingsAccountTransactionData.getBalanceNumberOfDays(),
savingsAccountTransactionData.getRunningBalance(), savingsAccountTransactionData.getCumulativeBalance(),
savingsAccountTransactionData.isReversalTransaction(), auditTime, userId,
savingsAccountTransactionData.getId() });
}
}
@@ -240,35 +232,23 @@ public class SavingsSchedularInterestPoster {
}
private String batchQueryForTransactionInsertion() {
StringBuilder query = new StringBuilder(100);
query.append("INSERT INTO m_savings_account_transaction (savings_account_id, office_id, is_reversed, ");
query.append("transaction_type_enum, transaction_date, amount, balance_end_date_derived, ");
query.append("balance_number_of_days_derived, running_balance_derived, cumulative_balance_derived, ");
query.append("created_date, appuser_id, is_manual, ref_no, is_reversal, ");
query.append("overdraft_amount_derived, submitted_on_date) VALUES ");
query.append("(?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)");
return query.toString();
return "INSERT INTO m_savings_account_transaction (savings_account_id, office_id, is_reversed, transaction_type_enum, transaction_date, amount, balance_end_date_derived, "
+ "balance_number_of_days_derived, running_balance_derived, cumulative_balance_derived, " + CREATED_DATE_DB_FIELD + ", "
+ CREATED_BY_DB_FIELD + ", " + LAST_MODIFIED_DATE_DB_FIELD + ", " + LAST_MODIFIED_BY_DB_FIELD
+ ", is_manual, ref_no, is_reversal, "
+ "overdraft_amount_derived, submitted_on_date) VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)";
}
private String batchQueryForSavingsSummaryUpdate() {
StringBuilder query = new StringBuilder(100);
query.append("update m_savings_account set total_deposits_derived=?, total_withdrawals_derived=?, ");
query.append("total_interest_earned_derived=?, total_interest_posted_derived=?, total_withdrawal_fees_derived=?, ");
query.append("total_fees_charge_derived=?, total_penalty_charge_derived=?, total_annual_fees_derived=?, ");
query.append("account_balance_derived=?, total_overdraft_interest_derived=?, total_withhold_tax_derived=?, ");
query.append("last_interest_calculation_date=?, interest_posted_till_date=? where id=? ");
return query.toString();
return "update m_savings_account set total_deposits_derived=?, total_withdrawals_derived=?, total_interest_earned_derived=?, total_interest_posted_derived=?, total_withdrawal_fees_derived=?, "
+ "total_fees_charge_derived=?, total_penalty_charge_derived=?, total_annual_fees_derived=?, account_balance_derived=?, total_overdraft_interest_derived=?, total_withhold_tax_derived=?, "
+ "last_interest_calculation_date=?, interest_posted_till_date=?, " + LAST_MODIFIED_DATE_DB_FIELD + " = ?, "
+ LAST_MODIFIED_BY_DB_FIELD + " = ? WHERE id=? ";
}
private String batchQueryForTransactionsUpdate() {
StringBuilder query = new StringBuilder(100);
query.append("UPDATE m_savings_account_transaction ");
query.append("SET is_reversed=?, ");
query.append("amount=?, overdraft_amount_derived=?, balance_end_date_derived=?, ");
query.append("balance_number_of_days_derived=?, running_balance_derived=?, cumulative_balance_derived=?, ");
query.append("is_reversal=? ");
query.append("WHERE id=?");
return query.toString();
return "UPDATE m_savings_account_transaction "
+ "SET is_reversed=?, amount=?, overdraft_amount_derived=?, balance_end_date_derived=?, balance_number_of_days_derived=?, running_balance_derived=?, cumulative_balance_derived=?, is_reversal=?, "
+ LAST_MODIFIED_DATE_DB_FIELD + " = ?, " + LAST_MODIFIED_BY_DB_FIELD + " = ? " + "WHERE id=?";
}
}
@@ -18,6 +18,7 @@
*/
package org.apache.fineract.portfolio.savings.service.search;
import static org.apache.fineract.infrastructure.core.domain.AuditableFieldsConstants.CREATED_DATE_DB_FIELD;
import static org.apache.fineract.portfolio.savings.SavingsApiConstants.SAVINGS_ACCOUNT_RESOURCE_NAME;
import com.google.gson.JsonObject;
@@ -87,7 +88,7 @@ public class SavingsAccountTransactionsSearchServiceImpl implements SavingsAccou
sortPageable = pageable.withSort(Sort.by(orders.stream()
.map(e -> e.withProperty(SearchUtil.validateToJdbcColumnName(e.getProperty(), headersByName, false))).toList()));
} else {
pageable = pageable.withSort(Sort.Direction.DESC, "transaction_date", "created_date", "id");
pageable = pageable.withSort(Sort.Direction.DESC, "transaction_date", CREATED_DATE_DB_FIELD, "id");
sortPageable = pageable;
}
@@ -147,4 +147,5 @@
<include file="parts/0125_transaction_summary_with_asset_owner_report_chargeoff_reason.xml" relativeToChangelogFile="true" />
<include file="parts/0126_add_loan_product_installment_level_delinquency.xml" relativeToChangelogFile="true" />
<include file="parts/0127_client_name_length.xml" relativeToChangelogFile="true" />
<include file="parts/0128_savings_audit.xml" relativeToChangelogFile="true" />
</databaseChangeLog>
@@ -0,0 +1,266 @@
<?xml version="1.0" encoding="UTF-8"?>
<!--
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.
-->
<databaseChangeLog xmlns="http://www.liquibase.org/xml/ns/dbchangelog"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://www.liquibase.org/xml/ns/dbchangelog http://www.liquibase.org/xml/ns/dbchangelog/dbchangelog-4.1.xsd">
<!-- add audit fields -->
<changeSet id="1" author="fineract">
<addColumn tableName="m_savings_account">
<column name="created_by" type="BIGINT" valueComputed="submittedon_userid"/>
<column name="last_modified_by" type="BIGINT"/>
</addColumn>
<renameColumn tableName="m_savings_account_transaction" oldColumnName="appuser_id" newColumnName="created_by" columnDataType="BIGINT"/>
<addColumn tableName="m_savings_account_transaction">
<column name="last_modified_by" type="BIGINT"/>
</addColumn>
<addColumn tableName="m_deposit_account_on_hold_transaction">
<column name="created_by" type="BIGINT"/>
<column name="last_modified_by" type="BIGINT"/>
</addColumn>
<addColumn tableName="m_savings_account_charge">
<column name="created_by" type="BIGINT"/>
<column name="last_modified_by" type="BIGINT"/>
</addColumn>
<renameColumn tableName="m_savings_officer_assignment_history" oldColumnName="createdby_id" newColumnName="created_by" columnDataType="BIGINT"/>
<renameColumn tableName="m_savings_officer_assignment_history" oldColumnName="lastmodifiedby_id" newColumnName="last_modified_by" columnDataType="BIGINT"/>
<renameColumn tableName="m_mandatory_savings_schedule" oldColumnName="createdby_id" newColumnName="created_by" columnDataType="BIGINT"/>
<renameColumn tableName="m_mandatory_savings_schedule" oldColumnName="lastmodifiedby_id" newColumnName="last_modified_by" columnDataType="BIGINT"/>
</changeSet>
<changeSet id="2" author="fineract" context="mysql">
<addColumn tableName="m_savings_account">
<column name="created_on_utc" type="DATETIME(6)"/>
<column name="last_modified_on_utc" type="DATETIME(6)"/>
</addColumn>
<addColumn tableName="m_savings_account_transaction">
<column name="created_on_utc" type="DATETIME(6)"/>
<column name="last_modified_on_utc" type="DATETIME(6)"/>
</addColumn>
<addColumn tableName="m_deposit_account_on_hold_transaction">
<column name="created_on_utc" type="DATETIME(6)"/>
<column name="last_modified_on_utc" type="DATETIME(6)"/>
</addColumn>
<addColumn tableName="m_savings_account_charge">
<column name="created_on_utc" type="DATETIME(6)"/>
<column name="last_modified_on_utc" type="DATETIME(6)"/>
</addColumn>
<addColumn tableName="m_savings_officer_assignment_history">
<column name="created_on_utc" type="DATETIME(6)"/>
<column name="last_modified_on_utc" type="DATETIME(6)"/>
</addColumn>
<addColumn tableName="m_mandatory_savings_schedule">
<column name="created_on_utc" type="DATETIME(6)"/>
<column name="last_modified_on_utc" type="DATETIME(6)"/>
</addColumn>
</changeSet>
<changeSet id="2" author="fineract" context="postgresql">
<addColumn tableName="m_savings_account">
<column name="created_on_utc" type="TIMESTAMP WITH TIME ZONE"/>
<column name="last_modified_on_utc" type="TIMESTAMP WITH TIME ZONE"/>
</addColumn>
<addColumn tableName="m_savings_account_transaction">
<column name="created_on_utc" type="TIMESTAMP WITH TIME ZONE"/>
<column name="last_modified_on_utc" type="TIMESTAMP WITH TIME ZONE"/>
</addColumn>
<addColumn tableName="m_deposit_account_on_hold_transaction">
<column name="created_on_utc" type="TIMESTAMP WITH TIME ZONE"/>
<column name="last_modified_on_utc" type="TIMESTAMP WITH TIME ZONE"/>
</addColumn>
<addColumn tableName="m_savings_account_charge">
<column name="created_on_utc" type="TIMESTAMP WITH TIME ZONE"/>
<column name="last_modified_on_utc" type="TIMESTAMP WITH TIME ZONE"/>
</addColumn>
<addColumn tableName="m_savings_officer_assignment_history">
<column name="created_on_utc" type="TIMESTAMP WITH TIME ZONE"/>
<column name="last_modified_on_utc" type="TIMESTAMP WITH TIME ZONE"/>
</addColumn>
<addColumn tableName="m_mandatory_savings_schedule">
<column name="created_on_utc" type="TIMESTAMP WITH TIME ZONE"/>
<column name="last_modified_on_utc" type="TIMESTAMP WITH TIME ZONE"/>
</addColumn>
</changeSet>
<!-- add audit constraints -->
<changeSet id="3" author="fineract" context="mysql">
<preConditions onFail="MARK_RAN">
<sqlCheck expectedResult="0">select count(*) from m_savings_account</sqlCheck>
</preConditions>
<addNotNullConstraint tableName="m_savings_account" columnName="created_by" columnDataType="BIGINT"/>
<addNotNullConstraint tableName="m_savings_account" columnName="last_modified_by" columnDataType="BIGINT"/>
<addNotNullConstraint tableName="m_savings_account" columnName="created_on_utc" columnDataType="DATETIME(6)"/>
<addNotNullConstraint tableName="m_savings_account" columnName="last_modified_on_utc" columnDataType="DATETIME(6)"/>
</changeSet>
<changeSet id="3" author="fineract" context="postgresql">
<preConditions onFail="MARK_RAN">
<sqlCheck expectedResult="0">select count(*) from m_savings_account</sqlCheck>
</preConditions>
<addNotNullConstraint tableName="m_savings_account" columnName="created_by"/>
<addNotNullConstraint tableName="m_savings_account" columnName="last_modified_by"/>
<addNotNullConstraint tableName="m_savings_account" columnName="created_on_utc"/>
<addNotNullConstraint tableName="m_savings_account" columnName="last_modified_on_utc"/>
</changeSet>
<changeSet id="4" author="fineract" context="mysql">
<preConditions onFail="MARK_RAN">
<sqlCheck expectedResult="0">select count(*) from m_savings_account_transaction</sqlCheck>
</preConditions>
<addNotNullConstraint tableName="m_savings_account_transaction" columnName="created_by" columnDataType="BIGINT"/>
<addNotNullConstraint tableName="m_savings_account_transaction" columnName="last_modified_by" columnDataType="BIGINT"/>
<addNotNullConstraint tableName="m_savings_account_transaction" columnName="created_on_utc" columnDataType="DATETIME(6)"/>
<addNotNullConstraint tableName="m_savings_account_transaction" columnName="last_modified_on_utc" columnDataType="DATETIME(6)"/>
</changeSet>
<changeSet id="4" author="fineract" context="postgresql">
<preConditions onFail="MARK_RAN">
<sqlCheck expectedResult="0">select count(*) from m_savings_account_transaction</sqlCheck>
</preConditions>
<addNotNullConstraint tableName="m_savings_account_transaction" columnName="created_by"/>
<addNotNullConstraint tableName="m_savings_account_transaction" columnName="last_modified_by"/>
<addNotNullConstraint tableName="m_savings_account_transaction" columnName="created_on_utc"/>
<addNotNullConstraint tableName="m_savings_account_transaction" columnName="last_modified_on_utc"/>
</changeSet>
<changeSet id="5" author="fineract" context="mysql">
<preConditions onFail="MARK_RAN">
<sqlCheck expectedResult="0">select count(*) from m_deposit_account_on_hold_transaction</sqlCheck>
</preConditions>
<addNotNullConstraint tableName="m_deposit_account_on_hold_transaction" columnName="created_by" columnDataType="BIGINT"/>
<addNotNullConstraint tableName="m_deposit_account_on_hold_transaction" columnName="last_modified_by" columnDataType="BIGINT"/>
<addNotNullConstraint tableName="m_deposit_account_on_hold_transaction" columnName="created_on_utc" columnDataType="DATETIME(6)"/>
<addNotNullConstraint tableName="m_deposit_account_on_hold_transaction" columnName="last_modified_on_utc" columnDataType="DATETIME(6)"/>
</changeSet>
<changeSet id="5" author="fineract" context="postgresql">
<preConditions onFail="MARK_RAN">
<sqlCheck expectedResult="0">select count(*) from m_deposit_account_on_hold_transaction</sqlCheck>
</preConditions>
<addNotNullConstraint tableName="m_deposit_account_on_hold_transaction" columnName="created_by"/>
<addNotNullConstraint tableName="m_deposit_account_on_hold_transaction" columnName="last_modified_by"/>
<addNotNullConstraint tableName="m_deposit_account_on_hold_transaction" columnName="created_on_utc"/>
<addNotNullConstraint tableName="m_deposit_account_on_hold_transaction" columnName="last_modified_on_utc"/>
</changeSet>
<changeSet id="6" author="fineract" context="mysql">
<preConditions onFail="MARK_RAN">
<sqlCheck expectedResult="0">select count(*) from m_savings_account_charge</sqlCheck>
</preConditions>
<addNotNullConstraint tableName="m_savings_account_charge" columnName="created_by" columnDataType="BIGINT"/>
<addNotNullConstraint tableName="m_savings_account_charge" columnName="last_modified_by" columnDataType="BIGINT"/>
<addNotNullConstraint tableName="m_savings_account_charge" columnName="created_on_utc" columnDataType="DATETIME(6)"/>
<addNotNullConstraint tableName="m_savings_account_charge" columnName="last_modified_on_utc" columnDataType="DATETIME(6)"/>
</changeSet>
<changeSet id="6" author="fineract" context="postgresql">
<preConditions onFail="MARK_RAN">
<sqlCheck expectedResult="0">select count(*) from m_savings_account_charge</sqlCheck>
</preConditions>
<addNotNullConstraint tableName="m_savings_account_charge" columnName="created_by"/>
<addNotNullConstraint tableName="m_savings_account_charge" columnName="last_modified_by"/>
<addNotNullConstraint tableName="m_savings_account_charge" columnName="created_on_utc"/>
<addNotNullConstraint tableName="m_savings_account_charge" columnName="last_modified_on_utc"/>
</changeSet>
<changeSet id="7" author="fineract" context="mysql">
<preConditions onFail="MARK_RAN">
<sqlCheck expectedResult="0">select count(*) from m_savings_officer_assignment_history</sqlCheck>
</preConditions>
<addNotNullConstraint tableName="m_savings_officer_assignment_history" columnName="created_by" columnDataType="BIGINT"/>
<addNotNullConstraint tableName="m_savings_officer_assignment_history" columnName="last_modified_by" columnDataType="BIGINT"/>
<addNotNullConstraint tableName="m_savings_officer_assignment_history" columnName="created_on_utc" columnDataType="DATETIME(6)"/>
<addNotNullConstraint tableName="m_savings_officer_assignment_history" columnName="last_modified_on_utc" columnDataType="DATETIME(6)"/>
</changeSet>
<changeSet id="7" author="fineract" context="postgresql">
<preConditions onFail="MARK_RAN">
<sqlCheck expectedResult="0">select count(*) from m_savings_officer_assignment_history</sqlCheck>
</preConditions>
<addNotNullConstraint tableName="m_savings_officer_assignment_history" columnName="created_by"/>
<addNotNullConstraint tableName="m_savings_officer_assignment_history" columnName="last_modified_by"/>
<addNotNullConstraint tableName="m_savings_officer_assignment_history" columnName="created_on_utc"/>
<addNotNullConstraint tableName="m_savings_officer_assignment_history" columnName="last_modified_on_utc"/>
</changeSet>
<changeSet id="8" author="fineract" context="mysql">
<preConditions onFail="MARK_RAN">
<sqlCheck expectedResult="0">select count(*) from m_mandatory_savings_schedule</sqlCheck>
</preConditions>
<addNotNullConstraint tableName="m_mandatory_savings_schedule" columnName="created_by" columnDataType="BIGINT"/>
<addNotNullConstraint tableName="m_mandatory_savings_schedule" columnName="last_modified_by" columnDataType="BIGINT"/>
<addNotNullConstraint tableName="m_mandatory_savings_schedule" columnName="created_on_utc" columnDataType="DATETIME(6)"/>
<addNotNullConstraint tableName="m_mandatory_savings_schedule" columnName="last_modified_on_utc" columnDataType="DATETIME(6)"/>
</changeSet>
<changeSet id="8" author="fineract" context="postgresql">
<preConditions onFail="MARK_RAN">
<sqlCheck expectedResult="0">select count(*) from m_mandatory_savings_schedule</sqlCheck>
</preConditions>
<addNotNullConstraint tableName="m_mandatory_savings_schedule" columnName="created_by"/>
<addNotNullConstraint tableName="m_mandatory_savings_schedule" columnName="last_modified_by"/>
<addNotNullConstraint tableName="m_mandatory_savings_schedule" columnName="created_on_utc"/>
<addNotNullConstraint tableName="m_mandatory_savings_schedule" columnName="last_modified_on_utc"/>
</changeSet>
<changeSet id="9" author="fineract">
<addForeignKeyConstraint baseColumnNames="created_by" baseTableName="m_savings_account"
constraintName="FK_savings_account_created_by" deferrable="false" initiallyDeferred="false"
onDelete="RESTRICT" onUpdate="RESTRICT" referencedColumnNames="id"
referencedTableName="m_appuser" validate="true"/>
<addForeignKeyConstraint baseColumnNames="last_modified_by" baseTableName="m_savings_account"
constraintName="FK_savings_account_last_modified_by" deferrable="false" initiallyDeferred="false"
onDelete="RESTRICT" onUpdate="RESTRICT" referencedColumnNames="id"
referencedTableName="m_appuser" validate="true"/>
<addForeignKeyConstraint baseColumnNames="created_by" baseTableName="m_savings_account_transaction"
constraintName="FK_savings_account_transaction_created_by" deferrable="false" initiallyDeferred="false"
onDelete="RESTRICT" onUpdate="RESTRICT" referencedColumnNames="id"
referencedTableName="m_appuser" validate="true"/>
<addForeignKeyConstraint baseColumnNames="last_modified_by" baseTableName="m_savings_account_transaction"
constraintName="FK_savings_account_transaction_last_modified_by" deferrable="false" initiallyDeferred="false"
onDelete="RESTRICT" onUpdate="RESTRICT" referencedColumnNames="id"
referencedTableName="m_appuser" validate="true"/>
<addForeignKeyConstraint baseColumnNames="created_by" baseTableName="m_deposit_account_on_hold_transaction"
constraintName="FK_deposit_account_on_hold_transaction_created_by" deferrable="false" initiallyDeferred="false"
onDelete="RESTRICT" onUpdate="RESTRICT" referencedColumnNames="id"
referencedTableName="m_appuser" validate="true"/>
<addForeignKeyConstraint baseColumnNames="last_modified_by" baseTableName="m_deposit_account_on_hold_transaction"
constraintName="FK_deposit_account_on_hold_transaction_last_modified_by" deferrable="false" initiallyDeferred="false"
onDelete="RESTRICT" onUpdate="RESTRICT" referencedColumnNames="id"
referencedTableName="m_appuser" validate="true"/>
<addForeignKeyConstraint baseColumnNames="created_by" baseTableName="m_savings_account_charge"
constraintName="FK_savings_account_charge_created_by" deferrable="false" initiallyDeferred="false"
onDelete="RESTRICT" onUpdate="RESTRICT" referencedColumnNames="id"
referencedTableName="m_appuser" validate="true"/>
<addForeignKeyConstraint baseColumnNames="last_modified_by" baseTableName="m_savings_account_charge"
constraintName="FK_savings_account_charge_last_modified_by" deferrable="false" initiallyDeferred="false"
onDelete="RESTRICT" onUpdate="RESTRICT" referencedColumnNames="id"
referencedTableName="m_appuser" validate="true"/>
<addForeignKeyConstraint baseColumnNames="created_by" baseTableName="m_savings_officer_assignment_history"
constraintName="FK_savings_officer_assignment_history_created_by" deferrable="false" initiallyDeferred="false"
onDelete="RESTRICT" onUpdate="RESTRICT" referencedColumnNames="id"
referencedTableName="m_appuser" validate="true"/>
<addForeignKeyConstraint baseColumnNames="last_modified_by" baseTableName="m_savings_officer_assignment_history"
constraintName="FK_savings_officer_assignment_history_last_modified_by" deferrable="false" initiallyDeferred="false"
onDelete="RESTRICT" onUpdate="RESTRICT" referencedColumnNames="id"
referencedTableName="m_appuser" validate="true"/>
<addForeignKeyConstraint baseColumnNames="created_by" baseTableName="m_mandatory_savings_schedule"
constraintName="FK_mandatory_savings_schedule_created_by" deferrable="false" initiallyDeferred="false"
onDelete="RESTRICT" onUpdate="RESTRICT" referencedColumnNames="id"
referencedTableName="m_appuser" validate="true"/>
<addForeignKeyConstraint baseColumnNames="last_modified_by" baseTableName="m_mandatory_savings_schedule"
constraintName="FK_mandatory_savings_schedule_last_modified_by" deferrable="false" initiallyDeferred="false"
onDelete="RESTRICT" onUpdate="RESTRICT" referencedColumnNames="id"
referencedTableName="m_appuser" validate="true"/>
</changeSet>
<!-- old fields -->
<changeSet id="10" author="fineract">
<dropNotNullConstraint tableName="m_savings_account_transaction" columnName="created_date" columnDataType="DATETIME"/>
<dropNotNullConstraint tableName="m_deposit_account_on_hold_transaction" columnName="created_date" columnDataType="DATETIME"/>
</changeSet>
</databaseChangeLog>
@@ -54,7 +54,7 @@ public class CustomAuditingHandlerTest {
CustomAuditingHandler testInstance = new CustomAuditingHandler(PersistentEntities.of(mappingContext));
AbstractAuditableWithUTCDateTimeCustom targetObject = Mockito.spy(AbstractAuditableWithUTCDateTimeCustom.class);
targetObject = testInstance.markCreated(targetObject);
OffsetDateTime now = OffsetDateTime.now(DateUtils.getDateTimeZoneOfTenant());
OffsetDateTime now = DateUtils.getAuditOffsetDateTime();
assertTrue(targetObject.getCreatedDate().isPresent());
assertEquals(now.getYear(), targetObject.getCreatedDate().get().getYear());
@@ -70,7 +70,7 @@ public class CustomAuditingHandlerTest {
CustomAuditingHandler testInstance = new CustomAuditingHandler(PersistentEntities.of(mappingContext));
AbstractAuditableWithUTCDateTimeCustom targetObject = Mockito.spy(AbstractAuditableWithUTCDateTimeCustom.class);
targetObject = testInstance.markModified(targetObject);
OffsetDateTime now = OffsetDateTime.now(DateUtils.getDateTimeZoneOfTenant());
OffsetDateTime now = DateUtils.getAuditOffsetDateTime();
assertTrue(targetObject.getLastModifiedDate().isPresent());
assertEquals(now.getYear(), targetObject.getLastModifiedDate().get().getYear());
@@ -86,7 +86,7 @@ public class CustomAuditingHandlerTest {
CustomAuditingHandler testInstance = new CustomAuditingHandler(PersistentEntities.of(mappingContext));
AbstractAuditableCustom targetObject = Mockito.spy(AbstractAuditableCustom.class);
targetObject = testInstance.markModified(targetObject);
LocalDateTime now = LocalDateTime.now(ZoneId.systemDefault());
LocalDateTime now = DateUtils.getLocalDateTimeOfSystem();
assertTrue(targetObject.getLastModifiedDate().isPresent());
assertEquals(now.getYear(), targetObject.getLastModifiedDate().get().getYear());
@@ -102,7 +102,7 @@ public class CustomAuditingHandlerTest {
CustomAuditingHandler testInstance = new CustomAuditingHandler(PersistentEntities.of(mappingContext));
AbstractAuditableCustom targetObject = Mockito.spy(AbstractAuditableCustom.class);
targetObject = testInstance.markCreated(targetObject);
LocalDateTime now = LocalDateTime.now(ZoneId.systemDefault());
LocalDateTime now = DateUtils.getLocalDateTimeOfSystem();
assertTrue(targetObject.getCreatedDate().isPresent());
assertEquals(now.getYear(), targetObject.getCreatedDate().get().getYear());
@@ -23,7 +23,6 @@ import static org.junit.jupiter.api.Assertions.assertTrue;
import java.time.LocalDateTime;
import java.time.OffsetDateTime;
import java.time.ZoneId;
import java.time.temporal.TemporalAccessor;
import java.util.Optional;
import org.apache.fineract.infrastructure.core.domain.FineractPlatformTenant;
@@ -36,14 +35,13 @@ public class CustomDateTimeProviderTest {
@BeforeEach
public void init() {
ThreadLocalContextUtil.setTenant(new FineractPlatformTenant(1L, "default", "Default", "Asia/Kolkata", null));
}
@Test
public void instanceDateProvider() {
Optional<TemporalAccessor> dateTimeProvider = CustomDateTimeProvider.INSTANCE.getNow();
LocalDateTime now = LocalDateTime.now(ZoneId.systemDefault());
LocalDateTime now = DateUtils.getLocalDateTimeOfSystem();
assertTrue(dateTimeProvider.isPresent());
assertTrue(dateTimeProvider.get() instanceof LocalDateTime);
@@ -56,8 +54,8 @@ public class CustomDateTimeProviderTest {
@Test
public void tenantDateProvider() {
Optional<TemporalAccessor> dateTimeProvider = CustomDateTimeProvider.TENANT.getNow();
OffsetDateTime now = OffsetDateTime.now(DateUtils.getDateTimeZoneOfTenant());
Optional<TemporalAccessor> dateTimeProvider = CustomDateTimeProvider.UTC.getNow();
OffsetDateTime now = DateUtils.getAuditOffsetDateTime();
assertTrue(dateTimeProvider.isPresent());
assertTrue(dateTimeProvider.get() instanceof OffsetDateTime);
@@ -56,22 +56,22 @@ public class DateUtilsTest {
@Test
public void getLocalDateOfTenant() {
assertEquals(LocalDate.now(ZoneId.of("Asia/Kolkata")), DateUtils.getLocalDateOfTenant());
assertTrue(DateUtils.isEqualTenantDate(LocalDate.now(ZoneId.of("Asia/Kolkata"))));
}
@Test
public void getLocalDateTimeOfTenant() {
assertEquals(LocalDateTime.now(ZoneId.of("Asia/Kolkata")).truncatedTo(ChronoUnit.SECONDS), DateUtils.getLocalDateTimeOfTenant());
assertTrue(DateUtils.isEqualTenantDateTime(LocalDateTime.now(ZoneId.of("Asia/Kolkata")), ChronoUnit.SECONDS));
}
@Test
public void getOffsetDateTimeOfTenant() {
assertEquals(OffsetDateTime.now(ZoneId.of("Asia/Kolkata")).truncatedTo(ChronoUnit.SECONDS), DateUtils.getOffsetDateTimeOfTenant());
assertTrue(DateUtils.isEqualTenantDateTime(OffsetDateTime.now(ZoneId.of("Asia/Kolkata")), ChronoUnit.SECONDS));
}
@Test
public void getLocalDateTimeOfSystem() {
assertEquals(LocalDateTime.now(ZoneId.systemDefault()).truncatedTo(ChronoUnit.SECONDS), DateUtils.getLocalDateTimeOfSystem());
assertTrue(DateUtils.isEqualSystemDateTime(LocalDateTime.now(ZoneId.systemDefault()), ChronoUnit.SECONDS));
}
@Test
@@ -83,6 +83,6 @@ public class DateUtilsTest {
@Test
public void getBusinesLocalDate() {
assertEquals(LocalDate.of(2022, 6, 12), DateUtils.getBusinessLocalDate());
assertTrue(DateUtils.isEqualBusinessDate(LocalDate.of(2022, 6, 12)));
}
}
@@ -3008,7 +3008,7 @@ public class ClientSavingsIntegrationTest {
this.savingsProductHelper = new SavingsProductHelper();
this.scheduleJobHelper = new SchedulerJobHelper(requestSpec);
configurationForBackdatedTransaction();
LocalDate transactionDate = LocalDate.now(Utils.getZoneIdOfTenant()).minusDays(5);
LocalDate transactionDate = Utils.getLocalDateOfTenant().minusDays(5);
final DateTimeFormatter formatter = DateTimeFormatter.ofPattern("dd MMMM yyyy");
String startDate = formatter.format(transactionDate);
String secondTrx = formatter.format(transactionDate.plusDays(1));
@@ -30,7 +30,6 @@ import io.restassured.specification.RequestSpecification;
import io.restassured.specification.ResponseSpecification;
import java.math.BigDecimal;
import java.time.LocalDate;
import java.time.ZoneId;
import java.util.HashMap;
import java.util.List;
import java.util.Locale;
@@ -162,7 +161,7 @@ public class SavingsAccountTransactionsSearchIntegrationTest {
@Test
public void testSavingsTransactionsSearchSubmittedDateFromTo() throws JsonProcessingException {
LocalDate businessDate = LocalDate.now(ZoneId.systemDefault());
LocalDate businessDate = Utils.getLocalDateOfTenant();
final Integer clientID = ClientHelper.createClient(this.requestSpec, this.responseSpec, startDate);
Assertions.assertNotNull(clientID);
final Integer savingsId = createSavingsAccountDailyPosting(clientID, startDate);
@@ -18,13 +18,13 @@
*/
package org.apache.fineract.integrationtests;
import java.text.SimpleDateFormat;
import java.util.Date;
import java.time.format.DateTimeFormatter;
import org.apache.fineract.client.models.PostSavingsAccountsAccountIdRequest;
import org.apache.fineract.client.models.PostSavingsAccountsAccountIdResponse;
import org.apache.fineract.client.models.PostSavingsAccountsRequest;
import org.apache.fineract.client.models.PostSavingsAccountsResponse;
import org.apache.fineract.integrationtests.client.IntegrationTest;
import org.apache.fineract.integrationtests.common.Utils;
import org.junit.jupiter.api.Order;
import org.junit.jupiter.api.Test;
import org.slf4j.Logger;
@@ -42,8 +42,8 @@ public class SavingsAccountsTest extends IntegrationTest {
private static final Logger LOG = LoggerFactory.getLogger(SavingsAccountsTest.class);
private final String dateFormat = "dd MMMM yyyy";
private final String locale = "en";
private final SimpleDateFormat simpleDateFormat = new SimpleDateFormat(dateFormat);
private final String formattedDate = simpleDateFormat.format(new Date());
private final DateTimeFormatter dateFormatter = DateTimeFormatter.ofPattern(dateFormat);
private final String formattedDate = dateFormatter.format(Utils.getLocalDateOfTenant());
private int savingId = 1;
@Test
@@ -27,13 +27,13 @@ import io.restassured.http.ContentType;
import io.restassured.specification.RequestSpecification;
import io.restassured.specification.ResponseSpecification;
import java.time.LocalDate;
import java.time.ZoneId;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.stream.Collectors;
import org.apache.fineract.infrastructure.businessdate.domain.BusinessDateType;
import org.apache.fineract.infrastructure.core.service.DateUtils;
import org.apache.fineract.integrationtests.common.BusinessDateHelper;
import org.apache.fineract.integrationtests.common.ClientHelper;
import org.apache.fineract.integrationtests.common.CommonConstants;
@@ -72,7 +72,7 @@ public class SavingsInterestPostingIntegrationTest {
@Test
public void testSavingsDailyInterestPosting() {
LocalDate today = LocalDate.now(ZoneId.systemDefault());
LocalDate today = Utils.getLocalDateOfTenant();
try {
GlobalConfigurationHelper.updateIsBusinessDateEnabled(requestSpec, responseSpec, true);
BusinessDateHelper.updateBusinessDate(requestSpec, responseSpec, BusinessDateType.BUSINESS_DATE, today);
@@ -100,7 +100,7 @@ public class SavingsInterestPostingIntegrationTest {
List<Integer> submittedOnDateStringList = (List<Integer>) interestPostingTransaction.get("submittedOnDate");
LocalDate submittedOnDate = submittedOnDateStringList.stream().collect(
Collectors.collectingAndThen(Collectors.toList(), list -> LocalDate.of(list.get(0), list.get(1), list.get(2))));
assertTrue(submittedOnDate.compareTo(today) == 0, "Submitted On Date check for Interest Posting transaction");
assertTrue(DateUtils.isEqual(submittedOnDate, today), "Submitted On Date check for Interest Posting transaction");
} finally {
GlobalConfigurationHelper.updateIsBusinessDateEnabled(requestSpec, responseSpec, false);
}
@@ -27,13 +27,13 @@ import io.restassured.http.ContentType;
import io.restassured.specification.RequestSpecification;
import io.restassured.specification.ResponseSpecification;
import java.time.LocalDate;
import java.time.ZoneId;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.stream.Collectors;
import org.apache.fineract.infrastructure.businessdate.domain.BusinessDateType;
import org.apache.fineract.infrastructure.core.service.DateUtils;
import org.apache.fineract.integrationtests.common.BusinessDateHelper;
import org.apache.fineract.integrationtests.common.ClientHelper;
import org.apache.fineract.integrationtests.common.CommonConstants;
@@ -149,7 +149,7 @@ public class SavingsInterestPostingJobIntegrationTest {
@Test
public void testSavingsDailyInterestPostingJob() {
LocalDate today = LocalDate.now(ZoneId.systemDefault());
LocalDate today = Utils.getLocalDateOfTenant();
try {
GlobalConfigurationHelper.updateIsBusinessDateEnabled(requestSpec, responseSpec, true);
BusinessDateHelper.updateBusinessDate(requestSpec, responseSpec, BusinessDateType.BUSINESS_DATE, today);
@@ -179,7 +179,7 @@ public class SavingsInterestPostingJobIntegrationTest {
List<Integer> submittedOnDateStringList = (List<Integer>) interestPostingTransaction.get("submittedOnDate");
LocalDate submittedOnDate = submittedOnDateStringList.stream().collect(
Collectors.collectingAndThen(Collectors.toList(), list -> LocalDate.of(list.get(0), list.get(1), list.get(2))));
assertTrue(submittedOnDate.compareTo(today) == 0, "Submitted On Date check for Interest Posting transaction");
assertTrue(DateUtils.isEqual(submittedOnDate, today), "Submitted On Date check for Interest Posting transaction");
} finally {
GlobalConfigurationHelper.updateIsBusinessDateEnabled(requestSpec, responseSpec, false);
}
@@ -198,9 +198,7 @@ public class SavingsInterestPostingJobIntegrationTest {
this.savingsAccountHelper.withdrawalFromSavingsAccount(savingsId, "10000", startDate, CommonConstants.RESPONSE_RESOURCE_ID);
/***
* Runs Post interest posting job and verify the new account created with Overdraft is posting negative interest
*/
// Runs Post interest posting job and verify the new account created with Overdraft is posting negative interest
this.scheduleJobHelper.executeAndAwaitJob(jobName);
Object transactionObj = this.savingsAccountHelper.getSavingsDetails(savingsId, "transactions");
ArrayList<HashMap<String, Object>> transactions = (ArrayList<HashMap<String, Object>>) transactionObj;
@@ -37,7 +37,6 @@ import java.text.SimpleDateFormat;
import java.time.Duration;
import java.time.LocalDate;
import java.time.LocalTime;
import java.time.ZoneId;
import java.time.ZonedDateTime;
import java.time.format.DateTimeFormatter;
import java.time.format.DateTimeFormatterBuilder;
@@ -179,7 +178,7 @@ public class SchedulerJobsTestResults {
ArrayList<Integer> annualFeeDueDateAsArrayList = (ArrayList<Integer>) annualFeeDetails.get("dueDate");
LocalDate nextDueDateForAnnualFee = LocalDate.of(annualFeeDueDateAsArrayList.get(0), annualFeeDueDateAsArrayList.get(1),
annualFeeDueDateAsArrayList.get(2));
LocalDate todaysDate = LocalDate.now(ZoneId.of("Asia/Kolkata"));
LocalDate todaysDate = Utils.getLocalDateOfTenant();
Truth.assertWithMessage("Verifying that all due Annual Fees have been paid").that(nextDueDateForAnnualFee)
.isGreaterThan(todaysDate);
@@ -42,7 +42,9 @@ import java.text.ParseException;
import java.text.SimpleDateFormat;
import java.time.LocalDate;
import java.time.LocalDateTime;
import java.time.OffsetDateTime;
import java.time.ZoneId;
import java.time.ZoneOffset;
import java.time.format.DateTimeFormatter;
import java.time.format.DateTimeFormatterBuilder;
import java.time.temporal.ChronoField;
@@ -374,6 +376,14 @@ public final class Utils {
return dateFormat.format(dateToBeConvert.getTime());
}
public static OffsetDateTime getAuditOffsetDateTime() {
return OffsetDateTime.now(ZoneOffset.UTC);
}
public static LocalDateTime getLocalDateTimeOfSystem() {
return LocalDateTime.now(ZoneId.systemDefault());
}
public static TimeZone getTimeZoneOfTenant() {
return TimeZone.getTimeZone(TENANT_TIME_ZONE);
}
@@ -386,6 +396,10 @@ public final class Utils {
return LocalDate.now(getZoneIdOfTenant());
}
public static LocalDateTime getLocalDateTimeOfTenant() {
return LocalDateTime.now(getZoneIdOfTenant());
}
public static Date convertJsonElementAsDate(JsonElement jsonElement) {
if (jsonElement.isJsonArray()) {
JsonArray jsonArray = jsonElement.getAsJsonArray();
@@ -25,7 +25,6 @@ import com.google.gson.Gson;
import io.restassured.path.json.JsonPath;
import io.restassured.specification.RequestSpecification;
import io.restassured.specification.ResponseSpecification;
import java.time.LocalDateTime;
import java.time.format.DateTimeFormatter;
import java.util.HashMap;
import java.util.List;
@@ -108,7 +107,7 @@ public class CampaignsHelper {
map.put("triggerType", triggerType);
if (2 == triggerType) {
map.put("recurrenceStartDate",
LocalDateTime.now(Utils.getZoneIdOfTenant()).plusMinutes(1).format(DateTimeFormatter.ofPattern(DATE_TIME_FORMAT)));
Utils.getLocalDateTimeOfTenant().plusMinutes(1).format(DateTimeFormatter.ofPattern(DATE_TIME_FORMAT)));
map.put("frequency", 1);
map.put("interval", "1");
}
@@ -136,7 +135,7 @@ public class CampaignsHelper {
map.put("triggerType", triggerType);
if (2 == triggerType) {
map.put("recurrenceStartDate",
LocalDateTime.now(Utils.getZoneIdOfTenant()).plusMinutes(1).format(DateTimeFormatter.ofPattern(DATE_TIME_FORMAT)));
Utils.getLocalDateTimeOfTenant().plusMinutes(1).format(DateTimeFormatter.ofPattern(DATE_TIME_FORMAT)));
}
map.put("campaignName", Utils.randomStringGenerator("Campaign_Name_", 5));
map.put("campaignType", 1);