minor change on client
Fineract Build & Cucumber tests (without E2E tests) / verify (progressive-loan, build-progressive-loan) (push) Canceled after 0s
Fineract Cargo & Unit- & Integration tests - MariaDB / test (test-core-2) (push) Canceled after 0s
Fineract Cargo & Unit- & Integration tests - MariaDB / test (test-core-3) (push) Canceled after 0s
Fineract Cargo & Unit- & Integration tests - MariaDB / test (test-core-4) (push) Canceled after 0s
Fineract Docker Builds / build (false, docker-compose-postgresql.yml, postgresql) (push) Canceled after 0s
Fineract Build & Cucumber tests (without E2E tests) / verify (main, build-core) (push) Canceled after 0s
Fineract Build & Cucumber tests (without E2E tests) / verify (main, cucumber) (push) Canceled after 0s
Fineract Docker Builds / build (true, docker-compose.yml, mariadb) (push) Canceled after 0s
Fineract Documentation build / build (push) Canceled after 0s
Fineract E2E Tests / E2E Tests (Shard 1 of 10) (push) Canceled after 0s
Fineract E2E Tests / E2E Tests (Shard 10 of 10) (push) Canceled after 0s
Fineract E2E Tests / E2E Tests (Shard 2 of 10) (push) Canceled after 0s
Fineract E2E Tests / E2E Tests (Shard 3 of 10) (push) Canceled after 0s
Fineract E2E Tests / E2E Tests (Shard 4 of 10) (push) Canceled after 0s
Fineract E2E Tests / E2E Tests (Shard 5 of 10) (push) Canceled after 0s
Fineract E2E Tests / E2E Tests (Shard 6 of 10) (push) Canceled after 0s
Fineract E2E Tests / E2E Tests (Shard 7 of 10) (push) Canceled after 0s
Fineract E2E Tests / E2E Tests (Shard 8 of 10) (push) Canceled after 0s
Fineract E2E Tests / E2E Tests (Shard 9 of 10) (push) Canceled after 0s
Fineract Cargo & Unit- & Integration tests - MariaDB / test (test-core-1) (push) Canceled after 0s
Fineract Cargo & Unit- & Integration tests - MariaDB / test (test-core-5) (push) Canceled after 0s
Fineract Cargo & Unit- & Integration tests - MySQL / test (test-core-1) (push) Canceled after 0s
Fineract Cargo & Unit- & Integration tests - MySQL / test (test-core-2) (push) Canceled after 0s
Fineract Cargo & Unit- & Integration tests - MySQL / test (test-core-3) (push) Canceled after 0s
Fineract Cargo & Unit- & Integration tests - MySQL / test (test-core-4) (push) Canceled after 0s
Fineract Cargo & Unit- & Integration tests - MySQL / test (test-core-5) (push) Canceled after 0s
Fineract Cargo & Unit- & Integration tests - PostgreSQL / test (test-core-1) (push) Canceled after 0s
Fineract Cargo & Unit- & Integration tests - PostgreSQL / test (test-core-2) (push) Canceled after 0s
Fineract Cargo & Unit- & Integration tests - PostgreSQL / test (test-core-3) (push) Canceled after 0s
Fineract Cargo & Unit- & Integration tests - PostgreSQL / test (test-core-4) (push) Canceled after 0s
Fineract Cargo & Unit- & Integration tests - PostgreSQL / test (test-core-5) (push) Canceled after 0s
Fineract Liquibase Only mode - PostgreSQL / test (push) Canceled after 0s
Fineract Messaging Smoke Tests / Smoke Test with ActiveMQ (push) Canceled after 0s
Fineract Messaging Smoke Tests / Smoke Test with Kafka (push) Canceled after 0s

This commit is contained in:
2026-07-28 10:43:06 +05:30
parent bc30241950
commit 026d902199
164 changed files with 813 additions and 607 deletions
@@ -446,6 +446,7 @@ public final class FixedDepositAccountData extends DepositAccountData {
final Collection<SavingsAccountTransactionData> transactions, final Collection<SavingsAccountChargeData> charges,
final PortfolioAccountData linkedAccount, PortfolioAccountData transferToSavingsAccount) {
final boolean templateProvided = template != null;
if (template == null) {
template = account;
}
@@ -470,7 +471,7 @@ public final class FixedDepositAccountData extends DepositAccountData {
account.transferToSavingsId, transferToSavingsAccount);
result.copyCbsFieldsFrom(account);
// Merge accountTypeOptions and customerSegmentOptions from template (not in account data)
if (template != null && template != account) {
if (templateProvided) {
if (template.getAccountTypeOptions() != null) result.setAccountTypeOptions(template.getAccountTypeOptions());
if (template.getCustomerSegmentOptions() != null) result.setCustomerSegmentOptions(template.getCustomerSegmentOptions());
}
@@ -76,7 +76,6 @@ import org.apache.fineract.portfolio.savings.DepositAccountType;
import org.apache.fineract.portfolio.savings.SavingsApiConstants;
import org.apache.fineract.portfolio.savings.SavingsCompoundingInterestPeriodType;
import org.apache.fineract.portfolio.savings.SavingsInterestCalculationDaysInYearType;
import org.apache.fineract.portfolio.savings.SavingsInterestCalculationType;
import org.apache.fineract.portfolio.savings.SavingsPostingInterestPeriodType;
import org.apache.fineract.portfolio.savings.domain.SavingsProduct;
import org.springframework.stereotype.Component;
@@ -22,13 +22,13 @@ import jakarta.persistence.Column;
import jakarta.persistence.Embedded;
import jakarta.persistence.Entity;
import jakarta.persistence.JoinColumn;
import jakarta.persistence.Lob;
import jakarta.persistence.ManyToOne;
import jakarta.persistence.Table;
import java.time.LocalDateTime;
import lombok.Getter;
import lombok.Setter;
import org.apache.fineract.infrastructure.core.domain.AbstractPersistableCustom;
import org.apache.fineract.infrastructure.core.service.DateUtils;
import org.apache.fineract.useradministration.domain.AppUser;
/**
@@ -132,7 +132,7 @@ public class ProductPendingEdit extends AbstractPersistableCustom<Long> {
this.productType = productType;
this.productId = productId;
this.maker = maker;
this.createdOn = LocalDateTime.now();
this.createdOn = DateUtils.getLocalDateTimeOfTenant();
this.status = STATUS_PENDING;
this.pendingLockKey = lockKeyFor(productType, productId);
}
@@ -190,14 +190,14 @@ public class ProductPendingEdit extends AbstractPersistableCustom<Long> {
public void markApproved(final AppUser checker) {
this.status = STATUS_APPROVED;
this.checker = checker;
this.checkedOn = LocalDateTime.now();
this.checkedOn = DateUtils.getLocalDateTimeOfTenant();
this.pendingLockKey = null;
}
public void markRejected(final AppUser checker, final String reason) {
this.status = STATUS_REJECTED;
this.checker = checker;
this.checkedOn = LocalDateTime.now();
this.checkedOn = DateUtils.getLocalDateTimeOfTenant();
this.rejectReason = reason;
this.pendingLockKey = null;
}
@@ -21,6 +21,7 @@ import java.time.LocalDate;
import lombok.Getter;
import lombok.NoArgsConstructor;
import lombok.Setter;
import org.apache.fineract.infrastructure.core.service.DateUtils;
@Entity
@Table(name = "m_rd_interest_rate_effective")
@@ -66,7 +67,7 @@ public class RdInterestRateEffective {
e.isActive = true;
e.remarks = remarks;
e.createdById = createdById;
e.createdDate = LocalDate.now();
e.createdDate = DateUtils.getLocalDateOfTenant();
return e;
}
}
@@ -21,6 +21,7 @@ import java.math.BigDecimal;
import java.time.LocalDate;
import lombok.Getter;
import lombok.NoArgsConstructor;
import org.apache.fineract.infrastructure.core.service.DateUtils;
@Entity
@Table(name = "m_rd_interest_rate_slab_history")
@@ -66,7 +67,7 @@ public class RdInterestRateSlabHistory {
s.fromPeriod = fromPeriod;
s.toPeriod = toPeriod;
s.annualInterestRate = annualInterestRate;
s.createdDate = LocalDate.now();
s.createdDate = DateUtils.getLocalDateOfTenant();
return s;
}
}
@@ -26,6 +26,7 @@ import jakarta.persistence.OneToOne;
import jakarta.persistence.Table;
import java.time.LocalDateTime;
import org.apache.fineract.infrastructure.core.domain.AbstractPersistableCustom;
import org.apache.fineract.infrastructure.core.service.DateUtils;
@Entity
@Table(name = "m_savings_account_facility_config")
@@ -87,12 +88,12 @@ public class SavingsAccountFacilityConfig extends AbstractPersistableCustom<Long
private LocalDateTime createdDate;
protected SavingsAccountFacilityConfig() {
this.createdDate = LocalDateTime.now();
}
public SavingsAccountFacilityConfig(SavingsAccount savingsAccount) {
this();
this.savingsAccount = savingsAccount;
this.createdDate = DateUtils.getLocalDateTimeOfTenant();
}
public SavingsAccount getSavingsAccount() { return savingsAccount; }
@@ -29,6 +29,7 @@ import java.time.LocalDateTime;
import lombok.Getter;
import lombok.Setter;
import org.apache.fineract.infrastructure.core.domain.AbstractPersistableCustom;
import org.apache.fineract.infrastructure.core.service.DateUtils;
import org.apache.fineract.useradministration.domain.AppUser;
/**
@@ -183,7 +184,7 @@ public class SavingsAccountPendingEdit extends AbstractPersistableCustom<Long> {
public SavingsAccountPendingEdit(final SavingsAccount savingsAccount, final AppUser maker) {
this.savingsAccount = savingsAccount;
this.maker = maker;
this.createdOn = LocalDateTime.now();
this.createdOn = DateUtils.getLocalDateTimeOfTenant();
this.status = STATUS_PENDING;
this.pendingLockKey = lockKeyFor(savingsAccount.getId());
}
@@ -199,14 +200,14 @@ public class SavingsAccountPendingEdit extends AbstractPersistableCustom<Long> {
public void markApproved(final AppUser checker) {
this.status = STATUS_APPROVED;
this.checker = checker;
this.checkedOn = LocalDateTime.now();
this.checkedOn = DateUtils.getLocalDateTimeOfTenant();
this.pendingLockKey = null;
}
public void markRejected(final AppUser checker, final String reason) {
this.status = STATUS_REJECTED;
this.checker = checker;
this.checkedOn = LocalDateTime.now();
this.checkedOn = DateUtils.getLocalDateTimeOfTenant();
this.rejectReason = reason;
this.pendingLockKey = null;
}
@@ -377,6 +377,7 @@ public class SavingsProduct extends AbstractPersistableCustom<Long> {
this.description = null;
}
@SuppressWarnings("ChainingConstructorIgnoresParameter")
protected SavingsProduct(final String name, final String shortName, final String description, final MonetaryCurrency currency,
final BigDecimal interestRate, final SavingsCompoundingInterestPeriodType interestCompoundingPeriodType,
final SavingsPostingInterestPeriodType interestPostingPeriodType, final SavingsInterestCalculationType interestCalculationType,
@@ -26,6 +26,7 @@ import jakarta.persistence.OneToOne;
import jakarta.persistence.Table;
import java.time.LocalDateTime;
import org.apache.fineract.infrastructure.core.domain.AbstractPersistableCustom;
import org.apache.fineract.infrastructure.core.service.DateUtils;
@Entity
@Table(name = "m_savings_product_deposit_limit_kyc")
@@ -57,12 +58,12 @@ public class SavingsProductDepositLimitKyc extends AbstractPersistableCustom<Lon
private LocalDateTime createdDate;
protected SavingsProductDepositLimitKyc() {
this.createdDate = LocalDateTime.now();
}
public SavingsProductDepositLimitKyc(SavingsProduct savingsProduct) {
this();
this.savingsProduct = savingsProduct;
this.createdDate = DateUtils.getLocalDateTimeOfTenant();
}
// Getters and setters
@@ -26,6 +26,7 @@ import jakarta.persistence.OneToOne;
import jakarta.persistence.Table;
import java.time.LocalDateTime;
import org.apache.fineract.infrastructure.core.domain.AbstractPersistableCustom;
import org.apache.fineract.infrastructure.core.service.DateUtils;
@Entity
@Table(name = "m_savings_product_facility_config")
@@ -87,12 +88,12 @@ public class SavingsProductFacilityConfig extends AbstractPersistableCustom<Long
private LocalDateTime createdDate;
protected SavingsProductFacilityConfig() {
this.createdDate = LocalDateTime.now();
}
public SavingsProductFacilityConfig(SavingsProduct savingsProduct) {
this();
this.savingsProduct = savingsProduct;
this.createdDate = DateUtils.getLocalDateTimeOfTenant();
}
public SavingsProduct getSavingsProduct() { return savingsProduct; }
@@ -26,6 +26,7 @@ import jakarta.persistence.ManyToOne;
import jakarta.persistence.Table;
import java.time.LocalDateTime;
import org.apache.fineract.infrastructure.core.domain.AbstractPersistableCustom;
import org.apache.fineract.infrastructure.core.service.DateUtils;
@Entity
@Table(name = "m_savings_product_facility_limits")
@@ -51,7 +52,6 @@ public class SavingsProductFacilityLimit extends AbstractPersistableCustom<Long>
private LocalDateTime createdDate;
protected SavingsProductFacilityLimit() {
this.createdDate = LocalDateTime.now();
}
public SavingsProductFacilityLimit(SavingsProduct savingsProduct, String limitType,
@@ -62,6 +62,7 @@ public class SavingsProductFacilityLimit extends AbstractPersistableCustom<Long>
this.generalLimit = generalLimit;
this.minorAccountLimit = minorAccountLimit;
this.smallSavingLimit = smallSavingLimit;
this.createdDate = DateUtils.getLocalDateTimeOfTenant();
}
public static SavingsProductFacilityLimit create(SavingsProduct savingsProduct, String limitType,
@@ -25,6 +25,7 @@ import java.util.ArrayList;
import java.util.List;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.apache.fineract.infrastructure.core.service.DateUtils;
import org.apache.fineract.organisation.monetary.domain.Money;
import org.apache.fineract.portfolio.charge.domain.Charge;
import org.apache.fineract.portfolio.savings.domain.FacilityChargeMapping;
@@ -202,34 +203,6 @@ public class FacilityChargeAutoApplyService {
return transactions;
}
private void autoCollectSavingsActivationCharges(final SavingsAccount account,
final List<SavingsAccountCharge> charges) {
final LocalDate activationDate = account.getActivationDate();
final List<SavingsAccountTransaction> transactions = new ArrayList<>();
for (final SavingsAccountCharge charge : charges) {
if (!charge.isSavingsActivation()) continue;
final BigDecimal amount = charge.getAmountOutstanding(account.getCurrency()).getAmount();
if (amount == null || amount.compareTo(BigDecimal.ZERO) <= 0) continue;
try {
final Money amountMoney = Money.of(account.getCurrency(), amount);
final SavingsAccountTransaction txn = account.payCharge(charge, amountMoney, activationDate, false, null);
if (txn != null) transactions.add(txn);
log.info("Auto-collected facility charge '{}' ₹{} from account id={}",
charge.getCharge().getName(), amount, account.getId());
} catch (Exception e) {
log.warn("Could not auto-collect facility charge '{}' from account id={}: {}",
charge.getCharge().getName(), account.getId(), e.getMessage());
}
}
if (!transactions.isEmpty()) {
savingsAccountTransactionRepository.saveAll(transactions);
account.recalculateBalancesAfterFacilityCharges(activationDate);
}
}
private void applyIfEnabled(final SavingsAccount account, final boolean facilityEnabled,
final String facilityType, final List<SavingsAccountCharge> collector) {
@@ -267,16 +240,16 @@ public class FacilityChargeAutoApplyService {
if (charge.getFeeOnMonthDay() != null) return charge.getFeeOnMonthDay();
if (charge.isMonthlyFee() || charge.isAnnualFee()) {
// Default: 1st of the month
return MonthDay.of(LocalDate.now().plusMonths(1).getMonth(), 1);
return MonthDay.of(DateUtils.getBusinessLocalDate().plusMonths(1).getMonth(), 1);
}
return null;
}
private LocalDate resolveDueDate(final Charge charge) {
if (charge.isMonthlyFee()) {
return LocalDate.now().plusMonths(1).withDayOfMonth(1);
return DateUtils.getBusinessLocalDate().plusMonths(1).withDayOfMonth(1);
} else if (charge.isAnnualFee()) {
return LocalDate.now().plusYears(1);
return DateUtils.getBusinessLocalDate().plusYears(1);
}
return null;
}
@@ -26,7 +26,6 @@ import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.springframework.jdbc.core.JdbcTemplate;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Propagation;
import org.springframework.transaction.annotation.Transactional;
/**