diff --git a/fineract-accounting/src/main/java/org/apache/fineract/accounting/journalentry/JournalEntryMapper.java b/fineract-accounting/src/main/java/org/apache/fineract/accounting/journalentry/JournalEntryMapper.java index 7abb384c7..89cd5e681 100644 --- a/fineract-accounting/src/main/java/org/apache/fineract/accounting/journalentry/JournalEntryMapper.java +++ b/fineract-accounting/src/main/java/org/apache/fineract/accounting/journalentry/JournalEntryMapper.java @@ -18,7 +18,6 @@ */ package org.apache.fineract.accounting.journalentry; -import java.time.OffsetDateTime; import org.apache.fineract.accounting.glaccount.domain.GLAccountType; import org.apache.fineract.accounting.journalentry.data.JournalEntryData; import org.apache.fineract.accounting.journalentry.domain.JournalEntry; diff --git a/fineract-accounting/src/main/java/org/apache/fineract/accounting/producttoaccountmapping/service/ProductToGLAccountMappingHelper.java b/fineract-accounting/src/main/java/org/apache/fineract/accounting/producttoaccountmapping/service/ProductToGLAccountMappingHelper.java index 059ac4845..6d48c3433 100644 --- a/fineract-accounting/src/main/java/org/apache/fineract/accounting/producttoaccountmapping/service/ProductToGLAccountMappingHelper.java +++ b/fineract-accounting/src/main/java/org/apache/fineract/accounting/producttoaccountmapping/service/ProductToGLAccountMappingHelper.java @@ -277,14 +277,14 @@ public class ProductToGLAccountMappingHelper { } final JsonArray chargeToIncomeAccountMappingArray = this.fromApiJsonHelper.extractJsonArrayNamed(arrayFragmentName, element); - /** + /* * Variable stores a map representation of charges (key) and their associated income Id's (value) extracted from * the passed in Jsoncommand - **/ + */ final Map inputChargeToIncomeAccountMap = new HashMap<>(); - /*** + /* * Variable stores all charges which have already been mapped to Income Accounts in the system - **/ + */ final Set existingCharges = new HashSet<>(); if (chargeToIncomeAccountMappingArray != null) { if (changes != null) { @@ -301,13 +301,13 @@ public class ProductToGLAccountMappingHelper { // If input map is empty, delete all existing mappings if (inputChargeToIncomeAccountMap.size() == 0) { this.accountMappingRepository.deleteAll(existingChargeToIncomeAccountMappings); - } /** + } /* * Else,
* update existing mappings OR
* delete old mappings (which are already present, but not passed in as a part of Jsoncommand)
* Create new mappings for charges that are passed in as a part of the Jsoncommand but not already present * - **/ + */ else { for (final ProductToGLAccountMapping chargeToIncomeAccountMapping : existingChargeToIncomeAccountMappings) { final Long currentCharge = chargeToIncomeAccountMapping.getCharge().getId(); @@ -356,14 +356,14 @@ public class ProductToGLAccountMappingHelper { .findAllPaymentTypeToFundSourceMappings(productId, portfolioProductType.getValue()); final JsonArray paymentChannelMappingArray = this.fromApiJsonHelper .extractJsonArrayNamed(LoanProductAccountingParams.PAYMENT_CHANNEL_FUND_SOURCE_MAPPING.getValue(), element); - /** + /* * Variable stores a map representation of Payment channels (key) and their fund sources (value) extracted from * the passed in Jsoncommand - **/ + */ final Map inputPaymentChannelFundSourceMap = new HashMap<>(); - /*** + /* * Variable stores all payment types which have already been mapped to Fund Sources in the system - **/ + */ final Set existingPaymentTypes = new HashSet<>(); if (paymentChannelMappingArray != null) { if (changes != null) { @@ -381,14 +381,14 @@ public class ProductToGLAccountMappingHelper { // If input map is empty, delete all existing mappings if (inputPaymentChannelFundSourceMap.isEmpty()) { this.accountMappingRepository.deleteAll(existingPaymentChannelToFundSourceMappings); - } /** + } /* * Else,
* update existing mappings OR
* delete old mappings (which re already present, but not passed in as a part of Jsoncommand)
* Create new mappings for payment types that are passed in as a part of the Jsoncommand but not already * present * - **/ + */ else { for (final ProductToGLAccountMapping existingPaymentChannelToFundSourceMapping : existingPaymentChannelToFundSourceMappings) { final Long currentPaymentChannelId = existingPaymentChannelToFundSourceMapping.getPaymentType().getId(); @@ -584,9 +584,9 @@ public class ProductToGLAccountMappingHelper { // based on input condition GLAccount glAccount; - /** + /* * Both CASH and Accrual placeholders have the same value for income from Interest and penalties - **/ + */ CashAccountsForLoan placeHolderAccountType; if (isPenalty) { glAccount = getAccountByIdAndType(LoanProductAccountingParams.INCOME_ACCOUNT_ID.getValue(), GLAccountType.INCOME, diff --git a/fineract-branch/src/main/java/org/apache/fineract/organisation/teller/api/TellerApiResource.java b/fineract-branch/src/main/java/org/apache/fineract/organisation/teller/api/TellerApiResource.java index 59e79b9fc..684937c3c 100644 --- a/fineract-branch/src/main/java/org/apache/fineract/organisation/teller/api/TellerApiResource.java +++ b/fineract-branch/src/main/java/org/apache/fineract/organisation/teller/api/TellerApiResource.java @@ -181,12 +181,12 @@ public class TellerApiResource { @Consumes({ MediaType.APPLICATION_JSON }) @Produces(MediaType.APPLICATION_JSON) @Operation(summary = "Create Cashiers", description = """ - Mandatory Fields:\s + Mandatory Fields: Cashier/staff, Fromm Date, To Date, Full Day or From time and To time - Optional Fields:\s + Optional Fields: Description/Notes""") @RequestBody(required = true, content = @Content(schema = @Schema(implementation = TellerApiResourceSwagger.PostTellersTellerIdCashiersRequest.class))) @ApiResponse(responseCode = "200", description = "OK", content = @Content(schema = @Schema(implementation = TellerApiResourceSwagger.PostTellersTellerIdCashiersResponse.class))) diff --git a/fineract-core/src/main/java/org/apache/fineract/portfolio/cfcfrms/domain/CfcfrmsSimulatorLog.java b/fineract-core/src/main/java/org/apache/fineract/portfolio/cfcfrms/domain/CfcfrmsSimulatorLog.java index 2408432df..ba18f26e6 100644 --- a/fineract-core/src/main/java/org/apache/fineract/portfolio/cfcfrms/domain/CfcfrmsSimulatorLog.java +++ b/fineract-core/src/main/java/org/apache/fineract/portfolio/cfcfrms/domain/CfcfrmsSimulatorLog.java @@ -23,6 +23,7 @@ import jakarta.persistence.Entity; import jakarta.persistence.Table; import java.time.OffsetDateTime; import org.apache.fineract.infrastructure.core.domain.AbstractAuditableWithUTCDateTimeCustom; +import org.apache.fineract.infrastructure.core.service.DateUtils; /** * Simulator-side audit log for CFCFRMS (I4C/MHA) events. @@ -69,7 +70,7 @@ public class CfcfrmsSimulatorLog extends AbstractAuditableWithUTCDateTimeCustom< this.eventType = eventType; this.payload = payload; this.responsePayload = responsePayload; - this.eventTimestamp = OffsetDateTime.now(); + this.eventTimestamp = DateUtils.getOffsetDateTimeOfTenant(); } public CfcfrmsSimulatorLog(final String cfcfrmsRef, final String ticketId, final String bankIfsc, diff --git a/fineract-core/src/main/java/org/apache/fineract/portfolio/cfcfrms/domain/ComplaintAuditLog.java b/fineract-core/src/main/java/org/apache/fineract/portfolio/cfcfrms/domain/ComplaintAuditLog.java index 6dc8ca92e..c8cc2860f 100644 --- a/fineract-core/src/main/java/org/apache/fineract/portfolio/cfcfrms/domain/ComplaintAuditLog.java +++ b/fineract-core/src/main/java/org/apache/fineract/portfolio/cfcfrms/domain/ComplaintAuditLog.java @@ -23,6 +23,7 @@ import jakarta.persistence.Entity; import jakarta.persistence.Table; import java.time.OffsetDateTime; import org.apache.fineract.infrastructure.core.domain.AbstractAuditableWithUTCDateTimeCustom; +import org.apache.fineract.infrastructure.core.service.DateUtils; /** * Audit trail for every status change on a CFCFRMS complaint ticket. @@ -54,7 +55,7 @@ public class ComplaintAuditLog extends AbstractAuditableWithUTCDateTimeCustom { form.estimatedTotalIncome = command.bigDecimalValueOfParameterNamed("estimatedTotalIncome"); form.reasonForNoPan = StringUtils.defaultIfEmpty(command.stringValueOfParameterNamed("reasonForNoPan"), null); form.declaration = command.booleanPrimitiveValueOfParameterNamed("declaration"); - form.submittedOn = LocalDate.now(); + form.submittedOn = DateUtils.getLocalDateOfTenant(); return form; } } diff --git a/fineract-core/src/main/java/org/apache/fineract/portfolio/client/domain/ClientKyc.java b/fineract-core/src/main/java/org/apache/fineract/portfolio/client/domain/ClientKyc.java index ff286a6cd..b9cb8cd05 100644 --- a/fineract-core/src/main/java/org/apache/fineract/portfolio/client/domain/ClientKyc.java +++ b/fineract-core/src/main/java/org/apache/fineract/portfolio/client/domain/ClientKyc.java @@ -32,6 +32,7 @@ import java.util.Map; import org.apache.commons.lang3.StringUtils; import org.apache.fineract.infrastructure.core.api.JsonCommand; import org.apache.fineract.infrastructure.core.domain.AbstractAuditableWithUTCDateTimeCustom; +import org.apache.fineract.infrastructure.core.service.DateUtils; /** * Represents a client's KYC (Know Your Customer) record as mandated by the Reserve Bank of India @@ -260,7 +261,7 @@ public class ClientKyc extends AbstractAuditableWithUTCDateTimeCustom { this.gstinVerified = false; this.cinVerified = false; this.dinVerified = false; - this.initiatedOn = LocalDate.now(); + this.initiatedOn = DateUtils.getLocalDateOfTenant(); } public static ClientKyc initiateKyc(final Client client, final JsonCommand command) { @@ -456,13 +457,13 @@ public class ClientKyc extends AbstractAuditableWithUTCDateTimeCustom { public void markCkycUploaded(final String ckycNumber, final String batchId) { this.ckycNumber = StringUtils.defaultIfEmpty(ckycNumber, null); this.ckycBatchId = StringUtils.defaultIfEmpty(batchId, null); - this.ckycUploadedOn = LocalDate.now(); + this.ckycUploadedOn = DateUtils.getLocalDateOfTenant(); } /** Called after successful 3rd-party verification of all required documents. */ public void markVerified(final String ckycNumber) { this.kycStatus = ClientKycStatus.VERIFIED.getValue(); - this.verifiedOn = LocalDate.now(); + this.verifiedOn = DateUtils.getLocalDateOfTenant(); this.ckycNumber = StringUtils.defaultIfEmpty(ckycNumber, null); final KycRiskCategory risk = KycRiskCategory.fromInt(this.riskCategory); @@ -474,14 +475,14 @@ public class ClientKyc extends AbstractAuditableWithUTCDateTimeCustom { /** Called when verification fails. */ public void markRejected(final String remarks) { this.kycStatus = ClientKycStatus.REJECTED.getValue(); - this.rejectedOn = LocalDate.now(); + this.rejectedOn = DateUtils.getLocalDateOfTenant(); this.remarks = StringUtils.defaultIfEmpty(remarks, this.remarks); } public void markPanVerified(final String fullName, final String firstName, final String lastName, final String aadhaarSeedingStatus, final String category, final String status) { this.panVerified = true; - this.panVerifiedOn = LocalDate.now(); + this.panVerifiedOn = DateUtils.getLocalDateOfTenant(); this.panFullName = StringUtils.defaultIfEmpty(fullName, null); this.panFirstName = StringUtils.defaultIfEmpty(firstName, null); this.panLastName = StringUtils.defaultIfEmpty(lastName, null); @@ -507,28 +508,28 @@ public class ClientKyc extends AbstractAuditableWithUTCDateTimeCustom { public void markAadhaarVerified() { this.aadhaarVerified = true; - this.aadhaarVerifiedOn = LocalDate.now(); + this.aadhaarVerifiedOn = DateUtils.getLocalDateOfTenant(); } public void markGstinVerified() { this.gstinVerified = true; - this.gstinVerifiedOn = LocalDate.now(); + this.gstinVerifiedOn = DateUtils.getLocalDateOfTenant(); } public void markCinVerified() { this.cinVerified = true; - this.cinVerifiedOn = LocalDate.now(); + this.cinVerifiedOn = DateUtils.getLocalDateOfTenant(); } public void markDinVerified() { this.dinVerified = true; - this.dinVerifiedOn = LocalDate.now(); + this.dinVerifiedOn = DateUtils.getLocalDateOfTenant(); } public void markDinVerified(final String dinNumber, final String mcaResponseJson) { this.dinNumber = dinNumber; this.dinVerified = true; - this.dinVerifiedOn = LocalDate.now(); + this.dinVerifiedOn = DateUtils.getLocalDateOfTenant(); this.isDirector = true; this.dinMcaResponse = mcaResponseJson; } diff --git a/fineract-core/src/main/java/org/apache/fineract/portfolio/mobilelookup/domain/MobileLookupLog.java b/fineract-core/src/main/java/org/apache/fineract/portfolio/mobilelookup/domain/MobileLookupLog.java index 51f01e935..b1a705ae2 100644 --- a/fineract-core/src/main/java/org/apache/fineract/portfolio/mobilelookup/domain/MobileLookupLog.java +++ b/fineract-core/src/main/java/org/apache/fineract/portfolio/mobilelookup/domain/MobileLookupLog.java @@ -24,6 +24,7 @@ import jakarta.persistence.Table; import java.time.OffsetDateTime; import lombok.Getter; import org.apache.fineract.infrastructure.core.domain.AbstractAuditableWithUTCDateTimeCustom; +import org.apache.fineract.infrastructure.core.service.DateUtils; /** * Activity log for each DIP / MNRL mobile number lookup request. @@ -78,6 +79,6 @@ public class MobileLookupLog extends AbstractAuditableWithUTCDateTimeCustom /** * Login gate: returns true if the user has at least one usable DSC mapping that's also not - * past its notAfter date. The {@code dscExpiryDate >= today} clause prevents 2FA-gating a + * past its notAfter date. The {@code dscExpiryDate >= today} clause prevents 2FA-gating a * user who's enrolled but whose cert silently expired between log-ins — they'd otherwise be * stuck in a verification loop with a cert the helper would sign with but the server would * accept (the verify side filters too, but the gate is what kicks the user into the DSC flow diff --git a/fineract-current-product/src/main/java/org/apache/fineract/portfolio/currentaccount/domain/CurrentAccountPendingEdit.java b/fineract-current-product/src/main/java/org/apache/fineract/portfolio/currentaccount/domain/CurrentAccountPendingEdit.java index 3b418d7d2..9631ee749 100644 --- a/fineract-current-product/src/main/java/org/apache/fineract/portfolio/currentaccount/domain/CurrentAccountPendingEdit.java +++ b/fineract-current-product/src/main/java/org/apache/fineract/portfolio/currentaccount/domain/CurrentAccountPendingEdit.java @@ -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; /** @@ -452,7 +453,7 @@ public class CurrentAccountPendingEdit extends AbstractPersistableCustom { public CurrentAccountPendingEdit(final CurrentAccount currentAccount, final AppUser maker) { this.currentAccount = currentAccount; this.maker = maker; - this.createdOn = LocalDateTime.now(); + this.createdOn = DateUtils.getLocalDateTimeOfTenant(); this.status = STATUS_PENDING; this.pendingLockKey = lockKeyFor(currentAccount.getId()); } @@ -582,14 +583,14 @@ public class CurrentAccountPendingEdit extends AbstractPersistableCustom { 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; } diff --git a/fineract-current-product/src/main/java/org/apache/fineract/portfolio/currentaccount/service/CurrentAccountNumberGenerator.java b/fineract-current-product/src/main/java/org/apache/fineract/portfolio/currentaccount/service/CurrentAccountNumberGenerator.java index ca585310b..df8be57cd 100644 --- a/fineract-current-product/src/main/java/org/apache/fineract/portfolio/currentaccount/service/CurrentAccountNumberGenerator.java +++ b/fineract-current-product/src/main/java/org/apache/fineract/portfolio/currentaccount/service/CurrentAccountNumberGenerator.java @@ -51,7 +51,9 @@ public class CurrentAccountNumberGenerator { if (val > maxVal) { maxVal = val; } - } catch (NumberFormatException ignored) {} + } catch (NumberFormatException ignored) { + // non-numeric suffix - skip when computing the max existing sequence + } } } diff --git a/fineract-current-product/src/main/java/org/apache/fineract/portfolio/currentproduct/data/CurrentProductDataValidator.java b/fineract-current-product/src/main/java/org/apache/fineract/portfolio/currentproduct/data/CurrentProductDataValidator.java index d91ff0219..8d09d6b64 100644 --- a/fineract-current-product/src/main/java/org/apache/fineract/portfolio/currentproduct/data/CurrentProductDataValidator.java +++ b/fineract-current-product/src/main/java/org/apache/fineract/portfolio/currentproduct/data/CurrentProductDataValidator.java @@ -54,7 +54,6 @@ import com.google.gson.JsonElement; import com.google.gson.reflect.TypeToken; import java.lang.reflect.Type; import java.math.BigDecimal; -import java.time.MonthDay; import java.util.ArrayList; import java.util.Arrays; import java.util.HashSet; @@ -76,7 +75,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.currentproduct.domain.CurrentProduct; import org.apache.fineract.portfolio.savings.data.SavingsProductAccountingDataValidator; diff --git a/fineract-current-product/src/main/java/org/apache/fineract/portfolio/currentproduct/domain/CurrentProduct.java b/fineract-current-product/src/main/java/org/apache/fineract/portfolio/currentproduct/domain/CurrentProduct.java index 69d33752b..947885750 100644 --- a/fineract-current-product/src/main/java/org/apache/fineract/portfolio/currentproduct/domain/CurrentProduct.java +++ b/fineract-current-product/src/main/java/org/apache/fineract/portfolio/currentproduct/domain/CurrentProduct.java @@ -56,18 +56,11 @@ import static org.apache.fineract.portfolio.savings.SavingsApiConstants.accountT import static org.apache.fineract.portfolio.savings.SavingsApiConstants.customerSegmentParamName; import static org.apache.fineract.portfolio.savings.SavingsApiConstants.productCodeParamName; import static org.apache.fineract.portfolio.savings.SavingsApiConstants.glAccountIdParamName; -import static org.apache.fineract.portfolio.savings.SavingsApiConstants.effectiveDateParamName; -import static org.apache.fineract.portfolio.savings.SavingsApiConstants.effectiveToParamName; -import static org.apache.fineract.portfolio.savings.SavingsApiConstants.endDateParamName; import static org.apache.fineract.portfolio.savings.SavingsApiConstants.introducerRequiredParamName; import static org.apache.fineract.portfolio.savings.SavingsApiConstants.shareLinkingEnabledParamName; import static org.apache.fineract.portfolio.savings.SavingsApiConstants.nominationFacilityParamName; import static org.apache.fineract.portfolio.savings.SavingsApiConstants.dormancyAlertParamName; -import static org.apache.fineract.portfolio.savings.SavingsApiConstants.interestCalculateSelectorParamName; -import static org.apache.fineract.portfolio.savings.SavingsApiConstants.averagePeriodParamName; import static org.apache.fineract.portfolio.savings.SavingsApiConstants.autoPostParamName; -import static org.apache.fineract.portfolio.savings.SavingsApiConstants.frequencyFixDayParamName; -import static org.apache.fineract.portfolio.savings.SavingsApiConstants.lastInterestDateParamName; import static org.apache.fineract.portfolio.savings.SavingsApiConstants.enableLockinPeriodParamName; import static org.apache.fineract.portfolio.savings.SavingsApiConstants.balanceSwapOptionParamName; import static org.apache.fineract.portfolio.savings.SavingsApiConstants.msmeParamName; diff --git a/fineract-current-product/src/main/java/org/apache/fineract/portfolio/currentproduct/domain/CurrentProductDepositLimitKyc.java b/fineract-current-product/src/main/java/org/apache/fineract/portfolio/currentproduct/domain/CurrentProductDepositLimitKyc.java index ae7dc9ab8..279fa49e2 100644 --- a/fineract-current-product/src/main/java/org/apache/fineract/portfolio/currentproduct/domain/CurrentProductDepositLimitKyc.java +++ b/fineract-current-product/src/main/java/org/apache/fineract/portfolio/currentproduct/domain/CurrentProductDepositLimitKyc.java @@ -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_current_product_deposit_limit_kyc") @@ -57,12 +58,12 @@ public class CurrentProductDepositLimitKyc extends AbstractPersistableCustom private LocalDateTime createdDate; protected CurrentProductFacilityLimit() { - this.createdDate = LocalDateTime.now(); } private CurrentProductFacilityLimit(CurrentProduct currentProduct, String limitType, @@ -62,6 +62,7 @@ public class CurrentProductFacilityLimit extends AbstractPersistableCustom this.generalLimit = generalLimit; this.minorAccountLimit = minorAccountLimit; this.smallSavingLimit = smallSavingLimit; + this.createdDate = DateUtils.getLocalDateTimeOfTenant(); } public static CurrentProductFacilityLimit create(CurrentProduct currentProduct, String limitType, diff --git a/fineract-current-product/src/main/java/org/apache/fineract/portfolio/currentproduct/service/CurrentProductReadPlatformServiceImpl.java b/fineract-current-product/src/main/java/org/apache/fineract/portfolio/currentproduct/service/CurrentProductReadPlatformServiceImpl.java index 08aca6829..e3625015b 100644 --- a/fineract-current-product/src/main/java/org/apache/fineract/portfolio/currentproduct/service/CurrentProductReadPlatformServiceImpl.java +++ b/fineract-current-product/src/main/java/org/apache/fineract/portfolio/currentproduct/service/CurrentProductReadPlatformServiceImpl.java @@ -19,13 +19,11 @@ package org.apache.fineract.portfolio.currentproduct.service; import com.google.gson.Gson; -import com.google.gson.JsonObject; import com.google.gson.reflect.TypeToken; import java.lang.reflect.Type; import java.math.BigDecimal; import java.sql.ResultSet; import java.sql.SQLException; -import java.util.ArrayList; import java.util.Collection; import java.util.HashMap; import java.util.List; diff --git a/fineract-provider/src/main/java/org/apache/fineract/accounting/journalentry/api/JournalEntriesApiResource.java b/fineract-provider/src/main/java/org/apache/fineract/accounting/journalentry/api/JournalEntriesApiResource.java index d49026418..9521a44d3 100644 --- a/fineract-provider/src/main/java/org/apache/fineract/accounting/journalentry/api/JournalEntriesApiResource.java +++ b/fineract-provider/src/main/java/org/apache/fineract/accounting/journalentry/api/JournalEntriesApiResource.java @@ -75,7 +75,7 @@ import org.springframework.stereotype.Component; @Path("/v1/journalentries") @Component @Tag(name = "Journal Entries", description = """ - A journal entry refers to the logging of transactions against general ledger accounts. A journal entry may consist of several line items, each of which is either a "debit" or a "credit". The total amount of the debits must equal the total amount of the credits or the journal entry is said to be "unbalanced"\s + A journal entry refers to the logging of transactions against general ledger accounts. A journal entry may consist of several line items, each of which is either a "debit" or a "credit". The total amount of the debits must equal the total amount of the credits or the journal entry is said to be "unbalanced" A journal entry directly changes the account balances on the general ledger""") @RequiredArgsConstructor diff --git a/fineract-provider/src/main/java/org/apache/fineract/infrastructure/email/service/EmailTemplateServiceImpl.java b/fineract-provider/src/main/java/org/apache/fineract/infrastructure/email/service/EmailTemplateServiceImpl.java index cacf4b0ed..c7fa18e22 100644 --- a/fineract-provider/src/main/java/org/apache/fineract/infrastructure/email/service/EmailTemplateServiceImpl.java +++ b/fineract-provider/src/main/java/org/apache/fineract/infrastructure/email/service/EmailTemplateServiceImpl.java @@ -21,6 +21,7 @@ package org.apache.fineract.infrastructure.email.service; import java.time.Year; import org.springframework.beans.factory.annotation.Value; import org.springframework.stereotype.Service; +import org.apache.fineract.infrastructure.core.service.DateUtils; @Service public class EmailTemplateServiceImpl implements EmailTemplateService { @@ -129,7 +130,7 @@ public class EmailTemplateServiceImpl implements EmailTemplateService { + escape(supportEmail) + "" + "

" + "

" - + " © " + Year.now().getValue() + " " + escape(brandName) + ". All rights reserved." + + " © " + Year.now(DateUtils.getDateTimeZoneOfTenant()).getValue() + " " + escape(brandName) + ". All rights reserved." + "

" + " " + " " diff --git a/fineract-provider/src/main/java/org/apache/fineract/infrastructure/imps/crypto/ImpsCryptoUtil.java b/fineract-provider/src/main/java/org/apache/fineract/infrastructure/imps/crypto/ImpsCryptoUtil.java index 2b79999f1..44ce44a64 100644 --- a/fineract-provider/src/main/java/org/apache/fineract/infrastructure/imps/crypto/ImpsCryptoUtil.java +++ b/fineract-provider/src/main/java/org/apache/fineract/infrastructure/imps/crypto/ImpsCryptoUtil.java @@ -109,6 +109,7 @@ public class ImpsCryptoUtil { } /** Decrypt inbound payload using the CBS private key. */ + @SuppressWarnings("StringSplitter") public String decryptJson(String encryptedPayload) { if (cbsPrivateKey == null) { throw new IllegalStateException("CBS private key not loaded — check fineract.imps.cbs.private-key-path"); diff --git a/fineract-provider/src/main/java/org/apache/fineract/infrastructure/imps/service/ImpsCbsServiceImpl.java b/fineract-provider/src/main/java/org/apache/fineract/infrastructure/imps/service/ImpsCbsServiceImpl.java index 6520a8ffe..cfe3660c8 100644 --- a/fineract-provider/src/main/java/org/apache/fineract/infrastructure/imps/service/ImpsCbsServiceImpl.java +++ b/fineract-provider/src/main/java/org/apache/fineract/infrastructure/imps/service/ImpsCbsServiceImpl.java @@ -34,6 +34,7 @@ import org.slf4j.Logger; import org.slf4j.LoggerFactory; import org.springframework.stereotype.Service; import org.springframework.transaction.annotation.Transactional; +import org.apache.fineract.infrastructure.core.service.DateUtils; /** * STUB implementation — returns hard-coded SUCCESS for every request and @@ -108,7 +109,7 @@ public class ImpsCbsServiceImpl implements ImpsCbsService { resp.setRefId(request.getRefId()); resp.setUtr(request.getUtr()); resp.setAmount(request.getAmount()); - resp.setTimeStamp(OffsetDateTime.now().format(ISO_OFFSET)); + resp.setTimeStamp(OffsetDateTime.now(DateUtils.getDateTimeZoneOfTenant()).format(ISO_OFFSET)); resp.setStatus("SUCCESS"); resp.setResponseCode("00"); AccountData payeeAcc = Optional.ofNullable(request.getPayee()).map(PartyData::getAccount).orElse(null); diff --git a/fineract-provider/src/main/java/org/apache/fineract/infrastructure/openproject/service/OpenProjectService.java b/fineract-provider/src/main/java/org/apache/fineract/infrastructure/openproject/service/OpenProjectService.java index 3ef36d4ac..2f5cbc9e7 100644 --- a/fineract-provider/src/main/java/org/apache/fineract/infrastructure/openproject/service/OpenProjectService.java +++ b/fineract-provider/src/main/java/org/apache/fineract/infrastructure/openproject/service/OpenProjectService.java @@ -28,7 +28,6 @@ import java.util.ArrayList; import java.util.Collection; import java.util.LinkedHashMap; import java.util.Map; -import java.util.concurrent.TimeUnit; import lombok.extern.slf4j.Slf4j; import okhttp3.Credentials; import okhttp3.MediaType; @@ -42,6 +41,7 @@ import org.apache.fineract.infrastructure.openproject.data.OpenProjectProjectDat import org.apache.fineract.infrastructure.openproject.data.OpenProjectStatusSummaryData; import org.apache.fineract.infrastructure.openproject.data.OpenProjectWorkPackageData; import org.springframework.stereotype.Service; +import org.apache.fineract.infrastructure.core.service.DateUtils; @Service @Slf4j @@ -164,7 +164,7 @@ public class OpenProjectService { } // Set required custom field: "Last Follow-up Date" (customField8) - body.addProperty("customField8", LocalDate.now().toString()); + body.addProperty("customField8", LocalDate.now(DateUtils.getDateTimeZoneOfTenant()).toString()); if (typeName != null && !typeName.isBlank()) { JsonObject links = new JsonObject(); diff --git a/fineract-provider/src/main/java/org/apache/fineract/infrastructure/rbifeed/service/RbiFeedFetchService.java b/fineract-provider/src/main/java/org/apache/fineract/infrastructure/rbifeed/service/RbiFeedFetchService.java index 1d97d05d0..4dc27a0d6 100644 --- a/fineract-provider/src/main/java/org/apache/fineract/infrastructure/rbifeed/service/RbiFeedFetchService.java +++ b/fineract-provider/src/main/java/org/apache/fineract/infrastructure/rbifeed/service/RbiFeedFetchService.java @@ -47,6 +47,7 @@ import org.springframework.transaction.annotation.Transactional; import org.w3c.dom.Document; import org.w3c.dom.Element; import org.w3c.dom.NodeList; +import org.apache.fineract.infrastructure.core.service.DateUtils; @Service @RequiredArgsConstructor @@ -127,7 +128,7 @@ public class RbiFeedFetchService { NodeList items = doc.getElementsByTagName("item"); log.debug("RBI FeedFetchService - Parsed {} items from RSS for category: {}", items.getLength(), category); List newItems = new ArrayList<>(); - LocalDateTime now = LocalDateTime.now(); + LocalDateTime now = LocalDateTime.now(DateUtils.getDateTimeZoneOfTenant()); for (int i = 0; i < items.getLength(); i++) { Element item = (Element) items.item(i); diff --git a/fineract-provider/src/main/java/org/apache/fineract/infrastructure/security/otp/api/EmailLoginOtpApiResource.java b/fineract-provider/src/main/java/org/apache/fineract/infrastructure/security/otp/api/EmailLoginOtpApiResource.java index a98b1f057..7bd8c7761 100644 --- a/fineract-provider/src/main/java/org/apache/fineract/infrastructure/security/otp/api/EmailLoginOtpApiResource.java +++ b/fineract-provider/src/main/java/org/apache/fineract/infrastructure/security/otp/api/EmailLoginOtpApiResource.java @@ -18,6 +18,8 @@ */ package org.apache.fineract.infrastructure.security.otp.api; +import com.google.common.base.Splitter; +import com.google.common.collect.Iterables; import com.google.gson.JsonObject; import com.google.gson.JsonParser; import io.swagger.v3.oas.annotations.Operation; @@ -107,7 +109,7 @@ public class EmailLoginOtpApiResource { } final String fwd = req.getHeader("X-Forwarded-For"); if (fwd != null && !fwd.isBlank()) { - return fwd.split(",")[0].trim(); + return Iterables.get(Splitter.on(',').split(fwd), 0).trim(); } return req.getRemoteAddr(); } diff --git a/fineract-provider/src/main/java/org/apache/fineract/infrastructure/security/otp/api/LoginOtpApiResource.java b/fineract-provider/src/main/java/org/apache/fineract/infrastructure/security/otp/api/LoginOtpApiResource.java index a7f1e78d6..c1c739abf 100644 --- a/fineract-provider/src/main/java/org/apache/fineract/infrastructure/security/otp/api/LoginOtpApiResource.java +++ b/fineract-provider/src/main/java/org/apache/fineract/infrastructure/security/otp/api/LoginOtpApiResource.java @@ -18,6 +18,8 @@ */ package org.apache.fineract.infrastructure.security.otp.api; +import com.google.common.base.Splitter; +import com.google.common.collect.Iterables; import com.google.gson.JsonObject; import com.google.gson.JsonParser; import io.swagger.v3.oas.annotations.Operation; @@ -107,7 +109,7 @@ public class LoginOtpApiResource { } final String fwd = req.getHeader("X-Forwarded-For"); if (fwd != null && !fwd.isBlank()) { - return fwd.split(",")[0].trim(); + return Iterables.get(Splitter.on(',').split(fwd), 0).trim(); } return req.getRemoteAddr(); } diff --git a/fineract-provider/src/main/java/org/apache/fineract/infrastructure/security/otp/service/EmailLoginOtpServiceImpl.java b/fineract-provider/src/main/java/org/apache/fineract/infrastructure/security/otp/service/EmailLoginOtpServiceImpl.java index 80969e691..b732ad8a4 100644 --- a/fineract-provider/src/main/java/org/apache/fineract/infrastructure/security/otp/service/EmailLoginOtpServiceImpl.java +++ b/fineract-provider/src/main/java/org/apache/fineract/infrastructure/security/otp/service/EmailLoginOtpServiceImpl.java @@ -45,6 +45,7 @@ import org.springframework.beans.factory.annotation.Autowired; import org.springframework.beans.factory.annotation.Value; import org.springframework.stereotype.Service; import org.springframework.transaction.annotation.Transactional; +import org.apache.fineract.infrastructure.core.service.DateUtils; @Service public class EmailLoginOtpServiceImpl implements EmailLoginOtpService { @@ -128,7 +129,7 @@ public class EmailLoginOtpServiceImpl implements EmailLoginOtpService { // Render the branded template — same look and feel for OTP, welcome, password-reset, alerts. final String html = emailTemplateService.renderOtp(recipientName, otp, validityMinutes); - final String subject = "Your OTP for Login - " + appName + " (" + LocalDateTime.now().format(SUBJECT_TIMESTAMP) + ")"; + final String subject = "Your OTP for Login - " + appName + " (" + LocalDateTime.now(DateUtils.getDateTimeZoneOfTenant()).format(SUBJECT_TIMESTAMP) + ")"; final boolean sent = emailSenderService.sendHtml(email, subject, html); if (sent) { diff --git a/fineract-provider/src/main/java/org/apache/fineract/organisation/teller/service/TellerWritePlatformServiceJpaImpl.java b/fineract-provider/src/main/java/org/apache/fineract/organisation/teller/service/TellerWritePlatformServiceJpaImpl.java index a2475b4c2..f4aaf9f4a 100644 --- a/fineract-provider/src/main/java/org/apache/fineract/organisation/teller/service/TellerWritePlatformServiceJpaImpl.java +++ b/fineract-provider/src/main/java/org/apache/fineract/organisation/teller/service/TellerWritePlatformServiceJpaImpl.java @@ -20,7 +20,6 @@ package org.apache.fineract.organisation.teller.service; import jakarta.persistence.PersistenceException; import java.util.Map; -import java.util.Set; import lombok.AllArgsConstructor; import lombok.extern.slf4j.Slf4j; import org.apache.commons.lang3.exception.ExceptionUtils; @@ -44,7 +43,6 @@ import org.apache.fineract.organisation.teller.domain.CashierTransactionReposito import org.apache.fineract.organisation.teller.domain.CashierTxnType; import org.apache.fineract.organisation.teller.domain.Teller; import org.apache.fineract.organisation.teller.domain.TellerRepositoryWrapper; -import org.apache.fineract.organisation.teller.exception.CashierExistForTellerException; import org.apache.fineract.organisation.teller.exception.CashierNotFoundException; import org.apache.fineract.organisation.teller.exception.TellerAlreadyExistsException; import org.apache.fineract.organisation.teller.serialization.TellerCommandFromApiJsonDeserializer; diff --git a/fineract-provider/src/main/java/org/apache/fineract/portfolio/cashexchange/api/CashExchangeApiResource.java b/fineract-provider/src/main/java/org/apache/fineract/portfolio/cashexchange/api/CashExchangeApiResource.java index 367433ddf..3ec138689 100644 --- a/fineract-provider/src/main/java/org/apache/fineract/portfolio/cashexchange/api/CashExchangeApiResource.java +++ b/fineract-provider/src/main/java/org/apache/fineract/portfolio/cashexchange/api/CashExchangeApiResource.java @@ -33,6 +33,7 @@ import org.apache.fineract.useradministration.domain.AppUser; import org.springframework.jdbc.core.JdbcTemplate; import org.springframework.stereotype.Component; import org.springframework.transaction.annotation.Transactional; +import org.apache.fineract.infrastructure.core.service.DateUtils; @Path("/v1/cashexchange") @Component @@ -94,7 +95,7 @@ public class CashExchangeApiResource { header.setNote(note); header.setCustomerIdProof(customerIdProof); header.setIsReversed(false); - header.setCreatedAt(LocalDateTime.now()); + header.setCreatedAt(LocalDateTime.now(DateUtils.getDateTimeZoneOfTenant())); try { AppUser user = this.context.authenticatedUser(); if (user != null) { @@ -107,7 +108,9 @@ public class CashExchangeApiResource { + "JOIN m_appuser au ON au.staff_id = ms.id WHERE au.id = ?", Long.class, user.getId()); header.setCashierId(cashierId); - } catch (Exception ignored) {} + } catch (Exception ignored) { + // intentionally ignored + } } } catch (Exception e) { // resolving the current user must never block recording the exchange @@ -160,14 +163,18 @@ public class CashExchangeApiResource { try { JsonObject json = JsonParser.parseString(body).getAsJsonObject(); reason = json.has("reason") && !json.get("reason").isJsonNull() ? json.get("reason").getAsString() : null; - } catch (Exception ignored) {} + } catch (Exception ignored) { + // intentionally ignored + } exchange.setIsReversed(true); - exchange.setReversedAt(LocalDateTime.now()); + exchange.setReversedAt(LocalDateTime.now(DateUtils.getDateTimeZoneOfTenant())); exchange.setReverseReason(reason); try { AppUser user = this.context.authenticatedUser(); if (user != null) exchange.setReversedBy(user.getId()); - } catch (Exception ignored) {} + } catch (Exception ignored) { + // intentionally ignored + } repository.save(exchange); JsonObject result = new JsonObject(); result.addProperty("resourceId", id); diff --git a/fineract-provider/src/main/java/org/apache/fineract/portfolio/cashierdeposit/api/CashierDepositRequestApiResource.java b/fineract-provider/src/main/java/org/apache/fineract/portfolio/cashierdeposit/api/CashierDepositRequestApiResource.java index 28b7389fd..2474b9c70 100644 --- a/fineract-provider/src/main/java/org/apache/fineract/portfolio/cashierdeposit/api/CashierDepositRequestApiResource.java +++ b/fineract-provider/src/main/java/org/apache/fineract/portfolio/cashierdeposit/api/CashierDepositRequestApiResource.java @@ -59,6 +59,9 @@ import org.apache.fineract.useradministration.domain.AppUser; import org.springframework.jdbc.core.JdbcTemplate; import org.springframework.stereotype.Component; import org.springframework.transaction.annotation.Transactional; +import org.apache.fineract.infrastructure.core.service.DateUtils; +import com.google.common.collect.Iterables; +import com.google.common.base.Splitter; @Path("/v1/cashier/deposit-requests") @Component @@ -364,7 +367,7 @@ public class CashierDepositRequestApiResource { final BigDecimal amount = new BigDecimal(record.get("amount").toString()); final Object ptId = record.get("payment_type_id"); final Object txnDateObj = record.get("txn_date"); - final String txnDateStr = txnDateObj != null ? txnDateObj.toString().split(" ")[0] : null; + final String txnDateStr = txnDateObj != null ? Iterables.get(Splitter.on(' ').split(txnDateObj.toString()), 0) : null; final String description = (String) record.get("description"); final String storedAccountType = (String) record.get("account_type"); @@ -513,7 +516,7 @@ public class CashierDepositRequestApiResource { final BigDecimal amount = new BigDecimal(record.get("amount").toString()); final Object ptId = record.get("payment_type_id"); final Object txnDateObj = record.get("txn_date"); - final String txnDateStr = txnDateObj != null ? txnDateObj.toString().split(" ")[0] : null; + final String txnDateStr = txnDateObj != null ? Iterables.get(Splitter.on(' ').split(txnDateObj.toString()), 0) : null; final String description = (String) record.get("description"); if (savingsAccountId == null || !isCurrentAccountById(savingsAccountId)) { @@ -559,7 +562,7 @@ public class CashierDepositRequestApiResource { final Long savingsAccountId, final BigDecimal amount, final Object paymentTypeId, final String txnDateStr, final String note) { - final String today = LocalDate.now().format(DateTimeFormatter.ofPattern("dd MMMM yyyy")); + final String today = LocalDate.now(DateUtils.getDateTimeZoneOfTenant()).format(DateTimeFormatter.ofPattern("dd MMMM yyyy")); final String date = txnDateStr != null && !txnDateStr.isBlank() ? formatForFineract(txnDateStr) : today; final JsonObject payload = new JsonObject(); @@ -587,7 +590,7 @@ public class CashierDepositRequestApiResource { final Long currentAccountId, final BigDecimal amount, final Object paymentTypeId, final String txnDateStr, final String note) { - final String today = LocalDate.now().format(DateTimeFormatter.ofPattern("dd MMMM yyyy")); + final String today = LocalDate.now(DateUtils.getDateTimeZoneOfTenant()).format(DateTimeFormatter.ofPattern("dd MMMM yyyy")); final String date = txnDateStr != null && !txnDateStr.isBlank() ? formatForFineract(txnDateStr) : today; final JsonObject payload = new JsonObject(); @@ -644,7 +647,7 @@ public class CashierDepositRequestApiResource { final Object paymentTypeId, final String txnDateStr, final String note, final boolean isDeposit) { - final String today = LocalDate.now().format(DateTimeFormatter.ofPattern("dd MMMM yyyy")); + final String today = LocalDate.now(DateUtils.getDateTimeZoneOfTenant()).format(DateTimeFormatter.ofPattern("dd MMMM yyyy")); final String date = txnDateStr != null && !txnDateStr.isBlank() ? formatForFineract(txnDateStr) : today; // Deposit (CR): cashier receives cash → credit selected GL, debit cash vault (contra) @@ -686,67 +689,6 @@ public class CashierDepositRequestApiResource { return result.getTransactionId() != null ? result.getTransactionId() : null; } - private void saveGlDenomination(final String denominationData, - final Map record, final String txnIdRaw) { - final JsonObject denomMap; - try { - denomMap = gson.fromJson(denominationData, JsonObject.class); - } catch (Exception e) { - return; - } - if (denomMap == null || denomMap.size() == 0) return; - - // Convert hex transaction ID to Long (same logic as CashierGlDenominationApiResource) - Long txnId = null; - if (txnIdRaw != null && !txnIdRaw.isBlank()) { - try { - txnId = Long.valueOf(txnIdRaw); - } catch (NumberFormatException ignored) { - try { - final String hex = txnIdRaw.length() > 15 ? txnIdRaw.substring(txnIdRaw.length() - 15) : txnIdRaw; - txnId = Long.parseUnsignedLong(hex, 16); - } catch (NumberFormatException ignored2) { - txnId = null; - } - } - } - - final String accountNo = (String) record.get("account_no"); - final Object cashierIdObj = record.get("cashier_id"); - final Long cashierId = cashierIdObj != null ? Long.valueOf(cashierIdObj.toString()) : null; - final String cashierUsername = (String) record.get("cashier_username"); - - for (final Map.Entry entry : denomMap.entrySet()) { - final int count; - try { count = entry.getValue().getAsInt(); } catch (Exception e) { continue; } - if (count <= 0) continue; - - final String[] parts = entry.getKey().split(":", 2); - if (parts.length != 2) continue; - final String kind = parts[0]; - final int value; - try { value = Integer.parseInt(parts[1]); } catch (Exception e) { continue; } - - final List ids = jdbcTemplate.queryForList( - "SELECT id FROM m_denomination_master WHERE denomination = ? AND kind = ?" - + " AND (deleted IS NULL OR deleted = false) LIMIT 1", - Long.class, value, kind); - if (ids.isEmpty()) continue; - final Long denomId = ids.get(0); - - jdbcTemplate.update(""" - INSERT INTO m_savings_txn_denomination - (txn_id, savings_account_id, account_no, client_id, denomination_id, - denomination_value, count, total_amount, txn_date, txn_type, officer_id, officer_username) - VALUES (?, NULL, ?, NULL, ?, ?, ?, ?, CURRENT_DATE, 'DEPOSIT', ?, ?) - """, - txnId, accountNo, denomId, - value, count, BigDecimal.valueOf((long) value * count), - cashierId, cashierUsername - ); - } - } - /** * Saves the denomination breakdown the cashier entered at submit time into * m_savings_txn_denomination once the deposit is approved, so the cashier's @@ -797,56 +739,6 @@ public class CashierDepositRequestApiResource { } } - private void saveDepositDenomination(final String denominationData, - final Map record, final Long txnId) { - final JsonObject denomMap; - try { - denomMap = gson.fromJson(denominationData, JsonObject.class); - } catch (Exception e) { - return; // malformed JSON — skip silently - } - if (denomMap == null || denomMap.size() == 0) return; - - final Object saObj = record.get("savings_account_id"); - final Long savingsAccountId = saObj != null ? Long.valueOf(saObj.toString()) : null; - final String accountNo = (String) record.get("account_no"); - final Object clientIdObj = record.get("client_id"); - final Long clientId = clientIdObj != null ? Long.valueOf(clientIdObj.toString()) : null; - final Object cashierIdObj = record.get("cashier_id"); - final Long cashierId = cashierIdObj != null ? Long.valueOf(cashierIdObj.toString()) : null; - final String cashierUsername = (String) record.get("cashier_username"); - - for (final Map.Entry entry : denomMap.entrySet()) { - final int count; - try { count = entry.getValue().getAsInt(); } catch (Exception e) { continue; } - if (count <= 0) continue; - - final String[] parts = entry.getKey().split(":", 2); // "note:500" or "coin:1" - if (parts.length != 2) continue; - final String kind = parts[0]; - final int value; - try { value = Integer.parseInt(parts[1]); } catch (Exception e) { continue; } - - final List ids = jdbcTemplate.queryForList( - "SELECT id FROM m_denomination_master WHERE denomination = ? AND kind = ?" - + " AND (deleted IS NULL OR deleted = false) LIMIT 1", - Long.class, value, kind); - if (ids.isEmpty()) continue; - final Long denomId = ids.get(0); - - jdbcTemplate.update(""" - INSERT INTO m_savings_txn_denomination - (txn_id, savings_account_id, account_no, client_id, denomination_id, - denomination_value, count, total_amount, txn_date, txn_type, officer_id, officer_username) - VALUES (?, ?, ?, ?, ?, ?, ?, ?, CURRENT_DATE, 'DEPOSIT', ?, ?) - """, - txnId, savingsAccountId, accountNo, clientId, denomId, - value, count, BigDecimal.valueOf((long) value * count), - cashierId, cashierUsername - ); - } - } - /** * If a cash denomination breakdown is provided, its total must exactly equal * the deposit amount — prevents the recorded vault movement from drifting @@ -946,7 +838,7 @@ public class CashierDepositRequestApiResource { final LocalDate ld = LocalDate.parse(isoDate, DateTimeFormatter.ISO_LOCAL_DATE); return ld.format(DateTimeFormatter.ofPattern("dd MMMM yyyy")); } catch (Exception e) { - return LocalDate.now().format(DateTimeFormatter.ofPattern("dd MMMM yyyy")); + return LocalDate.now(DateUtils.getDateTimeZoneOfTenant()).format(DateTimeFormatter.ofPattern("dd MMMM yyyy")); } } diff --git a/fineract-provider/src/main/java/org/apache/fineract/portfolio/cashintercashier/api/CashInterCashierApiResource.java b/fineract-provider/src/main/java/org/apache/fineract/portfolio/cashintercashier/api/CashInterCashierApiResource.java index a3d76e4f5..2f72e2ad2 100644 --- a/fineract-provider/src/main/java/org/apache/fineract/portfolio/cashintercashier/api/CashInterCashierApiResource.java +++ b/fineract-provider/src/main/java/org/apache/fineract/portfolio/cashintercashier/api/CashInterCashierApiResource.java @@ -31,6 +31,7 @@ import org.apache.fineract.portfolio.cashintercashier.domain.CashInterCashierRep import org.apache.fineract.useradministration.domain.AppUser; import org.springframework.stereotype.Component; import org.springframework.transaction.annotation.Transactional; +import org.apache.fineract.infrastructure.core.service.DateUtils; @Path("/v1/cashintercashier") @Component @@ -69,7 +70,7 @@ public class CashInterCashierApiResource { } final LocalDate transferDate = json.has("transferDate") && !json.get("transferDate").isJsonNull() - ? LocalDate.parse(json.get("transferDate").getAsString()) : LocalDate.now(); + ? LocalDate.parse(json.get("transferDate").getAsString()) : LocalDate.now(DateUtils.getDateTimeZoneOfTenant()); final String fromParty = json.has("fromParty") && !json.get("fromParty").isJsonNull() ? json.get("fromParty").getAsString() : null; final String toParty = json.has("toParty") && !json.get("toParty").isJsonNull() @@ -95,13 +96,15 @@ public class CashInterCashierApiResource { header.setToParty(toParty); header.setTransferAmount(total); header.setNote(note); - header.setCreatedAt(LocalDateTime.now()); + header.setCreatedAt(LocalDateTime.now(DateUtils.getDateTimeZoneOfTenant())); header.setIsReversed(false); try { AppUser user = this.context.authenticatedUser(); header.setPerformedBy(user.getId()); header.setPerformedByUsername(user.getUsername()); - } catch (Exception ignored) {} + } catch (Exception ignored) { + // intentionally ignored + } CashInterCashier saved = repository.saveAndFlush(header); saveDetails(saved.getId(), denominations); @@ -128,13 +131,17 @@ public class CashInterCashierApiResource { try { JsonObject json = JsonParser.parseString(body).getAsJsonObject(); reason = json.has("reason") ? json.get("reason").getAsString() : null; - } catch (Exception ignored) {} + } catch (Exception ignored) { + // intentionally ignored + } AppUser user = null; - try { user = this.context.authenticatedUser(); } catch (Exception ignored) {} + try { user = this.context.authenticatedUser(); } catch (Exception ignored) { + // intentionally ignored + } record.setIsReversed(true); - record.setReversedAt(LocalDateTime.now()); + record.setReversedAt(LocalDateTime.now(DateUtils.getDateTimeZoneOfTenant())); record.setReverseReason(reason); if (user != null) record.setReversedBy(user.getId()); repository.save(record); diff --git a/fineract-provider/src/main/java/org/apache/fineract/portfolio/cashreconciliation/api/CashReconciliationApiResource.java b/fineract-provider/src/main/java/org/apache/fineract/portfolio/cashreconciliation/api/CashReconciliationApiResource.java index 9d8cf0325..cc922d638 100644 --- a/fineract-provider/src/main/java/org/apache/fineract/portfolio/cashreconciliation/api/CashReconciliationApiResource.java +++ b/fineract-provider/src/main/java/org/apache/fineract/portfolio/cashreconciliation/api/CashReconciliationApiResource.java @@ -32,6 +32,7 @@ import org.apache.fineract.useradministration.domain.AppUser; import org.springframework.jdbc.core.JdbcTemplate; import org.springframework.stereotype.Component; import org.springframework.transaction.annotation.Transactional; +import org.apache.fineract.infrastructure.core.service.DateUtils; @Path("/v1/cashreconciliation") @Component @@ -62,7 +63,7 @@ public class CashReconciliationApiResource { throw new PlatformDataIntegrityException("error.msg.cashreconciliation.cashier.required", "cashierId query param is required."); } - final String dateFilter = (asOfDate != null && !asOfDate.isBlank()) ? asOfDate : LocalDate.now().toString(); + final String dateFilter = (asOfDate != null && !asOfDate.isBlank()) ? asOfDate : LocalDate.now(DateUtils.getDateTimeZoneOfTenant()).toString(); // In: vault → cashier allocations — GROUP BY denomination_id+kind to keep coin and note separate final String sqlIn1 = "SELECT ctd.denomination_id, ctd.denomination_value, COALESCE(dm.kind, 'note') AS kind, SUM(ctd.count) AS total_count " @@ -187,7 +188,7 @@ public class CashReconciliationApiResource { @Path("expected/me") public String getExpectedForMe(@QueryParam("asOfDate") String asOfDate) { context.authenticatedUser().validateHasPermissionTo("READ_CASHRECONCILIATION"); - final String dateFilter = (asOfDate != null && !asOfDate.isBlank()) ? asOfDate : LocalDate.now().toString(); + final String dateFilter = (asOfDate != null && !asOfDate.isBlank()) ? asOfDate : LocalDate.now(DateUtils.getDateTimeZoneOfTenant()).toString(); Long appUserId; try { appUserId = context.authenticatedUser().getId(); @@ -223,7 +224,7 @@ public class CashReconciliationApiResource { throw new PlatformDataIntegrityException("error.msg.cashreconciliation.cashier.required", "cashierId query param is required."); } - final String reconDate = (date != null && !date.isBlank()) ? date : LocalDate.now().toString(); + final String reconDate = (date != null && !date.isBlank()) ? date : LocalDate.now(DateUtils.getDateTimeZoneOfTenant()).toString(); Integer count = jdbcTemplate.queryForObject( "SELECT COUNT(*) FROM m_cash_reconciliation WHERE cashier_id = ? AND recon_date = CAST(? AS DATE)", Integer.class, cashierId, reconDate); @@ -247,7 +248,7 @@ public class CashReconciliationApiResource { "cashierId is required."); } final LocalDate reconDate = json.has("reconDate") && !json.get("reconDate").isJsonNull() - ? LocalDate.parse(json.get("reconDate").getAsString()) : LocalDate.now(); + ? LocalDate.parse(json.get("reconDate").getAsString()) : LocalDate.now(DateUtils.getDateTimeZoneOfTenant()); final String cashierName = json.has("cashierName") && !json.get("cashierName").isJsonNull() ? json.get("cashierName").getAsString() : null; final Long tellerId = json.has("tellerId") && !json.get("tellerId").isJsonNull() @@ -299,12 +300,14 @@ public class CashReconciliationApiResource { header.setVariance(variance); header.setStatus(status); header.setNote(note); - header.setCreatedAt(LocalDateTime.now()); + header.setCreatedAt(LocalDateTime.now(DateUtils.getDateTimeZoneOfTenant())); try { AppUser user = this.context.authenticatedUser(); header.setPerformedBy(user.getId()); header.setPerformedByUsername(user.getUsername()); - } catch (Exception ignored) {} + } catch (Exception ignored) { + // intentionally ignored + } CashReconciliation saved = repository.saveAndFlush(header); for (CashReconciliationDetail d : details) { diff --git a/fineract-provider/src/main/java/org/apache/fineract/portfolio/cashreport/api/CashReportApiResource.java b/fineract-provider/src/main/java/org/apache/fineract/portfolio/cashreport/api/CashReportApiResource.java index 3e29e1d0c..f0cb31fce 100644 --- a/fineract-provider/src/main/java/org/apache/fineract/portfolio/cashreport/api/CashReportApiResource.java +++ b/fineract-provider/src/main/java/org/apache/fineract/portfolio/cashreport/api/CashReportApiResource.java @@ -18,6 +18,7 @@ import org.apache.fineract.portfolio.cashreport.service.CashierRoleHelper; import org.apache.fineract.portfolio.denominationmaster.service.DenominationBreakdownWriter; import org.springframework.jdbc.core.JdbcTemplate; import org.springframework.stereotype.Component; +import org.apache.fineract.infrastructure.core.service.DateUtils; @Path("/v1/cashreports") @Component @@ -34,7 +35,7 @@ public class CashReportApiResource { @GET @Path("closing") public String closing(@QueryParam("date") String date) { - final String txnDate = (date != null && !date.isBlank()) ? date : LocalDate.now().toString(); + final String txnDate = (date != null && !date.isBlank()) ? date : LocalDate.now(DateUtils.getDateTimeZoneOfTenant()).toString(); // Single query — conditional aggregation for deposit, withdrawal, net per denomination final String sql = "SELECT std.denomination_id, std.denomination_value, COALESCE(dm.kind, 'note') AS kind, " @@ -238,7 +239,7 @@ public class CashReportApiResource { return gson.toJson(result); } - final String today = LocalDate.now().toString(); + final String today = LocalDate.now(DateUtils.getDateTimeZoneOfTenant()).toString(); // Find the earliest transfer date before today for which no settlement exists on or after that date final String sql = "SELECT MIN(ct.transfer_date) AS earliest_unsettled " @@ -256,7 +257,9 @@ public class CashReportApiResource { java.sql.Date earliestDate = null; try { earliestDate = jdbcTemplate.queryForObject(sql, java.sql.Date.class, cashierId, today, cashierId); - } catch (Exception ignored) {} + } catch (Exception ignored) { + // intentionally ignored + } final boolean unsettled = earliestDate != null; final String unsettledSince = earliestDate != null ? earliestDate.toString() : null; @@ -265,7 +268,9 @@ public class CashReportApiResource { if (unsettled) { try { pendingAmount = denominationBreakdownWriter.getCashierTotalCash(cashierId); - } catch (Exception ignored) {} + } catch (Exception ignored) { + // intentionally ignored + } } // Check whether today's morning cash transfer has been received @@ -276,7 +281,9 @@ public class CashReportApiResource { Integer todayTransferCount = 0; try { todayTransferCount = jdbcTemplate.queryForObject(morningTransferSql, Integer.class, cashierId, today); - } catch (Exception ignored) {} + } catch (Exception ignored) { + // intentionally ignored + } final boolean morningTransferReceived = todayTransferCount != null && todayTransferCount > 0; result.put("cashierId", cashierId); @@ -295,7 +302,7 @@ public class CashReportApiResource { @Path("cashier-position") public String cashierPosition(@QueryParam("cashierId") Long cashierId, @QueryParam("asOfDate") String asOfDate) { - final String dateFilter = (asOfDate != null && !asOfDate.isBlank()) ? asOfDate : LocalDate.now().toString(); + final String dateFilter = (asOfDate != null && !asOfDate.isBlank()) ? asOfDate : LocalDate.now(DateUtils.getDateTimeZoneOfTenant()).toString(); // CASHIER role: always scope to their own position only final Long scopedId = cashierRoleHelper.getCashierIdForFiltering(); @@ -326,7 +333,7 @@ public class CashReportApiResource { @GET @Path("cashier-position/me") public String cashierPositionMe(@QueryParam("asOfDate") String asOfDate) { - final String dateFilter = (asOfDate != null && !asOfDate.isBlank()) ? asOfDate : LocalDate.now().toString(); + final String dateFilter = (asOfDate != null && !asOfDate.isBlank()) ? asOfDate : LocalDate.now(DateUtils.getDateTimeZoneOfTenant()).toString(); Long appUserId; try { appUserId = context.authenticatedUser().getId(); @@ -362,7 +369,7 @@ public class CashReportApiResource { @Path("cashier-morning") public String cashierMorning(@QueryParam("cashierId") Long cashierId, @QueryParam("date") String date) { - final String txnDate = (date != null && !date.isBlank()) ? date : LocalDate.now().toString(); + final String txnDate = (date != null && !date.isBlank()) ? date : LocalDate.now(DateUtils.getDateTimeZoneOfTenant()).toString(); if (cashierId == null) { Map empty = new LinkedHashMap<>(); empty.put("cashierId", null); @@ -515,7 +522,9 @@ public class CashReportApiResource { cashierName = jdbcTemplate.queryForObject( "SELECT ms.display_name FROM m_cashiers mc JOIN m_staff ms ON ms.id = mc.staff_id WHERE mc.id = ?", String.class, cashierId); - } catch (Exception ignored) {} + } catch (Exception ignored) { + // intentionally ignored + } Map result = new LinkedHashMap<>(); result.put("cashierId", cashierId); @@ -562,7 +571,7 @@ public class CashReportApiResource { @QueryParam("offset") Integer offset, @QueryParam("limit") Integer limit) { - final String txnDate = (date != null && !date.isBlank()) ? date : LocalDate.now().toString(); + final String txnDate = (date != null && !date.isBlank()) ? date : LocalDate.now(DateUtils.getDateTimeZoneOfTenant()).toString(); final int resolvedLimit = (limit != null && limit > 0) ? limit : 20; final int resolvedOffset = (offset != null && offset >= 0) ? offset : 0; diff --git a/fineract-provider/src/main/java/org/apache/fineract/portfolio/cashsettlement/api/CashSettlementApiResource.java b/fineract-provider/src/main/java/org/apache/fineract/portfolio/cashsettlement/api/CashSettlementApiResource.java index a9b8b64d9..90007a91a 100644 --- a/fineract-provider/src/main/java/org/apache/fineract/portfolio/cashsettlement/api/CashSettlementApiResource.java +++ b/fineract-provider/src/main/java/org/apache/fineract/portfolio/cashsettlement/api/CashSettlementApiResource.java @@ -36,6 +36,7 @@ import org.springframework.stereotype.Component; import org.springframework.transaction.PlatformTransactionManager; import org.springframework.transaction.annotation.Transactional; import org.springframework.transaction.support.TransactionTemplate; +import org.apache.fineract.infrastructure.core.service.DateUtils; @Path("/v1/cashsettlement") @Component @@ -70,7 +71,7 @@ public class CashSettlementApiResource { } final LocalDate settlementDate = json.has("settlementDate") && !json.get("settlementDate").isJsonNull() - ? LocalDate.parse(json.get("settlementDate").getAsString()) : LocalDate.now(); + ? LocalDate.parse(json.get("settlementDate").getAsString()) : LocalDate.now(DateUtils.getDateTimeZoneOfTenant()); final String fromParty = json.has("fromParty") && !json.get("fromParty").isJsonNull() ? json.get("fromParty").getAsString() : null; final String toParty = json.has("toParty") && !json.get("toParty").isJsonNull() @@ -116,13 +117,15 @@ public class CashSettlementApiResource { header.setToParty(toParty); header.setSettlementAmount(total); header.setNote(note); - header.setCreatedAt(LocalDateTime.now()); + header.setCreatedAt(LocalDateTime.now(DateUtils.getDateTimeZoneOfTenant())); header.setIsReversed(false); try { AppUser user = this.context.authenticatedUser(); header.setPerformedBy(user.getId()); header.setPerformedByUsername(user.getUsername()); - } catch (Exception ignored) {} + } catch (Exception ignored) { + // intentionally ignored + } // Commit header + details first, then GL dispatch separately to avoid // EclipseLink flushing pending detail rows inside Fineract's GL transaction. @@ -142,7 +145,9 @@ public class CashSettlementApiResource { Long resolved = jdbcTemplate.queryForObject( "SELECT teller_id FROM m_cashiers WHERE id = ?", Long.class, fromCashierId); if (resolved != null) glTellerId = resolved; - } catch (Exception ignored) {} + } catch (Exception ignored) { + // intentionally ignored + } glDispatchService.settleCashFromCashier(glTellerId, fromCashierId, total, currencyCode, settlementDate.format(DateTimeFormatter.ISO_LOCAL_DATE), note != null ? note : ""); @@ -174,13 +179,17 @@ public class CashSettlementApiResource { try { JsonObject json = JsonParser.parseString(body).getAsJsonObject(); reason = json.has("reason") ? json.get("reason").getAsString() : null; - } catch (Exception ignored) {} + } catch (Exception ignored) { + // intentionally ignored + } AppUser user = null; - try { user = this.context.authenticatedUser(); } catch (Exception ignored) {} + try { user = this.context.authenticatedUser(); } catch (Exception ignored) { + // intentionally ignored + } settlement.setIsReversed(true); - settlement.setReversedAt(LocalDateTime.now()); + settlement.setReversedAt(LocalDateTime.now(DateUtils.getDateTimeZoneOfTenant())); settlement.setReverseReason(reason); if (user != null) settlement.setReversedBy(user.getId()); repository.save(settlement); @@ -192,12 +201,16 @@ public class CashSettlementApiResource { Long resolved = jdbcTemplate.queryForObject( "SELECT teller_id FROM m_cashiers WHERE id = ?", Long.class, settlement.getFromCashierId()); if (resolved != null) glTellerId = resolved; - } catch (Exception ignored) {} + } catch (Exception ignored) { + // intentionally ignored + } glDispatchService.allocateCashToCashier(glTellerId, settlement.getFromCashierId(), settlement.getSettlementAmount(), "INR", - LocalDate.now().format(DateTimeFormatter.ISO_LOCAL_DATE), + LocalDate.now(DateUtils.getDateTimeZoneOfTenant()).format(DateTimeFormatter.ISO_LOCAL_DATE), "Reversal of cash settlement #" + id + (reason != null ? ": " + reason : "")); - } catch (Exception ignored) {} + } catch (Exception ignored) { + // intentionally ignored + } } JsonObject result = new JsonObject(); @@ -214,7 +227,7 @@ public class CashSettlementApiResource { throw new PlatformDataIntegrityException("error.msg.cashsettlement.cashier.required", "cashierId query param is required."); } - final String settlementDate = (date != null && !date.isBlank()) ? date : LocalDate.now().toString(); + final String settlementDate = (date != null && !date.isBlank()) ? date : LocalDate.now(DateUtils.getDateTimeZoneOfTenant()).toString(); Integer count = jdbcTemplate.queryForObject( "SELECT COUNT(*) FROM m_cash_settlement WHERE from_cashier_id = ? AND settlement_date = CAST(? AS DATE) AND (is_reversed IS NULL OR is_reversed = false)", Integer.class, cashierId, settlementDate); diff --git a/fineract-provider/src/main/java/org/apache/fineract/portfolio/cashtransfer/api/CashTransferApiResource.java b/fineract-provider/src/main/java/org/apache/fineract/portfolio/cashtransfer/api/CashTransferApiResource.java index 359aad652..615b0623e 100644 --- a/fineract-provider/src/main/java/org/apache/fineract/portfolio/cashtransfer/api/CashTransferApiResource.java +++ b/fineract-provider/src/main/java/org/apache/fineract/portfolio/cashtransfer/api/CashTransferApiResource.java @@ -36,6 +36,7 @@ import org.springframework.stereotype.Component; import org.springframework.transaction.PlatformTransactionManager; import org.springframework.transaction.annotation.Transactional; import org.springframework.transaction.support.TransactionTemplate; +import org.apache.fineract.infrastructure.core.service.DateUtils; @Path("/v1/cashtransfer") @Component @@ -105,7 +106,7 @@ public class CashTransferApiResource { header.setToCashierId(toCashierId); header.setTransferAmount(total); header.setNote(note); - header.setCreatedAt(LocalDateTime.now()); + header.setCreatedAt(LocalDateTime.now(DateUtils.getDateTimeZoneOfTenant())); try { AppUser user = this.context.authenticatedUser(); if (user != null) { @@ -136,8 +137,10 @@ public class CashTransferApiResource { Long resolved = jdbcTemplate.queryForObject( "SELECT teller_id FROM m_cashiers WHERE id = ?", Long.class, toCashierId); if (resolved != null) glTellerId = resolved; - } catch (Exception ignored) {} - final LocalDate txnDate = transferDate != null ? transferDate : LocalDate.now(); + } catch (Exception ignored) { + // intentionally ignored + } + final LocalDate txnDate = transferDate != null ? transferDate : LocalDate.now(DateUtils.getDateTimeZoneOfTenant()); glDispatchService.allocateCashToCashier(glTellerId, toCashierId, total, currencyCode, txnDate.format(DateTimeFormatter.ISO_LOCAL_DATE), note != null ? note : ""); @@ -169,15 +172,19 @@ public class CashTransferApiResource { try { JsonObject json = JsonParser.parseString(body).getAsJsonObject(); reason = json.has("reason") ? json.get("reason").getAsString() : null; - } catch (Exception ignored) {} + } catch (Exception ignored) { + // intentionally ignored + } try { AppUser user = this.context.authenticatedUser(); transfer.setReversedBy(user.getId()); - } catch (Exception ignored) {} + } catch (Exception ignored) { + // intentionally ignored + } transfer.setIsReversed(true); - transfer.setReversedAt(java.time.LocalDateTime.now()); + transfer.setReversedAt(java.time.LocalDateTime.now(DateUtils.getDateTimeZoneOfTenant())); transfer.setReverseReason(reason); repository.save(transfer); @@ -188,12 +195,16 @@ public class CashTransferApiResource { Long resolved = jdbcTemplate.queryForObject( "SELECT teller_id FROM m_cashiers WHERE id = ?", Long.class, transfer.getToCashierId()); if (resolved != null) glTellerId = resolved; - } catch (Exception ignored) {} + } catch (Exception ignored) { + // intentionally ignored + } glDispatchService.settleCashFromCashier(glTellerId, transfer.getToCashierId(), transfer.getTransferAmount(), "INR", - java.time.LocalDate.now().format(DateTimeFormatter.ISO_LOCAL_DATE), + java.time.LocalDate.now(DateUtils.getDateTimeZoneOfTenant()).format(DateTimeFormatter.ISO_LOCAL_DATE), "Reversal of cash transfer #" + id + (reason != null ? ": " + reason : "")); - } catch (Exception ignored) {} + } catch (Exception ignored) { + // intentionally ignored + } } JsonObject result = new JsonObject(); diff --git a/fineract-provider/src/main/java/org/apache/fineract/portfolio/cashtransfer/api/CashierGlDenominationApiResource.java b/fineract-provider/src/main/java/org/apache/fineract/portfolio/cashtransfer/api/CashierGlDenominationApiResource.java index 57e7d361a..002638999 100644 --- a/fineract-provider/src/main/java/org/apache/fineract/portfolio/cashtransfer/api/CashierGlDenominationApiResource.java +++ b/fineract-provider/src/main/java/org/apache/fineract/portfolio/cashtransfer/api/CashierGlDenominationApiResource.java @@ -38,6 +38,7 @@ import org.apache.fineract.portfolio.denominationmaster.domain.SavingsTxnDenomin import org.apache.fineract.useradministration.domain.AppUser; import org.springframework.stereotype.Component; import org.springframework.transaction.annotation.Transactional; +import org.apache.fineract.infrastructure.core.service.DateUtils; /** * Records cashier denomination breakdown for GL account transactions (journal entries). @@ -90,7 +91,7 @@ public class CashierGlDenominationApiResource { final String txnDateStr = fromJsonHelper.extractStringNamed("txnDate", root); final LocalDate txnDate = (txnDateStr != null && !txnDateStr.isBlank()) ? LocalDate.parse(txnDateStr) - : LocalDate.now(); + : LocalDate.now(DateUtils.getDateTimeZoneOfTenant()); if (!fromJsonHelper.parameterExists("denominationBreakdown", root)) { return "{\"result\":\"skipped\"}"; @@ -109,7 +110,9 @@ public class CashierGlDenominationApiResource { officerId = user.getId(); officerUsername = user.getUsername(); } - } catch (final Exception ignored) {} + } catch (final Exception ignored) { + // intentionally ignored + } final String resolvedTxnType = (txnType != null && !txnType.isBlank()) ? txnType.toUpperCase() @@ -144,7 +147,7 @@ public class CashierGlDenominationApiResource { .count(count) .totalAmount(lineTotal) .txnDate(txnDate) - .createdAt(LocalDateTime.now()) + .createdAt(LocalDateTime.now(DateUtils.getDateTimeZoneOfTenant())) .txnType(resolvedTxnType) .officerId(officerId) .officerUsername(officerUsername) diff --git a/fineract-provider/src/main/java/org/apache/fineract/portfolio/cashtransfer/api/ShareCollectionApiResource.java b/fineract-provider/src/main/java/org/apache/fineract/portfolio/cashtransfer/api/ShareCollectionApiResource.java index c59def7ee..5e7d9c977 100644 --- a/fineract-provider/src/main/java/org/apache/fineract/portfolio/cashtransfer/api/ShareCollectionApiResource.java +++ b/fineract-provider/src/main/java/org/apache/fineract/portfolio/cashtransfer/api/ShareCollectionApiResource.java @@ -29,6 +29,7 @@ import org.springframework.dao.IncorrectResultSizeDataAccessException; import org.springframework.jdbc.core.JdbcTemplate; import org.springframework.stereotype.Component; import org.springframework.transaction.annotation.Transactional; +import org.apache.fineract.infrastructure.core.service.DateUtils; /** * Cashier Share Collection API — POST /v1/cashier/sharecollection @@ -131,7 +132,7 @@ public class ShareCollectionApiResource { final LocalDate entryDate; try { entryDate = transactionDateStr != null - ? LocalDate.parse(transactionDateStr) : LocalDate.now(); + ? LocalDate.parse(transactionDateStr) : LocalDate.now(DateUtils.getDateTimeZoneOfTenant()); } catch (DateTimeParseException e) { throw new PlatformDataIntegrityException( "error.msg.sharecollection.date.invalid", @@ -193,7 +194,7 @@ public class ShareCollectionApiResource { final String txnId = "SC-" + shareAccountId + "-" + System.currentTimeMillis(); final long userId = currentUser.getId(); final String collectorName = currentUser.getUsername(); - final LocalDateTime now = LocalDateTime.now(); + final LocalDateTime now = LocalDateTime.now(DateUtils.getDateTimeZoneOfTenant()); // ── Post GL journal entries ──────────────────────────────────────── // Dr Cash at Vault (SHARES_REFERENCE) = totalAmount diff --git a/fineract-provider/src/main/java/org/apache/fineract/portfolio/cfcfrms/api/CfcfrmsComplaintApiResource.java b/fineract-provider/src/main/java/org/apache/fineract/portfolio/cfcfrms/api/CfcfrmsComplaintApiResource.java index 3daf73e02..55ae18e7b 100644 --- a/fineract-provider/src/main/java/org/apache/fineract/portfolio/cfcfrms/api/CfcfrmsComplaintApiResource.java +++ b/fineract-provider/src/main/java/org/apache/fineract/portfolio/cfcfrms/api/CfcfrmsComplaintApiResource.java @@ -41,7 +41,6 @@ import org.apache.fineract.infrastructure.core.serialization.DefaultToApiJsonSer import org.apache.fineract.infrastructure.security.service.PlatformSecurityContext; import org.apache.fineract.portfolio.cfcfrms.data.ComplaintStatsData; import org.apache.fineract.portfolio.cfcfrms.data.ComplaintTicketData; -import org.apache.fineract.portfolio.cfcfrms.data.TimelineEventData; import org.apache.fineract.portfolio.cfcfrms.service.CfcfrmsComplaintService; import org.springframework.data.domain.Page; import org.springframework.data.domain.PageRequest; diff --git a/fineract-provider/src/main/java/org/apache/fineract/portfolio/cfcfrms/api/CfcfrmsSimulatorApiResource.java b/fineract-provider/src/main/java/org/apache/fineract/portfolio/cfcfrms/api/CfcfrmsSimulatorApiResource.java index a64fecca5..25674bc53 100644 --- a/fineract-provider/src/main/java/org/apache/fineract/portfolio/cfcfrms/api/CfcfrmsSimulatorApiResource.java +++ b/fineract-provider/src/main/java/org/apache/fineract/portfolio/cfcfrms/api/CfcfrmsSimulatorApiResource.java @@ -56,7 +56,7 @@ import org.springframework.stereotype.Component; * POST /v1/simulator/cfcfrms/verify-account – Verify account at bank * POST /v1/simulator/cfcfrms/verify-transaction – Verify transaction ref * - * --- STATUS & REPORTING --- + * --- STATUS & REPORTING --- * GET /v1/simulator/cfcfrms/complaint-status/{ref} – Complaint status from CFCFRMS side * GET /v1/simulator/cfcfrms/bank-performance – Bank performance metrics * diff --git a/fineract-provider/src/main/java/org/apache/fineract/portfolio/cfcfrms/seed/CfcfrmsDataSeeder.java b/fineract-provider/src/main/java/org/apache/fineract/portfolio/cfcfrms/seed/CfcfrmsDataSeeder.java index 851e9e734..febad64b7 100644 --- a/fineract-provider/src/main/java/org/apache/fineract/portfolio/cfcfrms/seed/CfcfrmsDataSeeder.java +++ b/fineract-provider/src/main/java/org/apache/fineract/portfolio/cfcfrms/seed/CfcfrmsDataSeeder.java @@ -36,6 +36,7 @@ import org.springframework.boot.context.event.ApplicationReadyEvent; import org.springframework.context.event.EventListener; import org.springframework.stereotype.Component; import org.springframework.transaction.annotation.Transactional; +import org.apache.fineract.infrastructure.core.service.DateUtils; /** * Seeds CFCFRMS complaint tickets, audit logs, and simulator logs on startup. @@ -59,7 +60,7 @@ public class CfcfrmsDataSeeder { } LOG.info("Seeding CFCFRMS complaint data..."); - final OffsetDateTime now = OffsetDateTime.now(); + final OffsetDateTime now = OffsetDateTime.now(DateUtils.getDateTimeZoneOfTenant()); // ─── 3 RECEIVED ────────────────────────────────────────────── seedTicket("TKT-20250318-001", "Rajesh Kumar Sharma", "9876543210", diff --git a/fineract-provider/src/main/java/org/apache/fineract/portfolio/cfcfrms/service/CfcfrmsComplaintServiceImpl.java b/fineract-provider/src/main/java/org/apache/fineract/portfolio/cfcfrms/service/CfcfrmsComplaintServiceImpl.java index 378f0eb35..1ebe927b3 100644 --- a/fineract-provider/src/main/java/org/apache/fineract/portfolio/cfcfrms/service/CfcfrmsComplaintServiceImpl.java +++ b/fineract-provider/src/main/java/org/apache/fineract/portfolio/cfcfrms/service/CfcfrmsComplaintServiceImpl.java @@ -46,6 +46,7 @@ import org.springframework.data.domain.Page; import org.springframework.data.domain.Pageable; import org.springframework.stereotype.Service; import org.springframework.transaction.annotation.Transactional; +import org.apache.fineract.infrastructure.core.service.DateUtils; @Service @RequiredArgsConstructor @@ -206,7 +207,7 @@ public class CfcfrmsComplaintServiceImpl implements CfcfrmsComplaintService { final Map result = new HashMap<>(); result.put("escalatedTo", nextIfsc); result.put("escalationRef", escalationRef); - result.put("timestamp", OffsetDateTime.now().toString()); + result.put("timestamp", OffsetDateTime.now(DateUtils.getDateTimeZoneOfTenant()).toString()); return result; } @@ -218,7 +219,7 @@ public class CfcfrmsComplaintServiceImpl implements CfcfrmsComplaintService { } private String generateTicketId() { - final String date = LocalDate.now().format(DateTimeFormatter.ofPattern("yyyyMMdd")); + final String date = LocalDate.now(DateUtils.getDateTimeZoneOfTenant()).format(DateTimeFormatter.ofPattern("yyyyMMdd")); final int seq = (int) (ticketRepository.count() + 1); return String.format("TKT-%s-%03d", date, seq); } diff --git a/fineract-provider/src/main/java/org/apache/fineract/portfolio/cfcfrms/service/CfcfrmsSimulatorServiceImpl.java b/fineract-provider/src/main/java/org/apache/fineract/portfolio/cfcfrms/service/CfcfrmsSimulatorServiceImpl.java index 20f2d1175..879f1c980 100644 --- a/fineract-provider/src/main/java/org/apache/fineract/portfolio/cfcfrms/service/CfcfrmsSimulatorServiceImpl.java +++ b/fineract-provider/src/main/java/org/apache/fineract/portfolio/cfcfrms/service/CfcfrmsSimulatorServiceImpl.java @@ -25,12 +25,10 @@ import java.time.LocalDate; import java.time.OffsetDateTime; import java.time.format.DateTimeFormatter; import java.util.ArrayList; -import java.util.HashMap; import java.util.LinkedHashMap; import java.util.List; import java.util.Map; import java.util.Random; -import java.util.UUID; import java.util.stream.Collectors; import lombok.RequiredArgsConstructor; import org.apache.fineract.portfolio.cfcfrms.data.CfcfrmsConstants; @@ -44,6 +42,7 @@ import org.slf4j.Logger; import org.slf4j.LoggerFactory; import org.springframework.stereotype.Service; import org.springframework.transaction.annotation.Transactional; +import org.apache.fineract.infrastructure.core.service.DateUtils; @Service @RequiredArgsConstructor @@ -76,7 +75,7 @@ public class CfcfrmsSimulatorServiceImpl implements CfcfrmsSimulatorService { final Map response = new LinkedHashMap<>(); response.put("cfcfrmsRef", cfcfrmsRef); response.put("ticketId", ticketData.getTicketId()); - response.put("pushedToBankAt", OffsetDateTime.now().toString()); + response.put("pushedToBankAt", OffsetDateTime.now(DateUtils.getDateTimeZoneOfTenant()).toString()); response.put("bankAcknowledged", true); response.put("message", "Complaint pushed to " + CfcfrmsConstants.BANK_IFSC + " successfully"); return response; @@ -85,7 +84,7 @@ public class CfcfrmsSimulatorServiceImpl implements CfcfrmsSimulatorService { @Override public Map pushHoldDirective(final JsonObject json) { final String cfcfrmsRef = getStringOrThrow(json, "cfcfrmsRef"); - final String directiveRef = "DIR-" + LocalDate.now().format(DateTimeFormatter.ofPattern("yyyyMMdd")) + final String directiveRef = "DIR-" + LocalDate.now(DateUtils.getDateTimeZoneOfTenant()).format(DateTimeFormatter.ofPattern("yyyyMMdd")) + "-" + String.format("%04d", RANDOM.nextInt(10000)); final String directiveType = getStringOrThrow(json, "directiveType"); @@ -112,7 +111,7 @@ public class CfcfrmsSimulatorServiceImpl implements CfcfrmsSimulatorService { response.put("directiveRef", directiveRef); response.put("status", "DIRECTIVE_SENT"); response.put("bankResponse", bankResponse); - response.put("timestamp", OffsetDateTime.now().toString()); + response.put("timestamp", OffsetDateTime.now(DateUtils.getDateTimeZoneOfTenant()).toString()); return response; } @@ -208,7 +207,7 @@ public class CfcfrmsSimulatorServiceImpl implements CfcfrmsSimulatorService { public Map receiveEscalation(final JsonObject json) { final String cfcfrmsRef = getStringOrThrow(json, "cfcfrmsRef"); final String ticketId = getStringOrThrow(json, "ticketId"); - final String escalationRef = "ESC-" + LocalDate.now().format(DateTimeFormatter.ofPattern("yyyy-MMdd")) + final String escalationRef = "ESC-" + LocalDate.now(DateUtils.getDateTimeZoneOfTenant()).format(DateTimeFormatter.ofPattern("yyyy-MMdd")) + "-" + String.format("%04d", RANDOM.nextInt(10000)); // Extract nextBank from fundsMovedTo @@ -268,7 +267,7 @@ public class CfcfrmsSimulatorServiceImpl implements CfcfrmsSimulatorService { final Map response = new LinkedHashMap<>(); response.put("transactionFound", true); response.put("transactionStatus", "COMPLETED"); - response.put("transactionTimestamp", OffsetDateTime.now().minusHours(2).toString()); + response.put("transactionTimestamp", OffsetDateTime.now(DateUtils.getDateTimeZoneOfTenant()).minusHours(2).toString()); response.put("senderAccount", json.has("accountNumber") ? json.get("accountNumber").getAsString() : "UNKNOWN"); response.put("receiverAccount", json.has("accountNumber") ? json.get("accountNumber").getAsString() : "UNKNOWN"); @@ -369,14 +368,14 @@ public class CfcfrmsSimulatorServiceImpl implements CfcfrmsSimulatorService { .setScale(1, java.math.RoundingMode.HALF_UP) + "%" : "0.0%"; response.put("tatComplianceRate", tatCompliance); - response.put("lastActivityAt", OffsetDateTime.now().toString()); + response.put("lastActivityAt", OffsetDateTime.now(DateUtils.getDateTimeZoneOfTenant()).toString()); return response; } // ── Helpers ── private String generateCfcfrmsRef() { - final String date = LocalDate.now().format(DateTimeFormatter.ofPattern("yyyy-MMdd")); + final String date = LocalDate.now(DateUtils.getDateTimeZoneOfTenant()).format(DateTimeFormatter.ofPattern("yyyy-MMdd")); return "CFCFRMS-" + date + "-" + String.format("%04d", RANDOM.nextInt(10000)); } diff --git a/fineract-provider/src/main/java/org/apache/fineract/portfolio/clearing/npci/service/NpciInwardPushService.java b/fineract-provider/src/main/java/org/apache/fineract/portfolio/clearing/npci/service/NpciInwardPushService.java index f6ae6838f..f3637cf92 100644 --- a/fineract-provider/src/main/java/org/apache/fineract/portfolio/clearing/npci/service/NpciInwardPushService.java +++ b/fineract-provider/src/main/java/org/apache/fineract/portfolio/clearing/npci/service/NpciInwardPushService.java @@ -201,7 +201,7 @@ public class NpciInwardPushService { final String presentingBranchCode = getString(instrument, "depositBranchCode"); item.recordInwardMeta(getString(instrument, "serialNumber"), presentingBranchCode, batch.getReturnTatDeadline()); - final Boolean instrumentStopPaymentFlag = instrument.has("stopPaymentFlag") && !instrument.get("stopPaymentFlag").isJsonNull() + final Boolean instrumentStopPaymentFlag = (instrument.has("stopPaymentFlag") && !instrument.get("stopPaymentFlag").isJsonNull()) ? instrument.get("stopPaymentFlag").getAsBoolean() : null; item.recordSourceDetails(getString(instrument, "ctsReferenceNumber"), instrumentStopPaymentFlag, diff --git a/fineract-provider/src/main/java/org/apache/fineract/portfolio/clerkdisbursement/api/ClerkDisbursementRequestApiResource.java b/fineract-provider/src/main/java/org/apache/fineract/portfolio/clerkdisbursement/api/ClerkDisbursementRequestApiResource.java index ad8d054c7..bbea5abf1 100644 --- a/fineract-provider/src/main/java/org/apache/fineract/portfolio/clerkdisbursement/api/ClerkDisbursementRequestApiResource.java +++ b/fineract-provider/src/main/java/org/apache/fineract/portfolio/clerkdisbursement/api/ClerkDisbursementRequestApiResource.java @@ -70,6 +70,7 @@ import org.apache.fineract.useradministration.domain.AppUser; import org.springframework.jdbc.core.JdbcTemplate; import org.springframework.stereotype.Component; import org.springframework.transaction.annotation.Transactional; +import org.apache.fineract.infrastructure.core.service.DateUtils; @Path("/v1/clerk/disbursement-requests") @Component @@ -383,7 +384,7 @@ public class ClerkDisbursementRequestApiResource { final JsonArray creditEntries = gson.fromJson(creditEntriesJson, JsonArray.class); final Object ptId = record.get("payment_type_id"); final String description = (String) record.get("description"); - final String txnDateStr = LocalDate.now().toString(); + final String txnDateStr = LocalDate.now(DateUtils.getDateTimeZoneOfTenant()).toString(); final Long sourceGlId = record.get("gl_account_id") != null ? ((Number) record.get("gl_account_id")).longValue() : null; @@ -556,7 +557,7 @@ public class ClerkDisbursementRequestApiResource { final String entryType = entry.has("accountType") ? entry.get("accountType").getAsString() : "SAVINGS"; final String acNo = entry.has("accountNo") ? entry.get("accountNo").getAsString() : "?"; final Long entryPtId = entry.has("paymentTypeId") && !entry.get("paymentTypeId").isJsonNull() - ? entry.get("paymentTypeId").getAsLong() + ? Long.valueOf(entry.get("paymentTypeId").getAsLong()) : (ptId != null ? ((Number) ptId).longValue() : null); if ("GL".equals(entryType)) { @@ -810,7 +811,7 @@ public class ClerkDisbursementRequestApiResource { ? req.get("currencyCode").getAsString() : "INR"; final String txnDateStr = req.has("transactionDate") && !req.get("transactionDate").isJsonNull() ? req.get("transactionDate").getAsString() - : LocalDate.now().format(DateTimeFormatter.ISO_LOCAL_DATE); + : LocalDate.now(DateUtils.getDateTimeZoneOfTenant()).format(DateTimeFormatter.ISO_LOCAL_DATE); final String description = req.has("description") && !req.get("description").isJsonNull() ? req.get("description").getAsString() : null; @@ -830,7 +831,6 @@ public class ClerkDisbursementRequestApiResource { // Validate all entries: savings/current only (no GL), savingsAccountId present, amount > 0 final Set drAccountIds = new LinkedHashSet<>(); - final Set crAccountIds = new LinkedHashSet<>(); for (final JsonObject e : drEntries) { final String acTyp = e.has("accountType") ? e.get("accountType").getAsString() : "SAVINGS"; @@ -858,7 +858,6 @@ public class ClerkDisbursementRequestApiResource { if (drAccountIds.contains(crId)) throw apiError(400, "Account " + (e.has("accountNo") ? e.get("accountNo").getAsString() : crId) + " cannot appear on both DR and CR sides of the same transfer."); - crAccountIds.add(crId); } // Validate balanced entry: total DR == total CR @@ -999,7 +998,7 @@ public class ClerkDisbursementRequestApiResource { * under concurrent inserts on the same date. */ private String generateBtVoucherNo(final long logId) { - return "BT" + LocalDate.now().format(DateTimeFormatter.ofPattern("yyMMdd")) + return "BT" + LocalDate.now(DateUtils.getDateTimeZoneOfTenant()).format(DateTimeFormatter.ofPattern("yyMMdd")) + String.format("%05d", logId); } @@ -1053,7 +1052,9 @@ public class ClerkDisbursementRequestApiResource { try { final Long txnIdLong = Long.parseLong(txnId); undoOps.add(() -> undoAccountTransaction(accountId, txnIdLong, isCurrentAccount)); - } catch (NumberFormatException ignored) {} + } catch (NumberFormatException ignored) { + // intentionally ignored + } } private void undoAccountTransaction(final Long accountId, final Long transactionId, @@ -1072,50 +1073,6 @@ public class ClerkDisbursementRequestApiResource { commandsSourceWritePlatformService.logCommandSource(cmd); } - private String executeSavingsDeposit( - final Long savingsAccountId, final BigDecimal amount, - final Long paymentTypeId, final String txnDateStr, final String note) { - - final String date = formatForFineract(txnDateStr); - final JsonObject payload = new JsonObject(); - payload.addProperty("locale", "en"); - payload.addProperty("dateFormat", "dd MMMM yyyy"); - payload.addProperty("transactionDate", date); - payload.addProperty("transactionAmount", amount); - if (paymentTypeId != null) payload.addProperty("paymentTypeId", paymentTypeId); - if (note != null && !note.isBlank()) payload.addProperty("note", note); - - final CommandWrapper cmd = new CommandWrapperBuilder() - .savingsAccountDeposit(savingsAccountId) - .withJson(payload.toString()) - .build(); - fineractRequestContextHolder.setAttribute(SynchronousCommandProcessingService.COMMAND_SOURCE_ID, null); - final CommandProcessingResult result = commandsSourceWritePlatformService.logCommandSource(cmd); - return result.getResourceId() != null ? result.getResourceId().toString() : null; - } - - private String executeCurrentAccountDeposit( - final Long currentAccountId, final BigDecimal amount, - final Long paymentTypeId, final String txnDateStr, final String note) { - - final String date = formatForFineract(txnDateStr); - final JsonObject payload = new JsonObject(); - payload.addProperty("locale", "en"); - payload.addProperty("dateFormat", "dd MMMM yyyy"); - payload.addProperty("transactionDate", date); - payload.addProperty("transactionAmount", amount); - if (paymentTypeId != null) payload.addProperty("paymentTypeId", paymentTypeId); - if (note != null && !note.isBlank()) payload.addProperty("note", note); - - final CommandWrapper cmd = new CommandWrapperBuilder() - .currentAccountDeposit(currentAccountId) - .withJson(payload.toString()) - .build(); - fineractRequestContextHolder.setAttribute(SynchronousCommandProcessingService.COMMAND_SOURCE_ID, null); - final CommandProcessingResult result = commandsSourceWritePlatformService.logCommandSource(cmd); - return result.getResourceId() != null ? result.getResourceId().toString() : null; - } - private boolean isCurrentAccountById(final Long accountId) { try { final Integer count = jdbcTemplate.queryForObject( @@ -1131,7 +1088,7 @@ public class ClerkDisbursementRequestApiResource { final LocalDate ld = LocalDate.parse(isoDate, DateTimeFormatter.ISO_LOCAL_DATE); return ld.format(DateTimeFormatter.ofPattern("dd MMMM yyyy")); } catch (Exception e) { - return LocalDate.now().format(DateTimeFormatter.ofPattern("dd MMMM yyyy")); + return LocalDate.now(DateUtils.getDateTimeZoneOfTenant()).format(DateTimeFormatter.ofPattern("dd MMMM yyyy")); } } @@ -1380,7 +1337,7 @@ public class ClerkDisbursementRequestApiResource { ? (BigDecimal) accts.get(0).get("account_balance_derived") : BigDecimal.ZERO; final java.sql.Date sqlDate = java.sql.Date.valueOf(txnDate); - final OffsetDateTime now = OffsetDateTime.now(); + final OffsetDateTime now = OffsetDateTime.now(DateUtils.getDateTimeZoneOfTenant()); final String refNo = UUID.randomUUID().toString().replace("-", "").substring(0, 20); final Long userId = currentUser.getId(); @@ -1534,7 +1491,7 @@ public class ClerkDisbursementRequestApiResource { + ". Available: " + currentBalance + ", Requested: " + amount); final java.sql.Date sqlDate = java.sql.Date.valueOf(txnDate); - final OffsetDateTime now = OffsetDateTime.now(); + final OffsetDateTime now = OffsetDateTime.now(DateUtils.getDateTimeZoneOfTenant()); final String refNo = UUID.randomUUID().toString().replace("-", "").substring(0, 20); final Long userId = currentUser.getId(); diff --git a/fineract-provider/src/main/java/org/apache/fineract/portfolio/clerkwithdrawal/api/ClerkWithdrawalRequestApiResource.java b/fineract-provider/src/main/java/org/apache/fineract/portfolio/clerkwithdrawal/api/ClerkWithdrawalRequestApiResource.java index bd7055cc6..813e80602 100644 --- a/fineract-provider/src/main/java/org/apache/fineract/portfolio/clerkwithdrawal/api/ClerkWithdrawalRequestApiResource.java +++ b/fineract-provider/src/main/java/org/apache/fineract/portfolio/clerkwithdrawal/api/ClerkWithdrawalRequestApiResource.java @@ -59,6 +59,9 @@ import org.apache.fineract.useradministration.domain.AppUser; import org.springframework.jdbc.core.JdbcTemplate; import org.springframework.stereotype.Component; import org.springframework.transaction.annotation.Transactional; +import org.apache.fineract.infrastructure.core.service.DateUtils; +import com.google.common.collect.Iterables; +import com.google.common.base.Splitter; @Path("/v1/clerk/withdrawal-requests") @Component @@ -437,7 +440,7 @@ public class ClerkWithdrawalRequestApiResource { final BigDecimal amount = new BigDecimal(record.get("amount").toString()); final Object ptId = record.get("payment_type_id"); final Object txnDateObj = record.get("txn_date"); - final String txnDateStr = txnDateObj != null ? txnDateObj.toString().split(" ")[0] : null; + final String txnDateStr = txnDateObj != null ? Iterables.get(Splitter.on(' ').split(txnDateObj.toString()), 0) : null; final String description = (String) record.get("description"); String txnId = null; @@ -713,7 +716,7 @@ public class ClerkWithdrawalRequestApiResource { final Long savingsAccountId, final BigDecimal amount, final Object paymentTypeId, final String txnDateStr, final String note) { - final String today = LocalDate.now().format(DateTimeFormatter.ofPattern("dd MMMM yyyy")); + final String today = LocalDate.now(DateUtils.getDateTimeZoneOfTenant()).format(DateTimeFormatter.ofPattern("dd MMMM yyyy")); final String date = txnDateStr != null && !txnDateStr.isBlank() ? formatForFineract(txnDateStr) : today; final JsonObject payload = new JsonObject(); @@ -741,7 +744,7 @@ public class ClerkWithdrawalRequestApiResource { final Long currentAccountId, final BigDecimal amount, final Object paymentTypeId, final String txnDateStr, final String note) { - final String today = LocalDate.now().format(DateTimeFormatter.ofPattern("dd MMMM yyyy")); + final String today = LocalDate.now(DateUtils.getDateTimeZoneOfTenant()).format(DateTimeFormatter.ofPattern("dd MMMM yyyy")); final String date = txnDateStr != null && !txnDateStr.isBlank() ? formatForFineract(txnDateStr) : today; final JsonObject payload = new JsonObject(); @@ -780,7 +783,7 @@ public class ClerkWithdrawalRequestApiResource { final LocalDate ld = LocalDate.parse(isoDate, DateTimeFormatter.ISO_LOCAL_DATE); return ld.format(DateTimeFormatter.ofPattern("dd MMMM yyyy")); } catch (Exception e) { - return LocalDate.now().format(DateTimeFormatter.ofPattern("dd MMMM yyyy")); + return LocalDate.now(DateUtils.getDateTimeZoneOfTenant()).format(DateTimeFormatter.ofPattern("dd MMMM yyyy")); } } diff --git a/fineract-provider/src/main/java/org/apache/fineract/portfolio/client/api/ClientKycApiResource.java b/fineract-provider/src/main/java/org/apache/fineract/portfolio/client/api/ClientKycApiResource.java index 46d5add4b..9b406eec8 100644 --- a/fineract-provider/src/main/java/org/apache/fineract/portfolio/client/api/ClientKycApiResource.java +++ b/fineract-provider/src/main/java/org/apache/fineract/portfolio/client/api/ClientKycApiResource.java @@ -39,6 +39,8 @@ import jakarta.ws.rs.core.MediaType; import java.io.InputStream; import org.glassfish.jersey.media.multipart.FormDataContentDisposition; import org.glassfish.jersey.media.multipart.FormDataParam; +import java.time.LocalDate; +import java.time.Period; import java.util.ArrayList; import java.util.LinkedHashMap; import java.util.List; @@ -158,7 +160,13 @@ public class ClientKycApiResource { template.put("clientTypeName", clientTypeName); template.put("legalFormId", legalFormId); - template.put("requiredDocuments", getRequiredDocuments(clientTypeName, legalFormId)); + // Minor detection mirrors the frontend's own rule (age < 10) so the document list + // served here stays consistent with what the UI computes from the same date of birth. + final LocalDate dateOfBirth = client.dateOfBirth(); + final boolean isMinor = dateOfBirth != null && Period.between(dateOfBirth, LocalDate.now()).getYears() < 10; + template.put("isMinor", isMinor); + + template.put("requiredDocuments", getRequiredDocuments(clientTypeName, legalFormId, isMinor)); return toApiJsonSerializer.serialize(template); } @@ -166,11 +174,21 @@ public class ClientKycApiResource { /** * Returns required KYC documents based on client type (RBI Master Direction on KYC). */ - private List> getRequiredDocuments(final String clientTypeName, final Integer legalFormId) { + private List> getRequiredDocuments(final String clientTypeName, final Integer legalFormId, + final boolean isMinor) { final List> docs = new ArrayList<>(); // Individual types (legalFormId=1) if (legalFormId != null && legalFormId == 1) { + if (isMinor) { + // Minors cannot hold PAN, Voter ID, Driving Licence or an NREGA job card — RBI + // accepts Aadhaar, Passport, Birth Certificate or School ID Card instead. + docs.add(doc("Aadhaar Card", "AADHAAR", true)); + docs.add(doc("Birth Certificate", "BIRTH_CERTIFICATE", false)); + docs.add(doc("School ID Card", "SCHOOL_ID_CARD", false)); + docs.add(doc("Passport", "PASSPORT", false)); + return docs; + } docs.add(doc("Aadhaar Card", "AADHAAR", true)); docs.add(doc("PAN Card", "PAN", true)); docs.add(doc("Voter ID", "VOTER_ID", false)); diff --git a/fineract-provider/src/main/java/org/apache/fineract/portfolio/client/ckyc/DummyCkycSftpUploadServiceImpl.java b/fineract-provider/src/main/java/org/apache/fineract/portfolio/client/ckyc/DummyCkycSftpUploadServiceImpl.java index 2a3facfbc..021ee4fa9 100644 --- a/fineract-provider/src/main/java/org/apache/fineract/portfolio/client/ckyc/DummyCkycSftpUploadServiceImpl.java +++ b/fineract-provider/src/main/java/org/apache/fineract/portfolio/client/ckyc/DummyCkycSftpUploadServiceImpl.java @@ -24,6 +24,7 @@ import java.util.concurrent.atomic.AtomicLong; import lombok.extern.slf4j.Slf4j; import org.apache.fineract.portfolio.client.domain.ClientKyc; import org.springframework.stereotype.Service; +import org.apache.fineract.infrastructure.core.service.DateUtils; /** * Dummy / stub implementation of {@link CkycSftpUploadService}. @@ -60,7 +61,7 @@ public class DummyCkycSftpUploadServiceImpl implements CkycSftpUploadService { final String ckycNumber = generateCkycNumber(kyc.getClient().getId()); final String batchId = generateBatchId(); - final LocalDate today = LocalDate.now(); + final LocalDate today = LocalDate.now(DateUtils.getDateTimeZoneOfTenant()); return CkycUploadResult.builder() .ckycNumber(ckycNumber) @@ -82,7 +83,7 @@ public class DummyCkycSftpUploadServiceImpl implements CkycSftpUploadService { return CkycUploadResult.builder() .status("FAILED") .remarks("Uploaded file is not a valid ZIP archive (bad magic bytes).") - .uploadedOn(LocalDate.now()) + .uploadedOn(LocalDate.now(DateUtils.getDateTimeZoneOfTenant())) .build(); } @@ -92,7 +93,7 @@ public class DummyCkycSftpUploadServiceImpl implements CkycSftpUploadService { return CkycUploadResult.builder() .ckycNumber(ckycNumber) .batchId(batchId) - .uploadedOn(LocalDate.now()) + .uploadedOn(LocalDate.now(DateUtils.getDateTimeZoneOfTenant())) .status("SUCCESS") .remarks("Dummy CKYC ZIP upload accepted (" + zipBytes.length + " bytes). " + "Replace with real CERSAI SFTP integration before go-live.") @@ -112,7 +113,7 @@ public class DummyCkycSftpUploadServiceImpl implements CkycSftpUploadService { } private String generateBatchId() { - return "DUMMYCKYC-" + BATCH_ID_FORMAT.format(LocalDate.now()) + "-" + return "DUMMYCKYC-" + BATCH_ID_FORMAT.format(LocalDate.now(DateUtils.getDateTimeZoneOfTenant())) + "-" + String.format("%06d", BATCH_COUNTER.getAndIncrement()); } } diff --git a/fineract-provider/src/main/java/org/apache/fineract/portfolio/client/ckyc/service/CkycBatchBuilderServiceImpl.java b/fineract-provider/src/main/java/org/apache/fineract/portfolio/client/ckyc/service/CkycBatchBuilderServiceImpl.java index f90a9d1a0..2ce0fc805 100644 --- a/fineract-provider/src/main/java/org/apache/fineract/portfolio/client/ckyc/service/CkycBatchBuilderServiceImpl.java +++ b/fineract-provider/src/main/java/org/apache/fineract/portfolio/client/ckyc/service/CkycBatchBuilderServiceImpl.java @@ -50,6 +50,7 @@ import org.apache.fineract.portfolio.client.ckyc.domain.CkycBatchRepository; import org.springframework.jdbc.core.JdbcTemplate; import org.springframework.stereotype.Service; import org.springframework.transaction.annotation.Transactional; +import org.apache.fineract.infrastructure.core.service.DateUtils; @Slf4j @Service @@ -86,11 +87,11 @@ public class CkycBatchBuilderServiceImpl implements CkycBatchBuilderService { throw new IllegalArgumentException("clientIds must not be empty"); } - final LocalDate today = LocalDate.now(); + final LocalDate today = LocalDate.now(DateUtils.getDateTimeZoneOfTenant()); final int seq = nextBatchSequenceForToday(today); final String batchId = "BATCH-" + BATCH_ID_FMT.format(today) + "-" + String.format("%03d", seq); // ZIP filename: "CERSAI-ZIP-.zip" — hyphen-separated per spec. - final String filename = "CERSAI-ZIP-" + ZIP_NAME_TS_FMT.format(java.time.LocalDateTime.now()) + ".zip"; + final String filename = "CERSAI-ZIP-" + ZIP_NAME_TS_FMT.format(java.time.LocalDateTime.now(DateUtils.getDateTimeZoneOfTenant())) + ".zip"; final List manifest = new ArrayList<>(); final ByteArrayOutputStream zipBytesOut = new ByteArrayOutputStream(); diff --git a/fineract-provider/src/main/java/org/apache/fineract/portfolio/client/ckyc/service/CkycReportsReadServiceImpl.java b/fineract-provider/src/main/java/org/apache/fineract/portfolio/client/ckyc/service/CkycReportsReadServiceImpl.java index 12ff63362..498260139 100644 --- a/fineract-provider/src/main/java/org/apache/fineract/portfolio/client/ckyc/service/CkycReportsReadServiceImpl.java +++ b/fineract-provider/src/main/java/org/apache/fineract/portfolio/client/ckyc/service/CkycReportsReadServiceImpl.java @@ -26,7 +26,6 @@ import java.nio.charset.StandardCharsets; import java.time.LocalDate; import java.time.format.DateTimeFormatter; import java.util.ArrayList; -import java.util.HashMap; import java.util.LinkedHashMap; import java.util.List; import java.util.Map; @@ -36,6 +35,7 @@ import org.apache.fineract.infrastructure.core.service.database.DatabaseSpecific import org.glassfish.jersey.media.multipart.FormDataContentDisposition; import org.springframework.jdbc.core.JdbcTemplate; import org.springframework.stereotype.Service; +import org.apache.fineract.infrastructure.core.service.DateUtils; @Slf4j @Service @@ -219,6 +219,7 @@ public class CkycReportsReadServiceImpl implements CkycReportsReadService { // ===== Customer List ===== @Override + @SuppressWarnings("StringSplitter") public Map listCustomers(String name, String branch, String city, String gender, String state, String dateFrom, String dateTo, Integer page, Integer pageSize, String sort) { @@ -375,13 +376,13 @@ public class CkycReportsReadServiceImpl implements CkycReportsReadService { switch (format != null ? format.toLowerCase() : "csv") { case "txt": contentType = "text/plain"; - filename = "ckyc_export_" + LocalDate.now() + ".txt"; + filename = "ckyc_export_" + LocalDate.now(DateUtils.getDateTimeZoneOfTenant()) + ".txt"; content = buildPipeDelimitedExport(rows); break; case "csv": default: contentType = "text/csv"; - filename = "ckyc_export_" + LocalDate.now() + ".csv"; + filename = "ckyc_export_" + LocalDate.now(DateUtils.getDateTimeZoneOfTenant()) + ".csv"; content = buildCsvExport(rows); break; } @@ -431,7 +432,7 @@ public class CkycReportsReadServiceImpl implements CkycReportsReadService { errors.add("Parse error: " + e.getMessage()); } - String fileId = "UPLOAD-" + LocalDate.now().format(DateTimeFormatter.ofPattern("yyyyMMdd")) + "-" + System.currentTimeMillis(); + String fileId = "UPLOAD-" + LocalDate.now(DateUtils.getDateTimeZoneOfTenant()).format(DateTimeFormatter.ofPattern("yyyyMMdd")) + "-" + System.currentTimeMillis(); result.put("fileId", fileId); result.put("totalRecords", totalRecords); result.put("customers", customers); @@ -453,9 +454,9 @@ public class CkycReportsReadServiceImpl implements CkycReportsReadService { @Override public Response generateCkycFile(Map request) { // Placeholder — delegates to CkycBatchBuilderService for actual ZIP generation - String content = "10|BATCH|" + LocalDate.now() + "|0\n"; + String content = "10|BATCH|" + LocalDate.now(DateUtils.getDateTimeZoneOfTenant()) + "|0\n"; return Response.ok(content.getBytes(StandardCharsets.UTF_8), "text/plain") - .header("Content-Disposition", "attachment; filename=\"ckyc_submission_" + LocalDate.now() + ".txt\"") + .header("Content-Disposition", "attachment; filename=\"ckyc_submission_" + LocalDate.now(DateUtils.getDateTimeZoneOfTenant()) + ".txt\"") .build(); } @@ -572,7 +573,7 @@ public class CkycReportsReadServiceImpl implements CkycReportsReadService { private String buildPipeDelimitedExport(List> rows) { StringBuilder sb = new StringBuilder(); - sb.append("10|CKYC_EXPORT|").append(LocalDate.now()).append("|").append(rows.size()).append("\n"); + sb.append("10|CKYC_EXPORT|").append(LocalDate.now(DateUtils.getDateTimeZoneOfTenant())).append("|").append(rows.size()).append("\n"); for (Map row : rows) { sb.append("20|"); sb.append(val(row.get("cif"))).append("|"); diff --git a/fineract-provider/src/main/java/org/apache/fineract/portfolio/client/ckyc/service/DummyCkycBatchSftpUploadServiceImpl.java b/fineract-provider/src/main/java/org/apache/fineract/portfolio/client/ckyc/service/DummyCkycBatchSftpUploadServiceImpl.java index e4f7635ea..f212130d9 100644 --- a/fineract-provider/src/main/java/org/apache/fineract/portfolio/client/ckyc/service/DummyCkycBatchSftpUploadServiceImpl.java +++ b/fineract-provider/src/main/java/org/apache/fineract/portfolio/client/ckyc/service/DummyCkycBatchSftpUploadServiceImpl.java @@ -47,6 +47,7 @@ import org.springframework.beans.factory.annotation.Value; import org.springframework.jdbc.core.JdbcTemplate; import org.springframework.stereotype.Service; import org.springframework.transaction.annotation.Transactional; +import org.apache.fineract.infrastructure.core.service.DateUtils; /** * Dummy / stub implementation of {@link CkycBatchSftpUploadService}. @@ -149,10 +150,10 @@ public class DummyCkycBatchSftpUploadServiceImpl implements CkycBatchSftpUploadS } // 3) Build the ACK reference and timestamp - final LocalDateTime now = LocalDateTime.now(); + final LocalDateTime now = LocalDateTime.now(DateUtils.getDateTimeZoneOfTenant()); final String ackReference = "CERSAI-ACK-" + ACK_TS_FMT.format(now) + "-" + String.format("%04d", ACK_COUNTER.getAndIncrement()); - final LocalDate today = LocalDate.now(); + final LocalDate today = LocalDate.now(DateUtils.getDateTimeZoneOfTenant()); // 4) Parse manifest → generate a CKYC number per included client → persist on m_client_kyc final List> perClient = new ArrayList<>(); diff --git a/fineract-provider/src/main/java/org/apache/fineract/portfolio/client/contactverification/api/ClientContactVerificationApiResource.java b/fineract-provider/src/main/java/org/apache/fineract/portfolio/client/contactverification/api/ClientContactVerificationApiResource.java index 9293cbf2c..eaf333fc3 100644 --- a/fineract-provider/src/main/java/org/apache/fineract/portfolio/client/contactverification/api/ClientContactVerificationApiResource.java +++ b/fineract-provider/src/main/java/org/apache/fineract/portfolio/client/contactverification/api/ClientContactVerificationApiResource.java @@ -18,6 +18,8 @@ */ package org.apache.fineract.portfolio.client.contactverification.api; +import com.google.common.base.Splitter; +import com.google.common.collect.Iterables; import com.google.gson.JsonObject; import com.google.gson.JsonParser; import io.swagger.v3.oas.annotations.Operation; @@ -152,7 +154,7 @@ public class ClientContactVerificationApiResource { } final String fwd = req.getHeader("X-Forwarded-For"); if (fwd != null && !fwd.isBlank()) { - return fwd.split(",")[0].trim(); + return Iterables.get(Splitter.on(',').split(fwd), 0).trim(); } return req.getRemoteAddr(); } diff --git a/fineract-provider/src/main/java/org/apache/fineract/portfolio/client/contactverification/api/ClientCreationContactVerificationApiResource.java b/fineract-provider/src/main/java/org/apache/fineract/portfolio/client/contactverification/api/ClientCreationContactVerificationApiResource.java index 1523975d4..c3ad7832f 100644 --- a/fineract-provider/src/main/java/org/apache/fineract/portfolio/client/contactverification/api/ClientCreationContactVerificationApiResource.java +++ b/fineract-provider/src/main/java/org/apache/fineract/portfolio/client/contactverification/api/ClientCreationContactVerificationApiResource.java @@ -18,6 +18,8 @@ */ package org.apache.fineract.portfolio.client.contactverification.api; +import com.google.common.base.Splitter; +import com.google.common.collect.Iterables; import com.google.gson.JsonObject; import com.google.gson.JsonParser; import io.swagger.v3.oas.annotations.Operation; @@ -147,7 +149,7 @@ public class ClientCreationContactVerificationApiResource { } final String fwd = req.getHeader("X-Forwarded-For"); if (fwd != null && !fwd.isBlank()) { - return fwd.split(",")[0].trim(); + return Iterables.get(Splitter.on(',').split(fwd), 0).trim(); } return req.getRemoteAddr(); } diff --git a/fineract-provider/src/main/java/org/apache/fineract/portfolio/client/contactverification/service/ClientContactOtpServiceImpl.java b/fineract-provider/src/main/java/org/apache/fineract/portfolio/client/contactverification/service/ClientContactOtpServiceImpl.java index c5b06c825..f207434ac 100644 --- a/fineract-provider/src/main/java/org/apache/fineract/portfolio/client/contactverification/service/ClientContactOtpServiceImpl.java +++ b/fineract-provider/src/main/java/org/apache/fineract/portfolio/client/contactverification/service/ClientContactOtpServiceImpl.java @@ -53,6 +53,7 @@ import org.springframework.transaction.annotation.Transactional; import org.springframework.web.client.HttpClientErrorException; import org.springframework.web.client.HttpServerErrorException; import org.springframework.web.client.RestTemplate; +import org.apache.fineract.infrastructure.core.service.DateUtils; /** * See {@link ClientContactOtpService}. Deliberately does NOT touch {@code LoginOtpServiceImpl} / @@ -209,7 +210,7 @@ public class ClientContactOtpServiceImpl implements ClientContactOtpService { log.setExpiresAt(OffsetDateTime.now(ZoneOffset.UTC).plusSeconds(ttlSeconds)); final String html = emailTemplateService.renderOtp(null, otp, validityMinutes); - final String subject = "Your OTP for Contact Verification - " + appName + " (" + LocalDateTime.now().format(SUBJECT_TIMESTAMP) + final String subject = "Your OTP for Contact Verification - " + appName + " (" + LocalDateTime.now(DateUtils.getDateTimeZoneOfTenant()).format(SUBJECT_TIMESTAMP) + ")"; final boolean sent = emailSenderService.sendHtml(emailAddress, subject, html); diff --git a/fineract-provider/src/main/java/org/apache/fineract/portfolio/client/mapper/ClientMapper.java b/fineract-provider/src/main/java/org/apache/fineract/portfolio/client/mapper/ClientMapper.java index 38aadc990..39f057b15 100644 --- a/fineract-provider/src/main/java/org/apache/fineract/portfolio/client/mapper/ClientMapper.java +++ b/fineract-provider/src/main/java/org/apache/fineract/portfolio/client/mapper/ClientMapper.java @@ -34,6 +34,7 @@ import org.mapstruct.Mapper; import org.mapstruct.Mapping; import org.mapstruct.MappingTarget; import org.mapstruct.Named; +import org.apache.fineract.infrastructure.core.service.DateUtils; @Mapper(config = MapstructMapperConfig.class) public interface ClientMapper { @@ -271,7 +272,7 @@ public interface ClientMapper { default void computeAge(Client source, @MappingTarget ClientData target) { final LocalDate dob = source.getDateOfBirth(); if (dob != null) { - final Period age = Period.between(dob, LocalDate.now()); + final Period age = Period.between(dob, LocalDate.now(DateUtils.getDateTimeZoneOfTenant())); target.setAgeYears(age.getYears()); target.setAgeMonths(age.getMonths()); target.setAgeDays(age.getDays()); diff --git a/fineract-provider/src/main/java/org/apache/fineract/portfolio/client/service/CifNumberGenerator.java b/fineract-provider/src/main/java/org/apache/fineract/portfolio/client/service/CifNumberGenerator.java index b54290143..c02688dc9 100644 --- a/fineract-provider/src/main/java/org/apache/fineract/portfolio/client/service/CifNumberGenerator.java +++ b/fineract-provider/src/main/java/org/apache/fineract/portfolio/client/service/CifNumberGenerator.java @@ -25,6 +25,7 @@ import org.apache.fineract.portfolio.client.domain.Client; import org.apache.fineract.portfolio.client.domain.ClientRepository; import org.apache.fineract.portfolio.client.domain.LegalForm; import org.springframework.stereotype.Component; +import org.apache.fineract.infrastructure.core.service.DateUtils; /** * Generates CIF numbers in the format TTYYYYNNNNNN: @@ -90,6 +91,6 @@ public class CifNumberGenerator { private int resolveYear(final Client client) { final LocalDate submittedOn = client.getSubmittedOnDate(); - return (submittedOn != null ? submittedOn : LocalDate.now()).getYear(); + return (submittedOn != null ? submittedOn : LocalDate.now(DateUtils.getDateTimeZoneOfTenant())).getYear(); } } diff --git a/fineract-provider/src/main/java/org/apache/fineract/portfolio/client/service/ClientChangeNotificationServiceImpl.java b/fineract-provider/src/main/java/org/apache/fineract/portfolio/client/service/ClientChangeNotificationServiceImpl.java index baa4dc4a4..2c8af5d72 100644 --- a/fineract-provider/src/main/java/org/apache/fineract/portfolio/client/service/ClientChangeNotificationServiceImpl.java +++ b/fineract-provider/src/main/java/org/apache/fineract/portfolio/client/service/ClientChangeNotificationServiceImpl.java @@ -30,6 +30,7 @@ import org.slf4j.LoggerFactory; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.beans.factory.annotation.Value; import org.springframework.stereotype.Service; +import org.apache.fineract.infrastructure.core.service.DateUtils; /** * See {@link ClientChangeNotificationService}. @@ -88,7 +89,7 @@ public class ClientChangeNotificationServiceImpl implements ClientChangeNotifica final String alertTitle = fieldLabel + " Updated"; final String alertMessage = "Your " + fieldLabel.toLowerCase() + " on file was changed from " + describeForDisplay(fieldLabel, oldValue) + " to " + describeForDisplay(fieldLabel, newValue) + " on " - + LocalDateTime.now().format(TIMESTAMP) + ". If you did not authorize this change, please contact us immediately."; + + LocalDateTime.now(DateUtils.getDateTimeZoneOfTenant()).format(TIMESTAMP) + ". If you did not authorize this change, please contact us immediately."; final String html = emailTemplateService.renderAlert(recipientName, alertTitle, alertMessage); final String subject = alertTitle + " - " + appName; diff --git a/fineract-provider/src/main/java/org/apache/fineract/portfolio/client/service/ClientReadPlatformServiceImpl.java b/fineract-provider/src/main/java/org/apache/fineract/portfolio/client/service/ClientReadPlatformServiceImpl.java index d1bd60de7..66f2c5f83 100644 --- a/fineract-provider/src/main/java/org/apache/fineract/portfolio/client/service/ClientReadPlatformServiceImpl.java +++ b/fineract-provider/src/main/java/org/apache/fineract/portfolio/client/service/ClientReadPlatformServiceImpl.java @@ -63,6 +63,7 @@ import org.springframework.dao.EmptyResultDataAccessException; import org.springframework.jdbc.core.JdbcTemplate; import org.springframework.jdbc.core.RowMapper; import org.springframework.stereotype.Service; +import org.apache.fineract.infrastructure.core.service.DateUtils; @Service @RequiredArgsConstructor @@ -488,7 +489,7 @@ public class ClientReadPlatformServiceImpl implements ClientReadPlatformService Integer ageMonths1 = null; Integer ageDays1 = null; if (dateOfBirth != null) { - final Period age = Period.between(dateOfBirth, LocalDate.now()); + final Period age = Period.between(dateOfBirth, LocalDate.now(DateUtils.getDateTimeZoneOfTenant())); ageYears1 = age.getYears(); ageMonths1 = age.getMonths(); ageDays1 = age.getDays(); @@ -879,7 +880,7 @@ public class ClientReadPlatformServiceImpl implements ClientReadPlatformService Integer ageMonths = null; Integer ageDays = null; if (dateOfBirth != null) { - final Period age = Period.between(dateOfBirth, LocalDate.now()); + final Period age = Period.between(dateOfBirth, LocalDate.now(DateUtils.getDateTimeZoneOfTenant())); ageYears = age.getYears(); ageMonths = age.getMonths(); ageDays = age.getDays(); diff --git a/fineract-provider/src/main/java/org/apache/fineract/portfolio/client/service/ClientWritePlatformServiceJpaRepositoryImpl.java b/fineract-provider/src/main/java/org/apache/fineract/portfolio/client/service/ClientWritePlatformServiceJpaRepositoryImpl.java index 3f40f928c..ecd05d910 100644 --- a/fineract-provider/src/main/java/org/apache/fineract/portfolio/client/service/ClientWritePlatformServiceJpaRepositoryImpl.java +++ b/fineract-provider/src/main/java/org/apache/fineract/portfolio/client/service/ClientWritePlatformServiceJpaRepositoryImpl.java @@ -1786,6 +1786,7 @@ public class ClientWritePlatformServiceJpaRepositoryImpl implements ClientWriteP * verifying KYC names against ID documents). Null / blank → null so we don't accidentally * persist an empty string in place of an unset field. */ + @SuppressWarnings("StringSplitter") private static String toTitleCase(final String raw) { if (raw == null) { return null; diff --git a/fineract-provider/src/main/java/org/apache/fineract/portfolio/ctsclearing/service/CtsClearingWritePlatformServiceImpl.java b/fineract-provider/src/main/java/org/apache/fineract/portfolio/ctsclearing/service/CtsClearingWritePlatformServiceImpl.java index aa91fbebe..1dec7cda0 100644 --- a/fineract-provider/src/main/java/org/apache/fineract/portfolio/ctsclearing/service/CtsClearingWritePlatformServiceImpl.java +++ b/fineract-provider/src/main/java/org/apache/fineract/portfolio/ctsclearing/service/CtsClearingWritePlatformServiceImpl.java @@ -582,21 +582,6 @@ public class CtsClearingWritePlatformServiceImpl implements CtsClearingWritePlat } } - /** SHA-256 hex digest of the given content, used as a visible integrity fingerprint in the CTS header. */ - private String sha256Hex(final String content) { - try { - final java.security.MessageDigest digest = java.security.MessageDigest.getInstance("SHA-256"); - final byte[] hash = digest.digest(content.getBytes(java.nio.charset.StandardCharsets.UTF_8)); - final StringBuilder hex = new StringBuilder(); - for (final byte b : hash) { - hex.append(String.format("%02x", b)); - } - return hex.toString(); - } catch (final java.security.NoSuchAlgorithmException e) { - throw new IllegalStateException("SHA-256 is not available", e); - } - } - /** Masks all but the last 4 characters of an account number (matches the CTS file convention of not exposing full numbers). */ private String maskAccountNumber(final String accountNumber) { if (accountNumber == null || accountNumber.isBlank()) { diff --git a/fineract-provider/src/main/java/org/apache/fineract/portfolio/denominationmaster/api/DenominationMasterApiResource.java b/fineract-provider/src/main/java/org/apache/fineract/portfolio/denominationmaster/api/DenominationMasterApiResource.java index 36166bffa..ce5115817 100644 --- a/fineract-provider/src/main/java/org/apache/fineract/portfolio/denominationmaster/api/DenominationMasterApiResource.java +++ b/fineract-provider/src/main/java/org/apache/fineract/portfolio/denominationmaster/api/DenominationMasterApiResource.java @@ -26,6 +26,7 @@ import org.apache.fineract.portfolio.denominationmaster.domain.DenominationMaste import org.apache.fineract.portfolio.denominationmaster.domain.DenominationMasterRepository; import org.apache.fineract.useradministration.domain.AppUser; import org.springframework.stereotype.Component; +import org.apache.fineract.infrastructure.core.service.DateUtils; @Path("/v1/denominationmaster") @Component @@ -105,7 +106,7 @@ public class DenominationMasterApiResource { writeAudit("ACTIVATE", dm, null); } else if ("deactivate".equals(command)) { dm.setIsActive(false); - dm.setDiscontinuedOn(LocalDate.now()); + dm.setDiscontinuedOn(LocalDate.now(DateUtils.getDateTimeZoneOfTenant())); repository.save(dm); writeAudit("DEACTIVATE", dm, null); } else if ("restore".equals(command)) { diff --git a/fineract-provider/src/main/java/org/apache/fineract/portfolio/denominationmaster/domain/DenominationMasterAudit.java b/fineract-provider/src/main/java/org/apache/fineract/portfolio/denominationmaster/domain/DenominationMasterAudit.java index 1e9d05c1a..6c1ea416c 100644 --- a/fineract-provider/src/main/java/org/apache/fineract/portfolio/denominationmaster/domain/DenominationMasterAudit.java +++ b/fineract-provider/src/main/java/org/apache/fineract/portfolio/denominationmaster/domain/DenominationMasterAudit.java @@ -15,6 +15,7 @@ import java.time.LocalDateTime; import lombok.Getter; import lombok.NoArgsConstructor; import lombok.Setter; +import org.apache.fineract.infrastructure.core.service.DateUtils; @Entity @Table(name = "m_denomination_master_audit") @@ -77,7 +78,7 @@ public class DenominationMasterAudit { a.changes = changes; a.performedBy = performedBy; a.performedByUsername = performedByUsername; - a.performedOn = LocalDateTime.now(); + a.performedOn = LocalDateTime.now(DateUtils.getDateTimeZoneOfTenant()); return a; } } diff --git a/fineract-provider/src/main/java/org/apache/fineract/portfolio/denominationmaster/service/DenominationBreakdownWriter.java b/fineract-provider/src/main/java/org/apache/fineract/portfolio/denominationmaster/service/DenominationBreakdownWriter.java index 67002369d..bf72dd855 100644 --- a/fineract-provider/src/main/java/org/apache/fineract/portfolio/denominationmaster/service/DenominationBreakdownWriter.java +++ b/fineract-provider/src/main/java/org/apache/fineract/portfolio/denominationmaster/service/DenominationBreakdownWriter.java @@ -26,6 +26,7 @@ import org.apache.fineract.portfolio.denominationmaster.domain.SavingsTxnDenomin import org.apache.fineract.useradministration.domain.AppUser; import org.springframework.jdbc.core.JdbcTemplate; import org.springframework.stereotype.Service; +import org.apache.fineract.infrastructure.core.service.DateUtils; /** * Validates and persists the per-transaction cash denomination breakdown sent by the UI @@ -163,7 +164,7 @@ public class DenominationBreakdownWriter { } if (cashierId == null) return; - final String today = java.time.LocalDate.now().toString(); + final String today = java.time.LocalDate.now(DateUtils.getDateTimeZoneOfTenant()).toString(); final String sql = "SELECT COUNT(*) FROM m_cash_transfer ct " + "WHERE ct.to_cashier_id = ? " + " AND ct.transfer_date < CAST(? AS DATE) " @@ -203,7 +204,7 @@ public class DenominationBreakdownWriter { } if (cashierId == null) return; - final String today = java.time.LocalDate.now().toString(); + final String today = java.time.LocalDate.now(DateUtils.getDateTimeZoneOfTenant()).toString(); final String sql = "SELECT COUNT(*) FROM m_cash_transfer ct " + "WHERE ct.to_cashier_id = ? " + " AND ct.transfer_date = CAST(? AS DATE) " @@ -511,7 +512,7 @@ public class DenominationBreakdownWriter { .count(count) .totalAmount(lineTotal) .txnDate(txnDate) - .createdAt(LocalDateTime.now()) + .createdAt(LocalDateTime.now(DateUtils.getDateTimeZoneOfTenant())) .txnType(resolvedTxnType) .officerId(officerId) .officerUsername(officerUsername) diff --git a/fineract-provider/src/main/java/org/apache/fineract/portfolio/election/api/CommitteeApiResource.java b/fineract-provider/src/main/java/org/apache/fineract/portfolio/election/api/CommitteeApiResource.java index 04b2754b9..c0428ced4 100644 --- a/fineract-provider/src/main/java/org/apache/fineract/portfolio/election/api/CommitteeApiResource.java +++ b/fineract-provider/src/main/java/org/apache/fineract/portfolio/election/api/CommitteeApiResource.java @@ -1,6 +1,13 @@ package org.apache.fineract.portfolio.election.api; -import jakarta.ws.rs.*; +import jakarta.ws.rs.Consumes; +import jakarta.ws.rs.DELETE; +import jakarta.ws.rs.GET; +import jakarta.ws.rs.POST; +import jakarta.ws.rs.PUT; +import jakarta.ws.rs.Path; +import jakarta.ws.rs.PathParam; +import jakarta.ws.rs.Produces; import jakarta.ws.rs.core.MediaType; import jakarta.ws.rs.core.Response; import lombok.RequiredArgsConstructor; diff --git a/fineract-provider/src/main/java/org/apache/fineract/portfolio/election/api/CommitteeMeetingApiResource.java b/fineract-provider/src/main/java/org/apache/fineract/portfolio/election/api/CommitteeMeetingApiResource.java index 0fbf934bb..044b675e6 100644 --- a/fineract-provider/src/main/java/org/apache/fineract/portfolio/election/api/CommitteeMeetingApiResource.java +++ b/fineract-provider/src/main/java/org/apache/fineract/portfolio/election/api/CommitteeMeetingApiResource.java @@ -3,7 +3,17 @@ package org.apache.fineract.portfolio.election.api; import io.swagger.v3.oas.annotations.Operation; import io.swagger.v3.oas.annotations.tags.Tag; import jakarta.servlet.http.HttpServletRequest; -import jakarta.ws.rs.*; +import jakarta.ws.rs.Consumes; +import com.google.common.collect.Iterables; +import com.google.common.base.Splitter; +import jakarta.ws.rs.DELETE; +import jakarta.ws.rs.GET; +import jakarta.ws.rs.PATCH; +import jakarta.ws.rs.POST; +import jakarta.ws.rs.PUT; +import jakarta.ws.rs.Path; +import jakarta.ws.rs.PathParam; +import jakarta.ws.rs.Produces; import jakarta.ws.rs.core.Context; import jakarta.ws.rs.core.MediaType; import jakarta.ws.rs.core.Response; @@ -138,6 +148,6 @@ public class CommitteeMeetingApiResource { private String clientIp(HttpServletRequest req) { String ip = req.getHeader("X-Forwarded-For"); - return (ip != null && !ip.isBlank()) ? ip.split(",")[0].trim() : req.getRemoteAddr(); + return (ip != null && !ip.isBlank()) ? Iterables.get(Splitter.on(',').split(ip), 0).trim() : req.getRemoteAddr(); } } diff --git a/fineract-provider/src/main/java/org/apache/fineract/portfolio/election/api/DirectorAppointmentApiResource.java b/fineract-provider/src/main/java/org/apache/fineract/portfolio/election/api/DirectorAppointmentApiResource.java index 9e422d57c..206eb5b95 100644 --- a/fineract-provider/src/main/java/org/apache/fineract/portfolio/election/api/DirectorAppointmentApiResource.java +++ b/fineract-provider/src/main/java/org/apache/fineract/portfolio/election/api/DirectorAppointmentApiResource.java @@ -4,7 +4,18 @@ import io.swagger.v3.oas.annotations.Operation; import io.swagger.v3.oas.annotations.tags.Tag; import jakarta.servlet.http.HttpServletRequest; import jakarta.validation.Valid; -import jakarta.ws.rs.*; +import jakarta.ws.rs.Consumes; +import com.google.common.collect.Iterables; +import com.google.common.base.Splitter; +import jakarta.ws.rs.DELETE; +import jakarta.ws.rs.DefaultValue; +import jakarta.ws.rs.GET; +import jakarta.ws.rs.POST; +import jakarta.ws.rs.PUT; +import jakarta.ws.rs.Path; +import jakarta.ws.rs.PathParam; +import jakarta.ws.rs.Produces; +import jakarta.ws.rs.QueryParam; import jakarta.ws.rs.core.Context; import jakarta.ws.rs.core.MediaType; import jakarta.ws.rs.core.Response; @@ -125,6 +136,6 @@ public class DirectorAppointmentApiResource { private String clientIp(HttpServletRequest req) { String ip = req.getHeader("X-Forwarded-For"); - return (ip != null && !ip.isBlank()) ? ip.split(",")[0].trim() : req.getRemoteAddr(); + return (ip != null && !ip.isBlank()) ? Iterables.get(Splitter.on(',').split(ip), 0).trim() : req.getRemoteAddr(); } } diff --git a/fineract-provider/src/main/java/org/apache/fineract/portfolio/election/api/ElectionCandidateApiResource.java b/fineract-provider/src/main/java/org/apache/fineract/portfolio/election/api/ElectionCandidateApiResource.java index ebf007aaa..3764721b8 100644 --- a/fineract-provider/src/main/java/org/apache/fineract/portfolio/election/api/ElectionCandidateApiResource.java +++ b/fineract-provider/src/main/java/org/apache/fineract/portfolio/election/api/ElectionCandidateApiResource.java @@ -15,6 +15,8 @@ import jakarta.ws.rs.QueryParam; import jakarta.ws.rs.core.Context; import jakarta.ws.rs.core.MediaType; import jakarta.ws.rs.core.Response; +import com.google.common.base.Splitter; +import com.google.common.collect.Iterables; import lombok.RequiredArgsConstructor; import org.apache.fineract.infrastructure.contentstore.service.ContentStoreService; import org.apache.fineract.infrastructure.security.service.PlatformSecurityContext; @@ -123,7 +125,9 @@ public class ElectionCandidateApiResource { if (existing != null && !existing.startsWith("data:") && existing.contains("|")) { String[] ep = existing.split("\\|", 2); if (ep.length == 2) { - try { contentStoreService.delete(ep[1]); } catch (Exception ignored) {} + try { contentStoreService.delete(ep[1]); } catch (Exception ignored) { + // intentionally ignored + } } } @@ -218,7 +222,7 @@ public class ElectionCandidateApiResource { private static String clientIp(HttpServletRequest req) { if (req == null) return null; String fwd = req.getHeader("X-Forwarded-For"); - if (fwd != null && !fwd.isBlank()) return fwd.split(",")[0].trim(); + if (fwd != null && !fwd.isBlank()) return Iterables.get(Splitter.on(',').split(fwd), 0).trim(); return req.getRemoteAddr(); } diff --git a/fineract-provider/src/main/java/org/apache/fineract/portfolio/election/api/ElectionConfigApiResource.java b/fineract-provider/src/main/java/org/apache/fineract/portfolio/election/api/ElectionConfigApiResource.java index 04cc25edd..d6a98c762 100644 --- a/fineract-provider/src/main/java/org/apache/fineract/portfolio/election/api/ElectionConfigApiResource.java +++ b/fineract-provider/src/main/java/org/apache/fineract/portfolio/election/api/ElectionConfigApiResource.java @@ -5,7 +5,6 @@ import io.swagger.v3.oas.annotations.Operation; import io.swagger.v3.oas.annotations.tags.Tag; import jakarta.servlet.http.HttpServletRequest; import jakarta.ws.rs.Consumes; -import jakarta.ws.rs.DELETE; import jakarta.ws.rs.GET; import jakarta.ws.rs.POST; import jakarta.ws.rs.PUT; @@ -17,6 +16,8 @@ import jakarta.ws.rs.QueryParam; import jakarta.ws.rs.core.Context; import jakarta.ws.rs.core.MediaType; import jakarta.ws.rs.core.Response; +import com.google.common.base.Splitter; +import com.google.common.collect.Iterables; import lombok.RequiredArgsConstructor; import org.apache.fineract.portfolio.election.data.ElectionConfigData; import org.apache.fineract.portfolio.election.data.ElectionConfigRequest; @@ -89,7 +90,9 @@ public class ElectionConfigApiResource { throw e; } String updateDetails = null; - try { updateDetails = objectMapper.writeValueAsString(request); } catch (Exception ignored) {} + try { updateDetails = objectMapper.writeValueAsString(request); } catch (Exception ignored) { + // intentionally ignored + } electionAuditService.log(ElectionAuditAction.UPDATE_ELECTION, "ELECTION", electionId, electionId, "Election updated: " + request.getTitle(), updateDetails, clientIp(httpRequest)); return Response.ok(Map.of("resourceId", electionId)).build(); @@ -214,7 +217,7 @@ public class ElectionConfigApiResource { private static String clientIp(HttpServletRequest req) { if (req == null) return null; String fwd = req.getHeader("X-Forwarded-For"); - if (fwd != null && !fwd.isBlank()) return fwd.split(",")[0].trim(); + if (fwd != null && !fwd.isBlank()) return Iterables.get(Splitter.on(',').split(fwd), 0).trim(); return req.getRemoteAddr(); } diff --git a/fineract-provider/src/main/java/org/apache/fineract/portfolio/election/api/ElectionNominationApiResource.java b/fineract-provider/src/main/java/org/apache/fineract/portfolio/election/api/ElectionNominationApiResource.java index f969b601d..871197201 100644 --- a/fineract-provider/src/main/java/org/apache/fineract/portfolio/election/api/ElectionNominationApiResource.java +++ b/fineract-provider/src/main/java/org/apache/fineract/portfolio/election/api/ElectionNominationApiResource.java @@ -15,6 +15,8 @@ import jakarta.ws.rs.core.MediaType; import jakarta.ws.rs.core.Response; import lombok.RequiredArgsConstructor; import org.apache.fineract.portfolio.election.data.ElectionApprovalActionRequest; +import com.google.common.base.Splitter; +import com.google.common.collect.Iterables; import org.apache.fineract.portfolio.election.data.ElectionApprovalStepData; import org.apache.fineract.portfolio.election.data.ElectionNominationData; import org.apache.fineract.portfolio.election.data.ElectionNominationRequest; @@ -295,7 +297,7 @@ public class ElectionNominationApiResource { private static String clientIp(HttpServletRequest req) { if (req == null) return null; String fwd = req.getHeader("X-Forwarded-For"); - if (fwd != null && !fwd.isBlank()) return fwd.split(",")[0].trim(); + if (fwd != null && !fwd.isBlank()) return Iterables.get(Splitter.on(',').split(fwd), 0).trim(); return req.getRemoteAddr(); } diff --git a/fineract-provider/src/main/java/org/apache/fineract/portfolio/election/api/ElectionVotingApiResource.java b/fineract-provider/src/main/java/org/apache/fineract/portfolio/election/api/ElectionVotingApiResource.java index c21a700e0..078f53a6e 100644 --- a/fineract-provider/src/main/java/org/apache/fineract/portfolio/election/api/ElectionVotingApiResource.java +++ b/fineract-provider/src/main/java/org/apache/fineract/portfolio/election/api/ElectionVotingApiResource.java @@ -15,6 +15,8 @@ import jakarta.ws.rs.GET; import jakarta.ws.rs.POST; import jakarta.ws.rs.Path; import jakarta.ws.rs.PathParam; +import com.google.common.base.Splitter; +import com.google.common.collect.Iterables; import jakarta.ws.rs.Produces; import jakarta.ws.rs.core.Context; import jakarta.ws.rs.core.MediaType; @@ -104,10 +106,10 @@ public class ElectionVotingApiResource { } winDet.append("]"); String declareDetails = wFirst ? null : winDet.toString(); - String declareDesc = "Results declared" + (declareDetails != null ? " — " + (results.stream() + String declareDesc = "Results declared" + (declareDetails != null ? " — " + results.stream() .filter(r -> Integer.valueOf(1).equals(r.getRankPosition()) || "WON".equalsIgnoreCase(r.getResult())) .map(r -> r.getCandidateName() + " won " + r.getPostName()) - .reduce((a, b) -> a + "; " + b).orElse("")) : ""); + .reduce((a, b) -> a + "; " + b).orElse("") : ""); electionAuditService.log(ElectionAuditAction.DECLARE_RESULTS, "RESULT", electionId, electionId, declareDesc, declareDetails, clientIp(httpRequest)); return Response.ok(results).build(); @@ -127,7 +129,7 @@ public class ElectionVotingApiResource { private static String clientIp(HttpServletRequest req) { if (req == null) return null; String fwd = req.getHeader("X-Forwarded-For"); - if (fwd != null && !fwd.isBlank()) return fwd.split(",")[0].trim(); + if (fwd != null && !fwd.isBlank()) return Iterables.get(Splitter.on(',').split(fwd), 0).trim(); return req.getRemoteAddr(); } diff --git a/fineract-provider/src/main/java/org/apache/fineract/portfolio/election/api/MeetingPublicVoteApiResource.java b/fineract-provider/src/main/java/org/apache/fineract/portfolio/election/api/MeetingPublicVoteApiResource.java index 428cff9fd..fd0ff7bd6 100644 --- a/fineract-provider/src/main/java/org/apache/fineract/portfolio/election/api/MeetingPublicVoteApiResource.java +++ b/fineract-provider/src/main/java/org/apache/fineract/portfolio/election/api/MeetingPublicVoteApiResource.java @@ -2,7 +2,12 @@ package org.apache.fineract.portfolio.election.api; import io.swagger.v3.oas.annotations.Operation; import io.swagger.v3.oas.annotations.tags.Tag; -import jakarta.ws.rs.*; +import jakarta.ws.rs.Consumes; +import jakarta.ws.rs.GET; +import jakarta.ws.rs.POST; +import jakarta.ws.rs.Path; +import jakarta.ws.rs.PathParam; +import jakarta.ws.rs.Produces; import jakarta.ws.rs.core.MediaType; import jakarta.ws.rs.core.Response; import lombok.RequiredArgsConstructor; diff --git a/fineract-provider/src/main/java/org/apache/fineract/portfolio/election/api/MeetingVoteAdminApiResource.java b/fineract-provider/src/main/java/org/apache/fineract/portfolio/election/api/MeetingVoteAdminApiResource.java index a353257c8..05903186f 100644 --- a/fineract-provider/src/main/java/org/apache/fineract/portfolio/election/api/MeetingVoteAdminApiResource.java +++ b/fineract-provider/src/main/java/org/apache/fineract/portfolio/election/api/MeetingVoteAdminApiResource.java @@ -2,7 +2,13 @@ package org.apache.fineract.portfolio.election.api; import io.swagger.v3.oas.annotations.Operation; import io.swagger.v3.oas.annotations.tags.Tag; -import jakarta.ws.rs.*; +import jakarta.ws.rs.Consumes; +import jakarta.ws.rs.GET; +import jakarta.ws.rs.POST; +import jakarta.ws.rs.PUT; +import jakarta.ws.rs.Path; +import jakarta.ws.rs.PathParam; +import jakarta.ws.rs.Produces; import jakarta.ws.rs.core.MediaType; import jakarta.ws.rs.core.Response; import lombok.RequiredArgsConstructor; diff --git a/fineract-provider/src/main/java/org/apache/fineract/portfolio/election/domain/Committee.java b/fineract-provider/src/main/java/org/apache/fineract/portfolio/election/domain/Committee.java index 6a394a65d..237ddee14 100644 --- a/fineract-provider/src/main/java/org/apache/fineract/portfolio/election/domain/Committee.java +++ b/fineract-provider/src/main/java/org/apache/fineract/portfolio/election/domain/Committee.java @@ -1,6 +1,13 @@ package org.apache.fineract.portfolio.election.domain; -import jakarta.persistence.*; +import jakarta.persistence.CascadeType; +import jakarta.persistence.Column; +import jakarta.persistence.Entity; +import jakarta.persistence.EnumType; +import jakarta.persistence.Enumerated; +import jakarta.persistence.FetchType; +import jakarta.persistence.OneToMany; +import jakarta.persistence.Table; import lombok.Getter; import lombok.NoArgsConstructor; import lombok.Setter; diff --git a/fineract-provider/src/main/java/org/apache/fineract/portfolio/election/domain/CommitteeMeeting.java b/fineract-provider/src/main/java/org/apache/fineract/portfolio/election/domain/CommitteeMeeting.java index 480b92e9d..7d65e8e37 100644 --- a/fineract-provider/src/main/java/org/apache/fineract/portfolio/election/domain/CommitteeMeeting.java +++ b/fineract-provider/src/main/java/org/apache/fineract/portfolio/election/domain/CommitteeMeeting.java @@ -1,6 +1,13 @@ package org.apache.fineract.portfolio.election.domain; -import jakarta.persistence.*; +import jakarta.persistence.Column; +import jakarta.persistence.Entity; +import jakarta.persistence.EnumType; +import jakarta.persistence.Enumerated; +import jakarta.persistence.FetchType; +import jakarta.persistence.OneToMany; +import jakarta.persistence.OrderBy; +import jakarta.persistence.Table; import lombok.Getter; import lombok.NoArgsConstructor; import lombok.Setter; diff --git a/fineract-provider/src/main/java/org/apache/fineract/portfolio/election/domain/CommitteeMeetingAgenda.java b/fineract-provider/src/main/java/org/apache/fineract/portfolio/election/domain/CommitteeMeetingAgenda.java index c3f2da500..211cfdfc5 100644 --- a/fineract-provider/src/main/java/org/apache/fineract/portfolio/election/domain/CommitteeMeetingAgenda.java +++ b/fineract-provider/src/main/java/org/apache/fineract/portfolio/election/domain/CommitteeMeetingAgenda.java @@ -1,6 +1,14 @@ package org.apache.fineract.portfolio.election.domain; -import jakarta.persistence.*; +import jakarta.persistence.Column; +import jakarta.persistence.Entity; +import jakarta.persistence.FetchType; +import jakarta.persistence.GeneratedValue; +import jakarta.persistence.GenerationType; +import jakarta.persistence.Id; +import jakarta.persistence.JoinColumn; +import jakarta.persistence.ManyToOne; +import jakarta.persistence.Table; import lombok.Getter; import lombok.NoArgsConstructor; import lombok.Setter; diff --git a/fineract-provider/src/main/java/org/apache/fineract/portfolio/election/domain/CommitteeMember.java b/fineract-provider/src/main/java/org/apache/fineract/portfolio/election/domain/CommitteeMember.java index b65c19f48..8d13ffc01 100644 --- a/fineract-provider/src/main/java/org/apache/fineract/portfolio/election/domain/CommitteeMember.java +++ b/fineract-provider/src/main/java/org/apache/fineract/portfolio/election/domain/CommitteeMember.java @@ -26,7 +26,7 @@ public class CommitteeMember { private Long directorAppointmentId; @Column(name = "added_date", nullable = false) - private LocalDate addedDate = LocalDate.now(); + private LocalDate addedDate; public static CommitteeMember create(Committee committee, Long directorAppointmentId) { CommitteeMember m = new CommitteeMember(); diff --git a/fineract-provider/src/main/java/org/apache/fineract/portfolio/election/domain/DirectorAppointment.java b/fineract-provider/src/main/java/org/apache/fineract/portfolio/election/domain/DirectorAppointment.java index 380d80935..aaa66fc33 100644 --- a/fineract-provider/src/main/java/org/apache/fineract/portfolio/election/domain/DirectorAppointment.java +++ b/fineract-provider/src/main/java/org/apache/fineract/portfolio/election/domain/DirectorAppointment.java @@ -1,6 +1,12 @@ package org.apache.fineract.portfolio.election.domain; -import jakarta.persistence.*; +import jakarta.persistence.Column; +import jakarta.persistence.Entity; +import jakarta.persistence.EnumType; +import jakarta.persistence.Enumerated; +import jakarta.persistence.PrePersist; +import jakarta.persistence.PreUpdate; +import jakarta.persistence.Table; import lombok.Getter; import lombok.NoArgsConstructor; import lombok.Setter; @@ -8,6 +14,7 @@ import org.apache.fineract.infrastructure.core.domain.AbstractPersistableCustom; import java.time.LocalDate; import java.time.LocalDateTime; +import org.apache.fineract.infrastructure.core.service.DateUtils; @Entity @Table(name = "m_election_director_appointment") @@ -58,12 +65,12 @@ public class DirectorAppointment extends AbstractPersistableCustom { @PrePersist void onPersist() { - this.createdDate = LocalDateTime.now(); + this.createdDate = LocalDateTime.now(DateUtils.getDateTimeZoneOfTenant()); } @PreUpdate void onUpdate() { - this.lastModifiedDate = LocalDateTime.now(); + this.lastModifiedDate = LocalDateTime.now(DateUtils.getDateTimeZoneOfTenant()); } public static DirectorAppointment create(Long electionId, Long candidateId, diff --git a/fineract-provider/src/main/java/org/apache/fineract/portfolio/election/domain/DirectorAppointmentRepository.java b/fineract-provider/src/main/java/org/apache/fineract/portfolio/election/domain/DirectorAppointmentRepository.java index d4e8e02c9..e09436211 100644 --- a/fineract-provider/src/main/java/org/apache/fineract/portfolio/election/domain/DirectorAppointmentRepository.java +++ b/fineract-provider/src/main/java/org/apache/fineract/portfolio/election/domain/DirectorAppointmentRepository.java @@ -14,6 +14,7 @@ import java.util.List; @Repository public interface DirectorAppointmentRepository extends JpaRepository { + @Override Page findAll(Pageable pageable); Page findByStatus(DirectorAppointmentStatus status, Pageable pageable); diff --git a/fineract-provider/src/main/java/org/apache/fineract/portfolio/election/domain/ElectionApprovalStep.java b/fineract-provider/src/main/java/org/apache/fineract/portfolio/election/domain/ElectionApprovalStep.java index e727a3a08..70236d8c0 100644 --- a/fineract-provider/src/main/java/org/apache/fineract/portfolio/election/domain/ElectionApprovalStep.java +++ b/fineract-provider/src/main/java/org/apache/fineract/portfolio/election/domain/ElectionApprovalStep.java @@ -1,12 +1,20 @@ package org.apache.fineract.portfolio.election.domain; -import jakarta.persistence.*; +import jakarta.persistence.Column; +import jakarta.persistence.Entity; +import jakarta.persistence.EnumType; +import jakarta.persistence.Enumerated; +import jakarta.persistence.FetchType; +import jakarta.persistence.JoinColumn; +import jakarta.persistence.ManyToOne; +import jakarta.persistence.Table; import lombok.Getter; import lombok.NoArgsConstructor; import lombok.Setter; import org.apache.fineract.infrastructure.core.domain.AbstractPersistableCustom; import java.time.LocalDateTime; +import org.apache.fineract.infrastructure.core.service.DateUtils; @Entity @Table(name = "m_election_approval_step") @@ -63,7 +71,7 @@ public class ElectionApprovalStep extends AbstractPersistableCustom { this.approverUserId = approverUserId; this.status = ApprovalStepStatus.APPROVED; this.remarks = remarks; - this.actionDate = LocalDateTime.now(); + this.actionDate = LocalDateTime.now(DateUtils.getDateTimeZoneOfTenant()); this.familyDetailsVerified = familyVerified; this.familyDetailsJson = familyJson; } @@ -72,6 +80,6 @@ public class ElectionApprovalStep extends AbstractPersistableCustom { this.approverUserId = approverUserId; this.status = ApprovalStepStatus.REJECTED; this.remarks = remarks; - this.actionDate = LocalDateTime.now(); + this.actionDate = LocalDateTime.now(DateUtils.getDateTimeZoneOfTenant()); } } diff --git a/fineract-provider/src/main/java/org/apache/fineract/portfolio/election/domain/ElectionAuditLog.java b/fineract-provider/src/main/java/org/apache/fineract/portfolio/election/domain/ElectionAuditLog.java index 2312901ef..cd701b6be 100644 --- a/fineract-provider/src/main/java/org/apache/fineract/portfolio/election/domain/ElectionAuditLog.java +++ b/fineract-provider/src/main/java/org/apache/fineract/portfolio/election/domain/ElectionAuditLog.java @@ -14,6 +14,7 @@ import lombok.NoArgsConstructor; import lombok.Setter; import java.time.LocalDateTime; +import org.apache.fineract.infrastructure.core.service.DateUtils; @Entity @Table(name = "m_election_audit_log") @@ -63,6 +64,6 @@ public class ElectionAuditLog { @PrePersist void prePersist() { - if (createdAt == null) createdAt = LocalDateTime.now(); + if (createdAt == null) createdAt = LocalDateTime.now(DateUtils.getDateTimeZoneOfTenant()); } } diff --git a/fineract-provider/src/main/java/org/apache/fineract/portfolio/election/domain/ElectionCandidate.java b/fineract-provider/src/main/java/org/apache/fineract/portfolio/election/domain/ElectionCandidate.java index 2e34798f9..b8938d086 100644 --- a/fineract-provider/src/main/java/org/apache/fineract/portfolio/election/domain/ElectionCandidate.java +++ b/fineract-provider/src/main/java/org/apache/fineract/portfolio/election/domain/ElectionCandidate.java @@ -1,12 +1,19 @@ package org.apache.fineract.portfolio.election.domain; -import jakarta.persistence.*; +import jakarta.persistence.Column; +import jakarta.persistence.Entity; +import jakarta.persistence.FetchType; +import jakarta.persistence.JoinColumn; +import jakarta.persistence.ManyToOne; +import jakarta.persistence.OneToOne; +import jakarta.persistence.Table; import lombok.Getter; import lombok.NoArgsConstructor; import lombok.Setter; import org.apache.fineract.infrastructure.core.domain.AbstractPersistableCustom; import java.time.LocalDateTime; +import org.apache.fineract.infrastructure.core.service.DateUtils; @Entity @Table(name = "m_election_candidate") @@ -67,7 +74,7 @@ public class ElectionCandidate extends AbstractPersistableCustom { candidate.candidateName = candidateName; candidate.serialNumber = serialNumber; candidate.approvedBy = approvedBy; - candidate.approvedDate = LocalDateTime.now(); + candidate.approvedDate = LocalDateTime.now(DateUtils.getDateTimeZoneOfTenant()); candidate.isActive = true; return candidate; } diff --git a/fineract-provider/src/main/java/org/apache/fineract/portfolio/election/domain/ElectionCeoPrecheck.java b/fineract-provider/src/main/java/org/apache/fineract/portfolio/election/domain/ElectionCeoPrecheck.java index 505303480..65f7c6f5f 100644 --- a/fineract-provider/src/main/java/org/apache/fineract/portfolio/election/domain/ElectionCeoPrecheck.java +++ b/fineract-provider/src/main/java/org/apache/fineract/portfolio/election/domain/ElectionCeoPrecheck.java @@ -1,6 +1,13 @@ package org.apache.fineract.portfolio.election.domain; -import jakarta.persistence.*; +import jakarta.persistence.Column; +import jakarta.persistence.Entity; +import jakarta.persistence.EnumType; +import jakarta.persistence.Enumerated; +import jakarta.persistence.FetchType; +import jakarta.persistence.JoinColumn; +import jakarta.persistence.OneToOne; +import jakarta.persistence.Table; import lombok.Getter; import lombok.NoArgsConstructor; import lombok.Setter; @@ -8,6 +15,7 @@ import org.apache.fineract.infrastructure.core.domain.AbstractPersistableCustom; import java.math.BigDecimal; import java.time.LocalDateTime; +import org.apache.fineract.infrastructure.core.service.DateUtils; @Entity @Table(name = "m_election_ceo_precheck") @@ -152,13 +160,13 @@ public class ElectionCeoPrecheck extends AbstractPersistableCustom { public void generateNoDueCertificate(String certificateNumber) { this.noDueCertificateNumber = certificateNumber; - this.noDueGeneratedDate = LocalDateTime.now(); + this.noDueGeneratedDate = LocalDateTime.now(DateUtils.getDateTimeZoneOfTenant()); this.noDueCheckResult = CheckResult.PASS; } public void finalise(Long checkedBy, String remarks) { this.checkedBy = checkedBy; - this.checkedDate = LocalDateTime.now(); + this.checkedDate = LocalDateTime.now(DateUtils.getDateTimeZoneOfTenant()); this.remarks = remarks; // NDC is generated manually after pre-check; only automated checks determine overall result boolean autoChecksPass = directorLoanCheckResult == CheckResult.PASS diff --git a/fineract-provider/src/main/java/org/apache/fineract/portfolio/election/domain/ElectionConfig.java b/fineract-provider/src/main/java/org/apache/fineract/portfolio/election/domain/ElectionConfig.java index 34fde4e50..b092fbe0a 100644 --- a/fineract-provider/src/main/java/org/apache/fineract/portfolio/election/domain/ElectionConfig.java +++ b/fineract-provider/src/main/java/org/apache/fineract/portfolio/election/domain/ElectionConfig.java @@ -1,6 +1,13 @@ package org.apache.fineract.portfolio.election.domain; -import jakarta.persistence.*; +import jakarta.persistence.CascadeType; +import jakarta.persistence.Column; +import jakarta.persistence.Entity; +import jakarta.persistence.EnumType; +import jakarta.persistence.Enumerated; +import jakarta.persistence.FetchType; +import jakarta.persistence.OneToMany; +import jakarta.persistence.Table; import lombok.Getter; import lombok.NoArgsConstructor; import lombok.Setter; @@ -9,6 +16,7 @@ import org.apache.fineract.infrastructure.core.domain.AbstractAuditableWithUTCDa import java.time.LocalDate; import java.util.ArrayList; import java.util.List; +import org.apache.fineract.infrastructure.core.service.DateUtils; @Entity @Table(name = "m_election_config") @@ -78,7 +86,7 @@ public class ElectionConfig extends AbstractAuditableWithUTCDateTimeCustom } public boolean isNominationOpen() { - LocalDate today = LocalDate.now(); + LocalDate today = LocalDate.now(DateUtils.getDateTimeZoneOfTenant()); return status == ElectionStatus.ACTIVE && !today.isBefore(nominationStartDate) && !today.isAfter(nominationEndDate); diff --git a/fineract-provider/src/main/java/org/apache/fineract/portfolio/election/domain/ElectionEligibilityCheck.java b/fineract-provider/src/main/java/org/apache/fineract/portfolio/election/domain/ElectionEligibilityCheck.java index e03b83dba..27a971187 100644 --- a/fineract-provider/src/main/java/org/apache/fineract/portfolio/election/domain/ElectionEligibilityCheck.java +++ b/fineract-provider/src/main/java/org/apache/fineract/portfolio/election/domain/ElectionEligibilityCheck.java @@ -1,12 +1,20 @@ package org.apache.fineract.portfolio.election.domain; -import jakarta.persistence.*; +import jakarta.persistence.Column; +import jakarta.persistence.Entity; +import jakarta.persistence.EnumType; +import jakarta.persistence.Enumerated; +import jakarta.persistence.FetchType; +import jakarta.persistence.JoinColumn; +import jakarta.persistence.OneToOne; +import jakarta.persistence.Table; import lombok.Getter; import lombok.NoArgsConstructor; import lombok.Setter; import org.apache.fineract.infrastructure.core.domain.AbstractPersistableCustom; import java.time.LocalDateTime; +import org.apache.fineract.infrastructure.core.service.DateUtils; @Entity @Table(name = "m_election_eligibility_check") @@ -71,7 +79,7 @@ public class ElectionEligibilityCheck extends AbstractPersistableCustom { public void complete(Long checkedBy, String remarks, boolean passed) { this.checkedBy = checkedBy; - this.checkedDate = LocalDateTime.now(); + this.checkedDate = LocalDateTime.now(DateUtils.getDateTimeZoneOfTenant()); this.remarks = remarks; this.overallResult = passed ? CheckResult.PASS : CheckResult.FAIL; this.ageEligible = passed; diff --git a/fineract-provider/src/main/java/org/apache/fineract/portfolio/election/domain/ElectionNomination.java b/fineract-provider/src/main/java/org/apache/fineract/portfolio/election/domain/ElectionNomination.java index 7c118aa1a..5ead0d6fb 100644 --- a/fineract-provider/src/main/java/org/apache/fineract/portfolio/election/domain/ElectionNomination.java +++ b/fineract-provider/src/main/java/org/apache/fineract/portfolio/election/domain/ElectionNomination.java @@ -1,6 +1,16 @@ package org.apache.fineract.portfolio.election.domain; -import jakarta.persistence.*; +import jakarta.persistence.CascadeType; +import jakarta.persistence.Column; +import jakarta.persistence.Entity; +import jakarta.persistence.EnumType; +import jakarta.persistence.Enumerated; +import jakarta.persistence.FetchType; +import jakarta.persistence.JoinColumn; +import jakarta.persistence.ManyToOne; +import jakarta.persistence.OneToMany; +import jakarta.persistence.Table; +import jakarta.persistence.UniqueConstraint; import lombok.Getter; import lombok.NoArgsConstructor; import lombok.Setter; @@ -10,6 +20,7 @@ import java.time.LocalDate; import java.time.LocalDateTime; import java.util.ArrayList; import java.util.List; +import org.apache.fineract.infrastructure.core.service.DateUtils; @Entity @Table(name = "m_election_nomination", @@ -121,7 +132,7 @@ public class ElectionNomination extends AbstractAuditableWithUTCDateTimeCustom { r.result = result; r.rankPosition = rankPosition; r.declaredBy = declaredBy; - r.declaredDate = LocalDateTime.now(); + r.declaredDate = LocalDateTime.now(DateUtils.getDateTimeZoneOfTenant()); return r; } } diff --git a/fineract-provider/src/main/java/org/apache/fineract/portfolio/election/domain/ElectionVote.java b/fineract-provider/src/main/java/org/apache/fineract/portfolio/election/domain/ElectionVote.java index 329e56082..0f42b7edb 100644 --- a/fineract-provider/src/main/java/org/apache/fineract/portfolio/election/domain/ElectionVote.java +++ b/fineract-provider/src/main/java/org/apache/fineract/portfolio/election/domain/ElectionVote.java @@ -1,12 +1,19 @@ package org.apache.fineract.portfolio.election.domain; -import jakarta.persistence.*; +import jakarta.persistence.Column; +import jakarta.persistence.Entity; +import jakarta.persistence.FetchType; +import jakarta.persistence.JoinColumn; +import jakarta.persistence.ManyToOne; +import jakarta.persistence.Table; +import jakarta.persistence.UniqueConstraint; import lombok.Getter; import lombok.NoArgsConstructor; import lombok.Setter; import org.apache.fineract.infrastructure.core.domain.AbstractPersistableCustom; import java.time.LocalDateTime; +import org.apache.fineract.infrastructure.core.service.DateUtils; @Entity @Table(name = "m_election_vote", @@ -50,7 +57,7 @@ public class ElectionVote extends AbstractPersistableCustom { vote.electionPost = post; vote.voterMemberId = voterMemberId; vote.candidate = candidate; - vote.voteTimestamp = LocalDateTime.now(); + vote.voteTimestamp = LocalDateTime.now(DateUtils.getDateTimeZoneOfTenant()); vote.boothId = boothId; vote.ipAddress = ipAddress; return vote; diff --git a/fineract-provider/src/main/java/org/apache/fineract/portfolio/election/domain/MeetingAgendaResolution.java b/fineract-provider/src/main/java/org/apache/fineract/portfolio/election/domain/MeetingAgendaResolution.java index fcb700643..32ff0973c 100644 --- a/fineract-provider/src/main/java/org/apache/fineract/portfolio/election/domain/MeetingAgendaResolution.java +++ b/fineract-provider/src/main/java/org/apache/fineract/portfolio/election/domain/MeetingAgendaResolution.java @@ -1,11 +1,19 @@ package org.apache.fineract.portfolio.election.domain; -import jakarta.persistence.*; +import jakarta.persistence.Column; +import jakarta.persistence.Entity; +import jakarta.persistence.EnumType; +import jakarta.persistence.Enumerated; +import jakarta.persistence.GeneratedValue; +import jakarta.persistence.GenerationType; +import jakarta.persistence.Id; +import jakarta.persistence.Table; import lombok.Getter; import lombok.NoArgsConstructor; import lombok.Setter; import java.time.LocalDateTime; +import org.apache.fineract.infrastructure.core.service.DateUtils; @Entity @Table(name = "m_election_meeting_agenda_resolution") @@ -41,7 +49,7 @@ public class MeetingAgendaResolution { r.agendaId = agendaId; r.resolution = resolution; r.discussionNotes = notes; - r.resolvedAt = LocalDateTime.now(); + r.resolvedAt = LocalDateTime.now(DateUtils.getDateTimeZoneOfTenant()); return r; } } diff --git a/fineract-provider/src/main/java/org/apache/fineract/portfolio/election/domain/MeetingMemberVote.java b/fineract-provider/src/main/java/org/apache/fineract/portfolio/election/domain/MeetingMemberVote.java index b8a6a4fba..3091d23bb 100644 --- a/fineract-provider/src/main/java/org/apache/fineract/portfolio/election/domain/MeetingMemberVote.java +++ b/fineract-provider/src/main/java/org/apache/fineract/portfolio/election/domain/MeetingMemberVote.java @@ -1,11 +1,20 @@ package org.apache.fineract.portfolio.election.domain; -import jakarta.persistence.*; +import jakarta.persistence.Column; +import jakarta.persistence.Entity; +import jakarta.persistence.EnumType; +import jakarta.persistence.Enumerated; +import jakarta.persistence.GeneratedValue; +import jakarta.persistence.GenerationType; +import jakarta.persistence.Id; +import jakarta.persistence.Table; +import jakarta.persistence.UniqueConstraint; import lombok.Getter; import lombok.NoArgsConstructor; import lombok.Setter; import java.time.LocalDateTime; +import org.apache.fineract.infrastructure.core.service.DateUtils; @Entity @Table(name = "m_election_meeting_member_vote", @@ -46,7 +55,7 @@ public class MeetingMemberVote { v.agendaId = agendaId; v.memberId = memberId; v.vote = vote; - v.votedAt = LocalDateTime.now(); + v.votedAt = LocalDateTime.now(DateUtils.getDateTimeZoneOfTenant()); v.remark = (remark != null && !remark.isBlank()) ? remark.trim() : null; return v; } diff --git a/fineract-provider/src/main/java/org/apache/fineract/portfolio/election/domain/MeetingVoteToken.java b/fineract-provider/src/main/java/org/apache/fineract/portfolio/election/domain/MeetingVoteToken.java index b8c66eaba..e53291a93 100644 --- a/fineract-provider/src/main/java/org/apache/fineract/portfolio/election/domain/MeetingVoteToken.java +++ b/fineract-provider/src/main/java/org/apache/fineract/portfolio/election/domain/MeetingVoteToken.java @@ -1,12 +1,16 @@ package org.apache.fineract.portfolio.election.domain; -import jakarta.persistence.*; +import jakarta.persistence.Column; +import jakarta.persistence.Entity; +import jakarta.persistence.Id; +import jakarta.persistence.Table; import lombok.Getter; import lombok.NoArgsConstructor; import lombok.Setter; import java.time.LocalDateTime; import java.util.UUID; +import org.apache.fineract.infrastructure.core.service.DateUtils; @Entity @Table(name = "m_election_meeting_vote_token") @@ -49,12 +53,12 @@ public class MeetingVoteToken { t.memberName = memberName; t.designation = designation; t.used = false; - t.createdAt = LocalDateTime.now(); + t.createdAt = LocalDateTime.now(DateUtils.getDateTimeZoneOfTenant()); t.expiresAt = t.createdAt.plusDays(validDays); return t; } public boolean isExpired() { - return LocalDateTime.now().isAfter(expiresAt); + return LocalDateTime.now(DateUtils.getDateTimeZoneOfTenant()).isAfter(expiresAt); } } diff --git a/fineract-provider/src/main/java/org/apache/fineract/portfolio/election/service/CommitteeMeetingServiceImpl.java b/fineract-provider/src/main/java/org/apache/fineract/portfolio/election/service/CommitteeMeetingServiceImpl.java index f63702e0e..d0e229aaf 100644 --- a/fineract-provider/src/main/java/org/apache/fineract/portfolio/election/service/CommitteeMeetingServiceImpl.java +++ b/fineract-provider/src/main/java/org/apache/fineract/portfolio/election/service/CommitteeMeetingServiceImpl.java @@ -32,6 +32,7 @@ import java.time.format.DateTimeFormatter; import java.util.ArrayList; import java.util.Collections; import java.util.List; +import org.apache.fineract.infrastructure.core.service.DateUtils; @Slf4j @Service @@ -215,7 +216,7 @@ public class CommitteeMeetingServiceImpl implements CommitteeMeetingService { private String buildMeetingInviteHtml(String recipientName, String committeeName, CommitteeMeeting meeting, boolean isUpdate) { DateTimeFormatter dateFmt = DateTimeFormatter.ofPattern("dd MMMM yyyy"); - String sentAt = java.time.LocalDateTime.now().format(DateTimeFormatter.ofPattern("dd MMM yyyy, hh:mm a")); + String sentAt = java.time.LocalDateTime.now(DateUtils.getDateTimeZoneOfTenant()).format(DateTimeFormatter.ofPattern("dd MMM yyyy, hh:mm a")); String dateStr = meeting.getMeetingDate() != null ? meeting.getMeetingDate().format(dateFmt) : "—"; String timeStr = meeting.getMeetingTime() != null ? meeting.getMeetingTime() : "—"; boolean isOnline = meeting.getMode() == CommitteeMeetingMode.ONLINE; @@ -381,7 +382,7 @@ public class CommitteeMeetingServiceImpl implements CommitteeMeetingService { if (date == null) { throw new IllegalArgumentException("Meeting date is required"); } - if (date.isBefore(LocalDate.now())) { + if (date.isBefore(LocalDate.now(DateUtils.getDateTimeZoneOfTenant()))) { throw new IllegalArgumentException("Meeting date cannot be in the past"); } } diff --git a/fineract-provider/src/main/java/org/apache/fineract/portfolio/election/service/CommitteeServiceImpl.java b/fineract-provider/src/main/java/org/apache/fineract/portfolio/election/service/CommitteeServiceImpl.java index 1edaa3044..c90429fe0 100644 --- a/fineract-provider/src/main/java/org/apache/fineract/portfolio/election/service/CommitteeServiceImpl.java +++ b/fineract-provider/src/main/java/org/apache/fineract/portfolio/election/service/CommitteeServiceImpl.java @@ -26,6 +26,7 @@ import java.util.List; import java.util.Map; import java.util.Set; import java.util.stream.Collectors; +import org.apache.fineract.infrastructure.core.service.DateUtils; @Service @RequiredArgsConstructor @@ -132,7 +133,7 @@ public class CommitteeServiceImpl implements CommitteeService { @Override public List getCurrentElectionDirectors() { - var currentElection = electionConfigRepository.findFirstWithActiveDuration(LocalDate.now()); + var currentElection = electionConfigRepository.findFirstWithActiveDuration(LocalDate.now(DateUtils.getDateTimeZoneOfTenant())); // fallback: most recent RESULT_DECLARED election if none has active duration if (currentElection.isEmpty()) { diff --git a/fineract-provider/src/main/java/org/apache/fineract/portfolio/election/service/DirectorAppointmentServiceImpl.java b/fineract-provider/src/main/java/org/apache/fineract/portfolio/election/service/DirectorAppointmentServiceImpl.java index a6950b779..21f08eb22 100644 --- a/fineract-provider/src/main/java/org/apache/fineract/portfolio/election/service/DirectorAppointmentServiceImpl.java +++ b/fineract-provider/src/main/java/org/apache/fineract/portfolio/election/service/DirectorAppointmentServiceImpl.java @@ -28,6 +28,7 @@ import java.util.List; import java.util.Map; import java.util.Set; import java.util.stream.Collectors; +import org.apache.fineract.infrastructure.core.service.DateUtils; @Service @RequiredArgsConstructor @@ -109,12 +110,12 @@ public class DirectorAppointmentServiceImpl implements DirectorAppointmentServic @Transactional @Scheduled(cron = "0 0 0 * * *") public void autoExpireByTenure() { - int updated = repository.expireByTenureDate(LocalDate.now()); + int updated = repository.expireByTenureDate(LocalDate.now(DateUtils.getDateTimeZoneOfTenant())); if (updated > 0) { log.info("Auto-expired {} director appointment(s) whose tenure ended.", updated); auditService.log(ElectionAuditAction.UPDATE_DIRECTOR_APPOINTMENT, "DIRECTOR_APPOINTMENT", null, null, "Scheduler auto-expired " + updated + " director appointment(s)", - "expiredCount=" + updated + ", date=" + LocalDate.now(), null); + "expiredCount=" + updated + ", date=" + LocalDate.now(DateUtils.getDateTimeZoneOfTenant()), null); } } @@ -126,7 +127,9 @@ public class DirectorAppointmentServiceImpl implements DirectorAppointmentServic DirectorAppointmentStatus statusEnum = null; if (status != null && !status.isBlank()) { - try { statusEnum = DirectorAppointmentStatus.valueOf(status.toUpperCase()); } catch (Exception ignored) {} + try { statusEnum = DirectorAppointmentStatus.valueOf(status.toUpperCase()); } catch (Exception ignored) { + // intentionally ignored + } } if (electionId != null && statusEnum != null) { @@ -177,7 +180,9 @@ public class DirectorAppointmentServiceImpl implements DirectorAppointmentServic if (req.getAppointmentDate() != null) d.setAppointmentDate(req.getAppointmentDate()); if (req.getRemarks() != null) d.setRemarks(req.getRemarks()); if (req.getStatus() != null) { - try { d.setStatus(DirectorAppointmentStatus.valueOf(req.getStatus().toUpperCase())); } catch (Exception ignored) {} + try { d.setStatus(DirectorAppointmentStatus.valueOf(req.getStatus().toUpperCase())); } catch (Exception ignored) { + // intentionally ignored + } } if (req.getCandidateName() != null) d.setCandidateName(req.getCandidateName()); if (req.getPostName() != null) d.setPostName(req.getPostName()); @@ -234,10 +239,6 @@ public class DirectorAppointmentServiceImpl implements DirectorAppointmentServic return toData(d, null, null); } - private DirectorAppointmentData toData(DirectorAppointment d, String electionTitle) { - return toData(d, electionTitle, null); - } - private DirectorAppointmentData toData(DirectorAppointment d, String electionTitle, Long memberId) { return DirectorAppointmentData.builder() .id(d.getId()) diff --git a/fineract-provider/src/main/java/org/apache/fineract/portfolio/election/service/ElectionAnalyticsServiceImpl.java b/fineract-provider/src/main/java/org/apache/fineract/portfolio/election/service/ElectionAnalyticsServiceImpl.java index 9b8486b55..135150415 100644 --- a/fineract-provider/src/main/java/org/apache/fineract/portfolio/election/service/ElectionAnalyticsServiceImpl.java +++ b/fineract-provider/src/main/java/org/apache/fineract/portfolio/election/service/ElectionAnalyticsServiceImpl.java @@ -15,6 +15,7 @@ import java.time.Period; import java.util.ArrayList; import java.util.List; import java.util.Map; +import org.apache.fineract.infrastructure.core.service.DateUtils; @Slf4j @Service @@ -318,7 +319,7 @@ public class ElectionAnalyticsServiceImpl implements ElectionAnalyticsService { Object dob = info.get("date_of_birth"); if (dob instanceof java.sql.Date) { LocalDate dobDate = ((java.sql.Date) dob).toLocalDate(); - candidateAge = Period.between(dobDate, LocalDate.now()).getYears(); + candidateAge = Period.between(dobDate, LocalDate.now(DateUtils.getDateTimeZoneOfTenant())).getYears(); } // ── Voter pool ───────────────────────────────────────────────────────── diff --git a/fineract-provider/src/main/java/org/apache/fineract/portfolio/election/service/ElectionCeoPreCheckServiceImpl.java b/fineract-provider/src/main/java/org/apache/fineract/portfolio/election/service/ElectionCeoPreCheckServiceImpl.java index 86fdac62f..7dc3d6122 100644 --- a/fineract-provider/src/main/java/org/apache/fineract/portfolio/election/service/ElectionCeoPreCheckServiceImpl.java +++ b/fineract-provider/src/main/java/org/apache/fineract/portfolio/election/service/ElectionCeoPreCheckServiceImpl.java @@ -16,6 +16,7 @@ import java.time.LocalDate; import java.util.ArrayList; import java.util.List; import java.util.Map; +import org.apache.fineract.infrastructure.core.service.DateUtils; @Slf4j @Service @@ -104,7 +105,7 @@ public class ElectionCeoPreCheckServiceImpl implements ElectionCeoPreCheckServic if (status == null || status != 300) { String label = statusLabel(status); precheck.completeKycCheck(CheckResult.FAIL, "KYC not verified (status: " + label + ")"); - } else if (expiry != null && expiry.isBefore(LocalDate.now())) { + } else if (expiry != null && expiry.isBefore(LocalDate.now(DateUtils.getDateTimeZoneOfTenant()))) { precheck.completeKycCheck(CheckResult.FAIL, "KYC expired on " + expiry); } else { String expiryNote = expiry != null ? ", expires " + expiry : ""; @@ -155,7 +156,7 @@ public class ElectionCeoPreCheckServiceImpl implements ElectionCeoPreCheckServic issues.add(name + ": No KYC record"); } else if (status != 300) { issues.add(name + ": KYC not verified (" + statusLabel(status) + ")"); - } else if (expiry != null && expiry.isBefore(LocalDate.now())) { + } else if (expiry != null && expiry.isBefore(LocalDate.now(DateUtils.getDateTimeZoneOfTenant()))) { issues.add(name + ": KYC expired on " + expiry); } } diff --git a/fineract-provider/src/main/java/org/apache/fineract/portfolio/election/service/ElectionNoDueCertificateServiceImpl.java b/fineract-provider/src/main/java/org/apache/fineract/portfolio/election/service/ElectionNoDueCertificateServiceImpl.java index e1fa01603..f927a0462 100644 --- a/fineract-provider/src/main/java/org/apache/fineract/portfolio/election/service/ElectionNoDueCertificateServiceImpl.java +++ b/fineract-provider/src/main/java/org/apache/fineract/portfolio/election/service/ElectionNoDueCertificateServiceImpl.java @@ -8,6 +8,7 @@ import org.springframework.stereotype.Service; import java.time.LocalDate; import java.time.format.DateTimeFormatter; +import org.apache.fineract.infrastructure.core.service.DateUtils; @Slf4j @Service @@ -18,7 +19,7 @@ public class ElectionNoDueCertificateServiceImpl implements ElectionNoDueCertifi @Override public String generateCertificateNumber(ElectionNomination nomination) { - String datePart = LocalDate.now().format(DateTimeFormatter.ofPattern("yyyyMMdd")); + String datePart = LocalDate.now(DateUtils.getDateTimeZoneOfTenant()).format(DateTimeFormatter.ofPattern("yyyyMMdd")); return "NDC-" + datePart + "-" + String.format("%06d", nomination.getId()); } diff --git a/fineract-provider/src/main/java/org/apache/fineract/portfolio/election/service/ElectionReadPlatformServiceImpl.java b/fineract-provider/src/main/java/org/apache/fineract/portfolio/election/service/ElectionReadPlatformServiceImpl.java index ac72a3dd5..9fdf3c513 100644 --- a/fineract-provider/src/main/java/org/apache/fineract/portfolio/election/service/ElectionReadPlatformServiceImpl.java +++ b/fineract-provider/src/main/java/org/apache/fineract/portfolio/election/service/ElectionReadPlatformServiceImpl.java @@ -36,6 +36,7 @@ import java.util.HashMap; import java.util.List; import java.util.Map; import java.util.stream.Collectors; +import org.apache.fineract.infrastructure.core.service.DateUtils; @Service @RequiredArgsConstructor @@ -315,7 +316,7 @@ public class ElectionReadPlatformServiceImpl implements ElectionReadPlatformServ private ElectionNominationData toNominationData(ElectionNomination n) { Integer age = null; if (n.getDateOfBirth() != null) { - age = Period.between(n.getDateOfBirth(), LocalDate.now()).getYears(); + age = Period.between(n.getDateOfBirth(), LocalDate.now(DateUtils.getDateTimeZoneOfTenant())).getYears(); } return ElectionNominationData.builder() .id(n.getId()) diff --git a/fineract-provider/src/main/java/org/apache/fineract/portfolio/election/service/ElectionWritePlatformServiceImpl.java b/fineract-provider/src/main/java/org/apache/fineract/portfolio/election/service/ElectionWritePlatformServiceImpl.java index bef267c0e..51e727516 100644 --- a/fineract-provider/src/main/java/org/apache/fineract/portfolio/election/service/ElectionWritePlatformServiceImpl.java +++ b/fineract-provider/src/main/java/org/apache/fineract/portfolio/election/service/ElectionWritePlatformServiceImpl.java @@ -25,7 +25,6 @@ import org.apache.fineract.portfolio.election.domain.ElectionResult; import org.apache.fineract.portfolio.election.domain.ElectionResultRepository; import org.apache.fineract.portfolio.election.domain.ElectionStatus; import org.apache.fineract.portfolio.election.domain.ElectionType; -import org.apache.fineract.portfolio.election.domain.ElectionVote; import org.apache.fineract.portfolio.election.domain.ElectionVoteRepository; import org.apache.fineract.portfolio.election.domain.NominationStatus; import org.apache.fineract.portfolio.election.exception.ElectionAlreadyOngoingException; @@ -36,7 +35,6 @@ import org.apache.fineract.portfolio.election.exception.ElectionNominationNotFou import org.apache.fineract.portfolio.election.exception.ElectionNotActiveException; import org.apache.fineract.portfolio.election.exception.InvalidNominationStateException; import org.apache.fineract.portfolio.election.exception.NominationAlreadyExistsException; -import org.apache.fineract.portfolio.election.exception.VoteAlreadyCastException; import org.apache.fineract.portfolio.election.exception.VoteCountExceedsShareAccountsException; import org.apache.fineract.portfolio.election.exception.VoteCountsNotSavedException; import org.apache.fineract.infrastructure.contentstore.service.ContentStoreService; @@ -49,6 +47,7 @@ import java.util.HashMap; import java.util.List; import java.util.Map; import java.util.Set; +import org.apache.fineract.infrastructure.core.service.DateUtils; @Slf4j @Service @@ -93,7 +92,7 @@ public class ElectionWritePlatformServiceImpl implements ElectionWritePlatformSe throw new ElectionAlreadyOngoingException(); } - electionConfigRepository.findFirstWithActiveDuration(LocalDate.now()).ifPresent(prev -> { + electionConfigRepository.findFirstWithActiveDuration(LocalDate.now(DateUtils.getDateTimeZoneOfTenant())).ifPresent(prev -> { LocalDate expiryDate = prev.getElectionDate().plusYears(prev.getDurationYears()); throw new ElectionDurationActiveException(expiryDate); }); @@ -158,7 +157,7 @@ public class ElectionWritePlatformServiceImpl implements ElectionWritePlatformSe context.authenticatedUser().validateHasPermissionTo("UPDATE_ELECTION"); ElectionConfig election = electionConfigRepository.findById(electionId) .orElseThrow(() -> new ElectionNotFoundException(electionId)); - if (LocalDate.now().isBefore(election.getNominationEndDate())) { + if (LocalDate.now(DateUtils.getDateTimeZoneOfTenant()).isBefore(election.getNominationEndDate())) { throw new ElectionDateViolationException( "Cannot close nominations before the nomination end date " + election.getNominationEndDate()); } @@ -172,7 +171,7 @@ public class ElectionWritePlatformServiceImpl implements ElectionWritePlatformSe context.authenticatedUser().validateHasPermissionTo("UPDATE_ELECTION"); ElectionConfig election = electionConfigRepository.findById(electionId) .orElseThrow(() -> new ElectionNotFoundException(electionId)); - if (LocalDate.now().isBefore(election.getElectionDate())) { + if (LocalDate.now(DateUtils.getDateTimeZoneOfTenant()).isBefore(election.getElectionDate())) { throw new ElectionDateViolationException( "Cannot open voting before election date " + election.getElectionDate()); } @@ -187,7 +186,7 @@ public class ElectionWritePlatformServiceImpl implements ElectionWritePlatformSe ElectionConfig election = electionConfigRepository.findById(electionId) .orElseThrow(() -> new ElectionNotFoundException(electionId)); - if (LocalDate.now().isBefore(election.getElectionDate())) { + if (LocalDate.now(DateUtils.getDateTimeZoneOfTenant()).isBefore(election.getElectionDate())) { throw new ElectionDateViolationException( "Cannot close voting before election date " + election.getElectionDate()); } @@ -273,7 +272,7 @@ public class ElectionWritePlatformServiceImpl implements ElectionWritePlatformSe throw new InvalidNominationStateException("withdraw", nomination.getStatus().name()); } ElectionConfig election = nomination.getElectionConfig(); - if (LocalDate.now().isAfter(election.getNominationEndDate())) { + if (LocalDate.now(DateUtils.getDateTimeZoneOfTenant()).isAfter(election.getNominationEndDate())) { throw new ElectionDateViolationException( "Nomination withdrawal period has ended. Nominations closed on " + election.getNominationEndDate()); } @@ -290,7 +289,7 @@ public class ElectionWritePlatformServiceImpl implements ElectionWritePlatformSe throw new InvalidNominationStateException("resubmit", nomination.getStatus().name()); } ElectionConfig election = nomination.getElectionConfig(); - if (LocalDate.now().isAfter(election.getNominationEndDate())) { + if (LocalDate.now(DateUtils.getDateTimeZoneOfTenant()).isAfter(election.getNominationEndDate())) { throw new ElectionDateViolationException( "Nomination resubmission period has ended. Nominations closed on " + election.getNominationEndDate()); } @@ -466,7 +465,9 @@ public class ElectionWritePlatformServiceImpl implements ElectionWritePlatformSe String symbol = candidate.getSymbol(); if (symbol != null && !symbol.startsWith("data:") && symbol.contains("|")) { - try { contentStoreService.delete(symbol.split("\\|", 2)[1]); } catch (Exception ignored) {} + try { contentStoreService.delete(symbol.split("\\|", 2)[1]); } catch (Exception ignored) { + // intentionally ignored + } } candidate.deactivate(); @@ -584,7 +585,7 @@ public class ElectionWritePlatformServiceImpl implements ElectionWritePlatformSe ElectionConfig election = electionConfigRepository.findById(electionId) .orElseThrow(() -> new ElectionNotFoundException(electionId)); - LocalDate today = LocalDate.now(); + LocalDate today = LocalDate.now(DateUtils.getDateTimeZoneOfTenant()); LocalDate effectiveDate = election.getResultDate() != null ? election.getResultDate() : election.getElectionDate(); if (today.isBefore(effectiveDate)) { throw new ElectionDateViolationException( diff --git a/fineract-provider/src/main/java/org/apache/fineract/portfolio/election/service/MeetingVoteService.java b/fineract-provider/src/main/java/org/apache/fineract/portfolio/election/service/MeetingVoteService.java index 742219218..aa3b48aec 100644 --- a/fineract-provider/src/main/java/org/apache/fineract/portfolio/election/service/MeetingVoteService.java +++ b/fineract-provider/src/main/java/org/apache/fineract/portfolio/election/service/MeetingVoteService.java @@ -5,14 +5,41 @@ import lombok.extern.slf4j.Slf4j; import org.apache.fineract.infrastructure.email.service.EmailSenderService; import org.springframework.beans.factory.annotation.Value; import org.apache.fineract.portfolio.client.domain.ClientRepository; -import org.apache.fineract.portfolio.election.data.*; -import org.apache.fineract.portfolio.election.domain.*; +import org.apache.fineract.portfolio.election.data.AgendaResolutionRequest; +import org.apache.fineract.portfolio.election.data.AgendaVoteRequest; +import org.apache.fineract.portfolio.election.data.AgendaVoteSummaryData; +import org.apache.fineract.portfolio.election.data.MeetingVoteSubmitRequest; +import org.apache.fineract.portfolio.election.data.MeetingVotingPageData; +import org.apache.fineract.portfolio.election.domain.AgendaResolution; +import org.apache.fineract.portfolio.election.domain.AgendaVote; +import org.apache.fineract.portfolio.election.domain.Committee; +import org.apache.fineract.portfolio.election.domain.CommitteeMeeting; +import org.apache.fineract.portfolio.election.domain.CommitteeMeetingAgenda; +import org.apache.fineract.portfolio.election.domain.CommitteeMeetingRepository; +import org.apache.fineract.portfolio.election.domain.CommitteeMember; +import org.apache.fineract.portfolio.election.domain.CommitteeMemberRepository; +import org.apache.fineract.portfolio.election.domain.CommitteeRepository; +import org.apache.fineract.portfolio.election.domain.DirectorAppointment; +import org.apache.fineract.portfolio.election.domain.DirectorAppointmentRepository; +import org.apache.fineract.portfolio.election.domain.ElectionCandidate; +import org.apache.fineract.portfolio.election.domain.ElectionCandidateRepository; +import org.apache.fineract.portfolio.election.domain.MeetingAgendaResolution; +import org.apache.fineract.portfolio.election.domain.MeetingAgendaResolutionRepository; +import org.apache.fineract.portfolio.election.domain.MeetingMemberVote; +import org.apache.fineract.portfolio.election.domain.MeetingMemberVoteRepository; +import org.apache.fineract.portfolio.election.domain.MeetingVoteToken; +import org.apache.fineract.portfolio.election.domain.MeetingVoteTokenRepository; import org.springframework.stereotype.Service; import org.springframework.transaction.annotation.Transactional; import java.time.format.DateTimeFormatter; -import java.util.*; +import java.util.ArrayList; +import java.util.HashMap; +import java.util.List; +import java.util.Map; +import java.util.Set; import java.util.stream.Collectors; +import org.apache.fineract.infrastructure.core.service.DateUtils; @Slf4j @Service @@ -289,7 +316,7 @@ public class MeetingVoteService { String baseUrl = frontendBaseUrl + "/#/vote/" + token; String dateStr = meeting.getMeetingDate() != null ? meeting.getMeetingDate().format(DateTimeFormatter.ofPattern("dd MMMM yyyy")) : "—"; - String sentAt = java.time.LocalDateTime.now() + String sentAt = java.time.LocalDateTime.now(DateUtils.getDateTimeZoneOfTenant()) .format(DateTimeFormatter.ofPattern("dd MMM yyyy, hh:mm a")); StringBuilder sb = new StringBuilder(); @@ -397,7 +424,7 @@ public class MeetingVoteService { Map resMap) { String dateStr = meeting.getMeetingDate() != null ? meeting.getMeetingDate().format(DateTimeFormatter.ofPattern("dd MMMM yyyy")) : "—"; - String sentAt = java.time.LocalDateTime.now() + String sentAt = java.time.LocalDateTime.now(DateUtils.getDateTimeZoneOfTenant()) .format(DateTimeFormatter.ofPattern("dd MMM yyyy, hh:mm a")); StringBuilder sb = new StringBuilder(); diff --git a/fineract-provider/src/main/java/org/apache/fineract/portfolio/fundtransfer/domain/FundTransferEvent.java b/fineract-provider/src/main/java/org/apache/fineract/portfolio/fundtransfer/domain/FundTransferEvent.java index fdc6bf8da..d2d15bfd0 100644 --- a/fineract-provider/src/main/java/org/apache/fineract/portfolio/fundtransfer/domain/FundTransferEvent.java +++ b/fineract-provider/src/main/java/org/apache/fineract/portfolio/fundtransfer/domain/FundTransferEvent.java @@ -31,6 +31,7 @@ import java.time.LocalDateTime; import lombok.Getter; import lombok.NoArgsConstructor; import lombok.Setter; +import org.apache.fineract.infrastructure.core.service.DateUtils; /** Append-only audit row per state transition on a {@link FundTransfer}. */ @Entity @@ -76,7 +77,7 @@ public class FundTransferEvent { e.toStatus = to; e.event = event; e.payloadJson = payloadJson; - e.createdAt = LocalDateTime.now(); + e.createdAt = LocalDateTime.now(DateUtils.getDateTimeZoneOfTenant()); e.createdBy = createdBy; return e; } diff --git a/fineract-provider/src/main/java/org/apache/fineract/portfolio/fundtransfer/domain/VerificationToken.java b/fineract-provider/src/main/java/org/apache/fineract/portfolio/fundtransfer/domain/VerificationToken.java index 0bb378575..ab3e92453 100644 --- a/fineract-provider/src/main/java/org/apache/fineract/portfolio/fundtransfer/domain/VerificationToken.java +++ b/fineract-provider/src/main/java/org/apache/fineract/portfolio/fundtransfer/domain/VerificationToken.java @@ -31,6 +31,7 @@ import java.time.LocalDateTime; import lombok.Getter; import lombok.NoArgsConstructor; import lombok.Setter; +import org.apache.fineract.infrastructure.core.service.DateUtils; /** * Short-lived token issued at /v1/transfers/verify and redeemed at @@ -97,6 +98,6 @@ public class VerificationToken { private Long redeemedFundTransferId; public boolean isExpired() { - return LocalDateTime.now().isAfter(expiresAt); + return LocalDateTime.now(DateUtils.getDateTimeZoneOfTenant()).isAfter(expiresAt); } } diff --git a/fineract-provider/src/main/java/org/apache/fineract/portfolio/fundtransfer/service/FundTransferWritePlatformServiceImpl.java b/fineract-provider/src/main/java/org/apache/fineract/portfolio/fundtransfer/service/FundTransferWritePlatformServiceImpl.java index 2973e1b3c..cd4547541 100644 --- a/fineract-provider/src/main/java/org/apache/fineract/portfolio/fundtransfer/service/FundTransferWritePlatformServiceImpl.java +++ b/fineract-provider/src/main/java/org/apache/fineract/portfolio/fundtransfer/service/FundTransferWritePlatformServiceImpl.java @@ -54,6 +54,7 @@ import org.slf4j.Logger; import org.slf4j.LoggerFactory; import org.springframework.stereotype.Service; import org.springframework.transaction.annotation.Transactional; +import org.apache.fineract.infrastructure.core.service.DateUtils; @Service @RequiredArgsConstructor @@ -85,7 +86,7 @@ public class FundTransferWritePlatformServiceImpl implements FundTransferWritePl throw new IllegalArgumentException("amount must be > 0"); } TransferChannel channel = TransferChannel.from(request.getChannel()); - LocalDateTime now = LocalDateTime.now(); + LocalDateTime now = LocalDateTime.now(DateUtils.getDateTimeZoneOfTenant()); windowValidator.requireOpen(channel, LocalTime.from(now), now.getDayOfWeek()); AppUser cashier = context.authenticatedUser(); @@ -157,7 +158,7 @@ public class FundTransferWritePlatformServiceImpl implements FundTransferWritePl transfer.setPayeeMaskName(token.getPayeeMaskName()); transfer.setAmount(token.getAmount()); transfer.setRemarks(remarks); - transfer.setInitiatedAt(LocalDateTime.now()); + transfer.setInitiatedAt(LocalDateTime.now(DateUtils.getDateTimeZoneOfTenant())); if (!needsApproval) { executeStrategy(transfer); @@ -210,7 +211,7 @@ public class FundTransferWritePlatformServiceImpl implements FundTransferWritePl t.setStatus(FundTransferStatus.FAILED); t.setResponseCode("REJ"); t.setResponseMessage(reason); - t.setSettledAt(LocalDateTime.now()); + t.setSettledAt(LocalDateTime.now(DateUtils.getDateTimeZoneOfTenant())); FundTransfer saved = fundTransferRepository.save(t); eventRepository.save(FundTransferEvent.of(saved.getId(), prev, saved.getStatus(), "REJECTED", reason, approver.getId())); return FundTransferReadPlatformServiceImpl.toData(saved); @@ -235,7 +236,7 @@ public class FundTransferWritePlatformServiceImpl implements FundTransferWritePl t.setStatus(FundTransferStatus.REVERSED); t.setResponseCode("RCL"); t.setResponseMessage(reason == null ? "Recall initiated by ops" : reason); - t.setSettledAt(LocalDateTime.now()); + t.setSettledAt(LocalDateTime.now(DateUtils.getDateTimeZoneOfTenant())); FundTransfer saved = fundTransferRepository.save(t); String payload = "reason=" + reason + ", switch=" + switchOutcome; eventRepository.save(FundTransferEvent.of(saved.getId(), prev, saved.getStatus(), "RECALLED", payload, actor.getId())); @@ -290,7 +291,7 @@ public class FundTransferWritePlatformServiceImpl implements FundTransferWritePl transfer.setStatus(FundTransferStatus.FAILED); transfer.setResponseCode("ERR"); transfer.setResponseMessage(ex.getMessage()); - transfer.setSettledAt(LocalDateTime.now()); + transfer.setSettledAt(LocalDateTime.now(DateUtils.getDateTimeZoneOfTenant())); } if (transfer.getDirection() == TransferDirection.OFF_US && suspenseLegId != null @@ -362,6 +363,7 @@ public class FundTransferWritePlatformServiceImpl implements FundTransferWritePl * Masks a display name to the IMPS RespValAdd convention: first letter of each * word kept, rest replaced with up to 5 asterisks. "John Doe" → "J*** D**". */ + @SuppressWarnings("StringSplitter") static String maskName(String displayName) { if (displayName == null || displayName.isBlank()) { return null; @@ -409,7 +411,7 @@ public class FundTransferWritePlatformServiceImpl implements FundTransferWritePl if (limits.getPerDayMax() == null) { return; } - LocalDateTime startOfDay = LocalDate.now().atStartOfDay(); + LocalDateTime startOfDay = LocalDate.now(DateUtils.getDateTimeZoneOfTenant()).atStartOfDay(); BigDecimal already = fundTransferRepository.sumActiveOnChannelSince(payerAccountId, channel, startOfDay); if (already.add(amount).compareTo(limits.getPerDayMax()) > 0) { throw new IllegalStateException("daily limit exhausted for channel " + channel + " — already " + already diff --git a/fineract-provider/src/main/java/org/apache/fineract/portfolio/fundtransfer/service/ImpsDeemedReconciliationService.java b/fineract-provider/src/main/java/org/apache/fineract/portfolio/fundtransfer/service/ImpsDeemedReconciliationService.java index 725144df6..409454e46 100644 --- a/fineract-provider/src/main/java/org/apache/fineract/portfolio/fundtransfer/service/ImpsDeemedReconciliationService.java +++ b/fineract-provider/src/main/java/org/apache/fineract/portfolio/fundtransfer/service/ImpsDeemedReconciliationService.java @@ -34,6 +34,7 @@ import org.slf4j.Logger; import org.slf4j.LoggerFactory; import org.springframework.stereotype.Service; import org.springframework.transaction.annotation.Transactional; +import org.apache.fineract.infrastructure.core.service.DateUtils; /** * Polls the IMPS switch for DEEMED transfers (responseCode=91) to resolve them @@ -62,7 +63,7 @@ public class ImpsDeemedReconciliationService { /** Picks all DEEMED rows in the window and tries to resolve each. Returns count touched. */ public int reconcileAll() { - LocalDateTime now = LocalDateTime.now(); + LocalDateTime now = LocalDateTime.now(DateUtils.getDateTimeZoneOfTenant()); LocalDateTime floor = now.minusHours(MAX_AGE_HOURS); LocalDateTime ceiling = now.minusSeconds(MIN_AGE_SECONDS); List deemed = fundTransferRepository.findDeemedNeedingReconciliation(floor, ceiling); @@ -107,7 +108,7 @@ public class ImpsDeemedReconciliationService { if (resp.getUtr() != null) { transfer.setUtr(resp.getUtr()); } - transfer.setSettledAt(LocalDateTime.now()); + transfer.setSettledAt(LocalDateTime.now(DateUtils.getDateTimeZoneOfTenant())); if (newStatus == FundTransferStatus.FAILED) { suspenseGl.reverseFromSuspense(transfer); } diff --git a/fineract-provider/src/main/java/org/apache/fineract/portfolio/fundtransfer/service/NeftBatchProcessorService.java b/fineract-provider/src/main/java/org/apache/fineract/portfolio/fundtransfer/service/NeftBatchProcessorService.java index 838e1886d..adafb63ba 100644 --- a/fineract-provider/src/main/java/org/apache/fineract/portfolio/fundtransfer/service/NeftBatchProcessorService.java +++ b/fineract-provider/src/main/java/org/apache/fineract/portfolio/fundtransfer/service/NeftBatchProcessorService.java @@ -36,6 +36,7 @@ import org.slf4j.LoggerFactory; import org.springframework.beans.factory.annotation.Value; import org.springframework.stereotype.Service; import org.springframework.transaction.annotation.Transactional; +import org.apache.fineract.infrastructure.core.service.DateUtils; /** * Processes a NEFT batch cycle: picks all rows in QUEUED, sends each to the @@ -100,7 +101,7 @@ public class NeftBatchProcessorService { t.setSwitchTxnId(resp.getTxnId() == null ? t.getTxnRef() : resp.getTxnId()); t.setUtr(resp.getUtr()); if (mapped != FundTransferStatus.DEEMED) { - t.setSettledAt(LocalDateTime.now()); + t.setSettledAt(LocalDateTime.now(DateUtils.getDateTimeZoneOfTenant())); } if (mapped == FundTransferStatus.FAILED) { suspenseGl.reverseFromSuspense(t); @@ -114,7 +115,7 @@ public class NeftBatchProcessorService { t.setStatus(FundTransferStatus.FAILED); t.setResponseCode("ERR"); t.setResponseMessage(ex.getMessage()); - t.setSettledAt(LocalDateTime.now()); + t.setSettledAt(LocalDateTime.now(DateUtils.getDateTimeZoneOfTenant())); suspenseGl.reverseFromSuspense(t); fundTransferRepository.save(t); eventRepository.save(FundTransferEvent.of(t.getId(), prev, FundTransferStatus.FAILED, diff --git a/fineract-provider/src/main/java/org/apache/fineract/portfolio/fundtransfer/service/SuspenseGlService.java b/fineract-provider/src/main/java/org/apache/fineract/portfolio/fundtransfer/service/SuspenseGlService.java index d971e9c16..df0a40893 100644 --- a/fineract-provider/src/main/java/org/apache/fineract/portfolio/fundtransfer/service/SuspenseGlService.java +++ b/fineract-provider/src/main/java/org/apache/fineract/portfolio/fundtransfer/service/SuspenseGlService.java @@ -32,6 +32,7 @@ import org.slf4j.Logger; import org.slf4j.LoggerFactory; import org.springframework.beans.factory.annotation.Value; import org.springframework.stereotype.Service; +import org.apache.fineract.infrastructure.core.service.DateUtils; /** * Moves money between the customer's savings account and the bank's "in transit" @@ -129,7 +130,7 @@ public class SuspenseGlService { } private Long move(Long fromAccountId, Long toAccountId, FundTransfer t, String description) { - AccountTransferDTO dto = new AccountTransferDTO(LocalDate.now(), t.getAmount(), PortfolioAccountType.SAVINGS, + AccountTransferDTO dto = new AccountTransferDTO(LocalDate.now(DateUtils.getDateTimeZoneOfTenant()), t.getAmount(), PortfolioAccountType.SAVINGS, PortfolioAccountType.SAVINGS, fromAccountId, toAccountId, description, null, null, null, null, null, null, null, AccountTransferType.ACCOUNT_TRANSFER.getValue(), null, null, ExternalId.empty(), null, null, null, Boolean.TRUE, Boolean.FALSE); diff --git a/fineract-provider/src/main/java/org/apache/fineract/portfolio/fundtransfer/service/TransferChannelWindowValidator.java b/fineract-provider/src/main/java/org/apache/fineract/portfolio/fundtransfer/service/TransferChannelWindowValidator.java index a255f22fc..09ac33fc8 100644 --- a/fineract-provider/src/main/java/org/apache/fineract/portfolio/fundtransfer/service/TransferChannelWindowValidator.java +++ b/fineract-provider/src/main/java/org/apache/fineract/portfolio/fundtransfer/service/TransferChannelWindowValidator.java @@ -72,6 +72,7 @@ public class TransferChannelWindowValidator { } } + @SuppressWarnings("StringSplitter") private static boolean isHourInWindow(LocalTime now, String spec) { if (spec == null || spec.isBlank()) { return true; @@ -86,6 +87,7 @@ public class TransferChannelWindowValidator { return hour >= start && hour < end; } + @SuppressWarnings("StringSplitter") private static boolean isDayInWindow(DayOfWeek now, String spec) { if (spec == null || spec.isBlank()) { return true; diff --git a/fineract-provider/src/main/java/org/apache/fineract/portfolio/fundtransfer/service/TransferLimitResolver.java b/fineract-provider/src/main/java/org/apache/fineract/portfolio/fundtransfer/service/TransferLimitResolver.java index 95bf2f0f2..0fa226fec 100644 --- a/fineract-provider/src/main/java/org/apache/fineract/portfolio/fundtransfer/service/TransferLimitResolver.java +++ b/fineract-provider/src/main/java/org/apache/fineract/portfolio/fundtransfer/service/TransferLimitResolver.java @@ -29,6 +29,7 @@ import org.apache.fineract.portfolio.fundtransfer.domain.TransferChannel; import org.apache.fineract.portfolio.fundtransfer.domain.TransferLimitConfig; import org.apache.fineract.portfolio.fundtransfer.domain.TransferLimitConfigRepository; import org.springframework.stereotype.Service; +import org.apache.fineract.infrastructure.core.service.DateUtils; /** * Resolves effective per-customer-per-channel limits by overlaying any @@ -47,7 +48,7 @@ public class TransferLimitResolver { .orElseThrow(() -> new IllegalStateException( "No active m_transfer_limit_config for channel " + channel + " — seed missing?")); - Optional override = customerRepository.findEffective(clientId, channel, LocalDate.now()); + Optional override = customerRepository.findEffective(clientId, channel, LocalDate.now(DateUtils.getDateTimeZoneOfTenant())); BigDecimal perTxnMax = override.map(CustomerTransferLimit::getPerTxnMax).orElse(null); if (perTxnMax == null) { diff --git a/fineract-provider/src/main/java/org/apache/fineract/portfolio/fundtransfer/service/VerificationTokenCleanupService.java b/fineract-provider/src/main/java/org/apache/fineract/portfolio/fundtransfer/service/VerificationTokenCleanupService.java index 67f68a200..74aaadee4 100644 --- a/fineract-provider/src/main/java/org/apache/fineract/portfolio/fundtransfer/service/VerificationTokenCleanupService.java +++ b/fineract-provider/src/main/java/org/apache/fineract/portfolio/fundtransfer/service/VerificationTokenCleanupService.java @@ -26,6 +26,7 @@ import org.slf4j.LoggerFactory; import org.springframework.beans.factory.annotation.Value; import org.springframework.stereotype.Service; import org.springframework.transaction.annotation.Transactional; +import org.apache.fineract.infrastructure.core.service.DateUtils; /** * Two-phase cleanup of {@code m_verification_token}: @@ -51,7 +52,7 @@ public class VerificationTokenCleanupService { @Transactional public CleanupResult cleanup() { - LocalDateTime now = LocalDateTime.now(); + LocalDateTime now = LocalDateTime.now(DateUtils.getDateTimeZoneOfTenant()); int expired = repository.markExpired(now); int deleted = repository.deleteTerminalOlderThan(now.minusHours(retentionHours)); log.info("[VerificationTokenCleanup] flipped {} → EXPIRED, deleted {} terminal token(s) older than {}h", diff --git a/fineract-provider/src/main/java/org/apache/fineract/portfolio/fundtransfer/service/VerificationTokenService.java b/fineract-provider/src/main/java/org/apache/fineract/portfolio/fundtransfer/service/VerificationTokenService.java index 327e7c0ce..3c7a5e129 100644 --- a/fineract-provider/src/main/java/org/apache/fineract/portfolio/fundtransfer/service/VerificationTokenService.java +++ b/fineract-provider/src/main/java/org/apache/fineract/portfolio/fundtransfer/service/VerificationTokenService.java @@ -29,6 +29,7 @@ import org.apache.fineract.portfolio.fundtransfer.domain.VerificationTokenReposi import org.apache.fineract.portfolio.fundtransfer.domain.VerificationTokenStatus; import org.springframework.stereotype.Service; import org.springframework.transaction.annotation.Transactional; +import org.apache.fineract.infrastructure.core.service.DateUtils; /** Issues + redeems verification tokens (the BANL → debit bridge). */ @Service @@ -56,7 +57,7 @@ public class VerificationTokenService { t.setPayeeMaskName(payeeMaskName); t.setAmount(amount); t.setStatus(VerificationTokenStatus.ISSUED); - t.setIssuedAt(LocalDateTime.now()); + t.setIssuedAt(LocalDateTime.now(DateUtils.getDateTimeZoneOfTenant())); t.setExpiresAt(t.getIssuedAt().plusSeconds(TTL_SECONDS)); return repository.save(t); } @@ -78,7 +79,7 @@ public class VerificationTokenService { @Transactional public void markRedeemed(VerificationToken t, Long fundTransferId) { t.setStatus(VerificationTokenStatus.REDEEMED); - t.setRedeemedAt(LocalDateTime.now()); + t.setRedeemedAt(LocalDateTime.now(DateUtils.getDateTimeZoneOfTenant())); t.setRedeemedFundTransferId(fundTransferId); repository.save(t); } diff --git a/fineract-provider/src/main/java/org/apache/fineract/portfolio/fundtransfer/service/strategy/ImpsOutwardStrategy.java b/fineract-provider/src/main/java/org/apache/fineract/portfolio/fundtransfer/service/strategy/ImpsOutwardStrategy.java index bd821629c..bd2bee487 100644 --- a/fineract-provider/src/main/java/org/apache/fineract/portfolio/fundtransfer/service/strategy/ImpsOutwardStrategy.java +++ b/fineract-provider/src/main/java/org/apache/fineract/portfolio/fundtransfer/service/strategy/ImpsOutwardStrategy.java @@ -30,6 +30,7 @@ import org.slf4j.Logger; import org.slf4j.LoggerFactory; import org.springframework.beans.factory.annotation.Value; import org.springframework.stereotype.Component; +import org.apache.fineract.infrastructure.core.service.DateUtils; /** * IMPS outward via LincPay's ReqPay endpoint. Maps the IMPS response code to @@ -64,7 +65,7 @@ public class ImpsOutwardStrategy implements TransferStrategy { transfer.setStatus(FundTransferStatus.FAILED); transfer.setResponseCode("ERR"); transfer.setResponseMessage(ex.getMessage()); - transfer.setSettledAt(LocalDateTime.now()); + transfer.setSettledAt(LocalDateTime.now(DateUtils.getDateTimeZoneOfTenant())); } } @@ -106,7 +107,7 @@ public class ImpsOutwardStrategy implements TransferStrategy { }; transfer.setStatus(mapped); if (mapped != FundTransferStatus.DEEMED) { - transfer.setSettledAt(LocalDateTime.now()); + transfer.setSettledAt(LocalDateTime.now(DateUtils.getDateTimeZoneOfTenant())); } log.info("[ImpsOutwardStrategy] txnRef={} responseCode={} → status={} utr={}", transfer.getTxnRef(), code, mapped, transfer.getUtr()); diff --git a/fineract-provider/src/main/java/org/apache/fineract/portfolio/fundtransfer/service/strategy/InternalTransferStrategy.java b/fineract-provider/src/main/java/org/apache/fineract/portfolio/fundtransfer/service/strategy/InternalTransferStrategy.java index 83672ac66..c87327614 100644 --- a/fineract-provider/src/main/java/org/apache/fineract/portfolio/fundtransfer/service/strategy/InternalTransferStrategy.java +++ b/fineract-provider/src/main/java/org/apache/fineract/portfolio/fundtransfer/service/strategy/InternalTransferStrategy.java @@ -33,6 +33,7 @@ import org.apache.fineract.portfolio.savings.domain.SavingsAccount; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import org.springframework.stereotype.Component; +import org.apache.fineract.infrastructure.core.service.DateUtils; /** * On-us settlement — debits payer + credits payee atomically via Fineract's @@ -54,7 +55,7 @@ public class InternalTransferStrategy implements TransferStrategy { SavingsAccount payee = payeeLookup.findByAccountNumber(transfer.getPayeeAccountNumber()).orElseThrow( () -> new IllegalStateException("Payee account vanished between verify and debit: " + transfer.getPayeeAccountNumber())); - AccountTransferDTO dto = new AccountTransferDTO(LocalDate.now(), transfer.getAmount(), PortfolioAccountType.SAVINGS, + AccountTransferDTO dto = new AccountTransferDTO(LocalDate.now(DateUtils.getDateTimeZoneOfTenant()), transfer.getAmount(), PortfolioAccountType.SAVINGS, PortfolioAccountType.SAVINGS, transfer.getPayerAccountId(), payee.getId(), buildDescription(transfer), null, null, null, null, null, null, null, AccountTransferType.ACCOUNT_TRANSFER.getValue(), null, null, ExternalId.empty(), null, null, null, @@ -68,7 +69,7 @@ public class InternalTransferStrategy implements TransferStrategy { transfer.setStatus(FundTransferStatus.SUCCESS); transfer.setResponseCode("00"); transfer.setResponseMessage("Internal transfer settled"); - transfer.setSettledAt(LocalDateTime.now()); + transfer.setSettledAt(LocalDateTime.now(DateUtils.getDateTimeZoneOfTenant())); } private static String buildDescription(FundTransfer t) { diff --git a/fineract-provider/src/main/java/org/apache/fineract/portfolio/fundtransfer/service/strategy/RtgsOutwardStrategy.java b/fineract-provider/src/main/java/org/apache/fineract/portfolio/fundtransfer/service/strategy/RtgsOutwardStrategy.java index 1154cd0af..a394030b1 100644 --- a/fineract-provider/src/main/java/org/apache/fineract/portfolio/fundtransfer/service/strategy/RtgsOutwardStrategy.java +++ b/fineract-provider/src/main/java/org/apache/fineract/portfolio/fundtransfer/service/strategy/RtgsOutwardStrategy.java @@ -30,6 +30,7 @@ import org.slf4j.Logger; import org.slf4j.LoggerFactory; import org.springframework.beans.factory.annotation.Value; import org.springframework.stereotype.Component; +import org.apache.fineract.infrastructure.core.service.DateUtils; /** * RTGS outward — realtime, same shape as IMPS but routed to {@code /RTGS/ReqPay}. @@ -61,7 +62,7 @@ public class RtgsOutwardStrategy implements TransferStrategy { transfer.setStatus(FundTransferStatus.FAILED); transfer.setResponseCode("ERR"); transfer.setResponseMessage(ex.getMessage()); - transfer.setSettledAt(LocalDateTime.now()); + transfer.setSettledAt(LocalDateTime.now(DateUtils.getDateTimeZoneOfTenant())); } } @@ -103,7 +104,7 @@ public class RtgsOutwardStrategy implements TransferStrategy { }; transfer.setStatus(mapped); if (mapped != FundTransferStatus.DEEMED) { - transfer.setSettledAt(LocalDateTime.now()); + transfer.setSettledAt(LocalDateTime.now(DateUtils.getDateTimeZoneOfTenant())); } log.info("[RtgsOutwardStrategy] txnRef={} responseCode={} → status={} utr={}", transfer.getTxnRef(), code, mapped, transfer.getUtr()); diff --git a/fineract-provider/src/main/java/org/apache/fineract/portfolio/sanctions/api/SanctionsScreeningApiResource.java b/fineract-provider/src/main/java/org/apache/fineract/portfolio/sanctions/api/SanctionsScreeningApiResource.java index 2a1e6cb79..38f1c2477 100644 --- a/fineract-provider/src/main/java/org/apache/fineract/portfolio/sanctions/api/SanctionsScreeningApiResource.java +++ b/fineract-provider/src/main/java/org/apache/fineract/portfolio/sanctions/api/SanctionsScreeningApiResource.java @@ -30,7 +30,6 @@ import jakarta.ws.rs.POST; import jakarta.ws.rs.Path; import jakarta.ws.rs.Produces; import jakarta.ws.rs.QueryParam; -import jakarta.ws.rs.core.Context; import jakarta.ws.rs.core.MediaType; import java.io.InputStream; import java.util.HashMap; diff --git a/fineract-provider/src/main/java/org/apache/fineract/portfolio/savings/api/CurrentAccountTransactionsApiResource.java b/fineract-provider/src/main/java/org/apache/fineract/portfolio/savings/api/CurrentAccountTransactionsApiResource.java index 5addf6078..8cecd0a1a 100644 --- a/fineract-provider/src/main/java/org/apache/fineract/portfolio/savings/api/CurrentAccountTransactionsApiResource.java +++ b/fineract-provider/src/main/java/org/apache/fineract/portfolio/savings/api/CurrentAccountTransactionsApiResource.java @@ -40,7 +40,6 @@ import java.util.LinkedHashMap; import java.util.Map; import lombok.RequiredArgsConstructor; import org.apache.commons.lang3.StringUtils; -import org.apache.fineract.commands.domain.CommandWrapper; import org.apache.fineract.commands.service.CommandWrapperBuilder; import org.apache.fineract.commands.service.PortfolioCommandSourceWritePlatformService; import org.apache.fineract.infrastructure.core.data.CommandProcessingResult; @@ -55,6 +54,7 @@ import org.apache.fineract.portfolio.savings.DepositsApiConstants; import org.apache.fineract.portfolio.savings.data.SavingsAccountTransactionData; import org.springframework.jdbc.core.JdbcTemplate; import org.springframework.stereotype.Component; +import org.apache.fineract.infrastructure.core.service.DateUtils; @Path("/v1/currentaccounts/{accountId}/transactions") @Component @@ -91,7 +91,7 @@ public class CurrentAccountTransactionsApiResource { try { template = jdbcTemplate.queryForObject(sql, (rs, rowNum) -> { final Map map = new LinkedHashMap<>(); - final LocalDate today = LocalDate.now(); + final LocalDate today = LocalDate.now(DateUtils.getDateTimeZoneOfTenant()); map.put("date", new int[] { today.getYear(), today.getMonthValue(), today.getDayOfMonth() }); final Map currency = new LinkedHashMap<>(); diff --git a/fineract-provider/src/main/java/org/apache/fineract/portfolio/savings/api/CurrentAccountsApiResource.java b/fineract-provider/src/main/java/org/apache/fineract/portfolio/savings/api/CurrentAccountsApiResource.java index c73fa3095..61cc740d4 100644 --- a/fineract-provider/src/main/java/org/apache/fineract/portfolio/savings/api/CurrentAccountsApiResource.java +++ b/fineract-provider/src/main/java/org/apache/fineract/portfolio/savings/api/CurrentAccountsApiResource.java @@ -37,7 +37,6 @@ import jakarta.ws.rs.core.MediaType; import jakarta.ws.rs.core.UriInfo; import com.google.gson.Gson; import com.google.gson.GsonBuilder; -import com.google.gson.JsonParser; import java.time.LocalDate; import java.util.Collection; import java.util.List; diff --git a/fineract-provider/src/main/java/org/apache/fineract/portfolio/savings/domain/FdBaseInterestRateEffective.java b/fineract-provider/src/main/java/org/apache/fineract/portfolio/savings/domain/FdBaseInterestRateEffective.java index e5891c0f3..775a3dfa1 100644 --- a/fineract-provider/src/main/java/org/apache/fineract/portfolio/savings/domain/FdBaseInterestRateEffective.java +++ b/fineract-provider/src/main/java/org/apache/fineract/portfolio/savings/domain/FdBaseInterestRateEffective.java @@ -20,6 +20,7 @@ import jakarta.persistence.Table; import java.time.LocalDate; import lombok.Getter; import lombok.NoArgsConstructor; +import org.apache.fineract.infrastructure.core.service.DateUtils; @Entity @Table(name = "m_cbs_base_interest_rate_effective") @@ -64,7 +65,7 @@ public class FdBaseInterestRateEffective { e.isActive = true; e.remarks = remarks; e.createdById = createdById; - e.createdDate = LocalDate.now(); + e.createdDate = LocalDate.now(DateUtils.getDateTimeZoneOfTenant()); return e; } diff --git a/fineract-provider/src/main/java/org/apache/fineract/portfolio/savings/domain/FdBaseInterestRateSlabHistory.java b/fineract-provider/src/main/java/org/apache/fineract/portfolio/savings/domain/FdBaseInterestRateSlabHistory.java index 2b6e842f1..ae4822687 100644 --- a/fineract-provider/src/main/java/org/apache/fineract/portfolio/savings/domain/FdBaseInterestRateSlabHistory.java +++ b/fineract-provider/src/main/java/org/apache/fineract/portfolio/savings/domain/FdBaseInterestRateSlabHistory.java @@ -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_cbs_base_interest_rate_slab_history") @@ -70,7 +71,7 @@ public class FdBaseInterestRateSlabHistory { s.toPeriod = toPeriod; s.annualInterestRate = annualInterestRate; s.seniorCitizenRate = seniorCitizenRate; - s.createdDate = LocalDate.now(); + s.createdDate = LocalDate.now(DateUtils.getDateTimeZoneOfTenant()); return s; } } diff --git a/fineract-provider/src/main/java/org/apache/fineract/portfolio/savings/domain/RdBaseInterestRateEffective.java b/fineract-provider/src/main/java/org/apache/fineract/portfolio/savings/domain/RdBaseInterestRateEffective.java index 5bf874c92..e2b57770f 100644 --- a/fineract-provider/src/main/java/org/apache/fineract/portfolio/savings/domain/RdBaseInterestRateEffective.java +++ b/fineract-provider/src/main/java/org/apache/fineract/portfolio/savings/domain/RdBaseInterestRateEffective.java @@ -20,6 +20,7 @@ import jakarta.persistence.Table; import java.time.LocalDate; import lombok.Getter; import lombok.NoArgsConstructor; +import org.apache.fineract.infrastructure.core.service.DateUtils; @Entity @Table(name = "m_rd_base_interest_rate_effective") @@ -59,7 +60,7 @@ public class RdBaseInterestRateEffective { e.isActive = true; e.remarks = remarks; e.createdById = createdById; - e.createdDate = LocalDate.now(); + e.createdDate = LocalDate.now(DateUtils.getDateTimeZoneOfTenant()); return e; } diff --git a/fineract-provider/src/main/java/org/apache/fineract/portfolio/savings/domain/RdInterestRateEffective.java b/fineract-provider/src/main/java/org/apache/fineract/portfolio/savings/domain/RdInterestRateEffective.java index 11836f623..1f826d3cd 100644 --- a/fineract-provider/src/main/java/org/apache/fineract/portfolio/savings/domain/RdInterestRateEffective.java +++ b/fineract-provider/src/main/java/org/apache/fineract/portfolio/savings/domain/RdInterestRateEffective.java @@ -20,6 +20,7 @@ import jakarta.persistence.Table; import java.time.LocalDate; import lombok.Getter; import lombok.NoArgsConstructor; +import org.apache.fineract.infrastructure.core.service.DateUtils; /** * Maps to: m_rd_interest_rate_effective @@ -69,7 +70,7 @@ public class RdInterestRateEffective { e.isActive = true; e.remarks = remarks; e.createdById = createdById; - e.createdDate = LocalDate.now(); + e.createdDate = LocalDate.now(DateUtils.getDateTimeZoneOfTenant()); return e; } diff --git a/fineract-provider/src/main/java/org/apache/fineract/portfolio/savings/domain/SavingsAccountAssembler.java b/fineract-provider/src/main/java/org/apache/fineract/portfolio/savings/domain/SavingsAccountAssembler.java index 571ad5d98..95d28d2d9 100644 --- a/fineract-provider/src/main/java/org/apache/fineract/portfolio/savings/domain/SavingsAccountAssembler.java +++ b/fineract-provider/src/main/java/org/apache/fineract/portfolio/savings/domain/SavingsAccountAssembler.java @@ -72,7 +72,6 @@ import static org.apache.fineract.portfolio.savings.SavingsApiConstants.withHold import static org.apache.fineract.portfolio.savings.SavingsApiConstants.withdrawalFeeForTransfersParamName; import com.google.gson.Gson; -import com.google.gson.JsonArray; import com.google.gson.JsonElement; import com.google.gson.JsonObject; import java.math.BigDecimal; diff --git a/fineract-provider/src/main/java/org/apache/fineract/portfolio/savings/service/CurrentAccountEditWritePlatformServiceJpaRepositoryImpl.java b/fineract-provider/src/main/java/org/apache/fineract/portfolio/savings/service/CurrentAccountEditWritePlatformServiceJpaRepositoryImpl.java index d48f970d3..34f73ee2e 100644 --- a/fineract-provider/src/main/java/org/apache/fineract/portfolio/savings/service/CurrentAccountEditWritePlatformServiceJpaRepositoryImpl.java +++ b/fineract-provider/src/main/java/org/apache/fineract/portfolio/savings/service/CurrentAccountEditWritePlatformServiceJpaRepositoryImpl.java @@ -182,9 +182,9 @@ public class CurrentAccountEditWritePlatformServiceJpaRepositoryImpl implements nom.has("percentageShare") && !nom.get("percentageShare").isJsonNull() ? nom.get("percentageShare").getAsBigDecimal() : null); pendingEdit.setNomineeIsActive( - nom.has("isActive") && !nom.get("isActive").isJsonNull() ? nom.get("isActive").getAsBoolean() : null); + (nom.has("isActive") && !nom.get("isActive").isJsonNull()) ? nom.get("isActive").getAsBoolean() : null); pendingEdit.setNomineeIsMinor( - nom.has("nomineeIsMinor") && !nom.get("nomineeIsMinor").isJsonNull() ? nom.get("nomineeIsMinor").getAsBoolean() + (nom.has("nomineeIsMinor") && !nom.get("nomineeIsMinor").isJsonNull()) ? nom.get("nomineeIsMinor").getAsBoolean() : null); pendingEdit.setGuardianClientId( nom.has("guardianClientId") && !nom.get("guardianClientId").isJsonNull() ? nom.get("guardianClientId").getAsLong() diff --git a/fineract-provider/src/main/java/org/apache/fineract/portfolio/savings/service/CurrentAccountTransactionWritePlatformServiceImpl.java b/fineract-provider/src/main/java/org/apache/fineract/portfolio/savings/service/CurrentAccountTransactionWritePlatformServiceImpl.java index 8b5539d5e..ef3d5c60b 100644 --- a/fineract-provider/src/main/java/org/apache/fineract/portfolio/savings/service/CurrentAccountTransactionWritePlatformServiceImpl.java +++ b/fineract-provider/src/main/java/org/apache/fineract/portfolio/savings/service/CurrentAccountTransactionWritePlatformServiceImpl.java @@ -46,6 +46,7 @@ import org.apache.fineract.portfolio.currentproduct.domain.CurrentProductReposit import org.apache.fineract.portfolio.denominationmaster.service.DenominationBreakdownWriter; import org.springframework.stereotype.Service; import org.springframework.transaction.annotation.Transactional; +import org.apache.fineract.infrastructure.core.service.DateUtils; @Slf4j @Service @@ -72,7 +73,7 @@ public class CurrentAccountTransactionWritePlatformServiceImpl implements Curren final Office office = account.getOffice(); LocalDate txnDate = command.localDateValueOfParameterNamed("transactionDate"); - if (txnDate == null) txnDate = LocalDate.now(); + if (txnDate == null) txnDate = LocalDate.now(DateUtils.getDateTimeZoneOfTenant()); final BigDecimal amount = command.bigDecimalValueOfParameterNamed("transactionAmount"); validatePositiveAmount(amount, accountId, "deposit"); @@ -118,7 +119,7 @@ public class CurrentAccountTransactionWritePlatformServiceImpl implements Curren final Office office = account.getOffice(); LocalDate txnDate = command.localDateValueOfParameterNamed("transactionDate"); - if (txnDate == null) txnDate = LocalDate.now(); + if (txnDate == null) txnDate = LocalDate.now(DateUtils.getDateTimeZoneOfTenant()); final BigDecimal amount = command.bigDecimalValueOfParameterNamed("transactionAmount"); validatePositiveAmount(amount, accountId, "withdrawal"); @@ -186,7 +187,7 @@ public class CurrentAccountTransactionWritePlatformServiceImpl implements Curren final Office office = account.getOffice(); LocalDate txnDate = command.localDateValueOfParameterNamed("transactionDate"); - if (txnDate == null) txnDate = LocalDate.now(); + if (txnDate == null) txnDate = LocalDate.now(DateUtils.getDateTimeZoneOfTenant()); final BigDecimal amount = command.bigDecimalValueOfParameterNamed("transactionAmount"); validatePositiveAmount(amount, accountId, "hold amount"); @@ -250,7 +251,7 @@ public class CurrentAccountTransactionWritePlatformServiceImpl implements Curren // Create release transaction final CurrentAccountTransaction releaseTxn = CurrentAccountTransaction.releaseAmount( - account, office, holdAmount, LocalDate.now(), transactionId); + account, office, holdAmount, LocalDate.now(DateUtils.getDateTimeZoneOfTenant()), transactionId); releaseTxn.setRunningBalanceDerived(currentBalance); currentAccountTransactionRepository.saveAndFlush(releaseTxn); @@ -328,7 +329,7 @@ public class CurrentAccountTransactionWritePlatformServiceImpl implements Curren // Create a reversal entry final CurrentAccountTransaction reversalTxn = CurrentAccountTransaction.reversal( - account, account.getOffice(), original.getAmount(), LocalDate.now(), transactionId); + account, account.getOffice(), original.getAmount(), LocalDate.now(DateUtils.getDateTimeZoneOfTenant()), transactionId); reversalTxn.setRunningBalanceDerived(safeBalance(account.getAccountBalanceDerived())); currentAccountTransactionRepository.saveAndFlush(reversalTxn); diff --git a/fineract-provider/src/main/java/org/apache/fineract/portfolio/savings/service/CurrentAccountWritePlatformServiceImpl.java b/fineract-provider/src/main/java/org/apache/fineract/portfolio/savings/service/CurrentAccountWritePlatformServiceImpl.java index 41c270644..e4ec06386 100644 --- a/fineract-provider/src/main/java/org/apache/fineract/portfolio/savings/service/CurrentAccountWritePlatformServiceImpl.java +++ b/fineract-provider/src/main/java/org/apache/fineract/portfolio/savings/service/CurrentAccountWritePlatformServiceImpl.java @@ -21,7 +21,6 @@ package org.apache.fineract.portfolio.savings.service; import com.google.gson.JsonArray; import com.google.gson.JsonElement; import com.google.gson.JsonObject; -import com.google.gson.JsonParser; import java.time.LocalDate; import java.time.format.DateTimeFormatter; import lombok.RequiredArgsConstructor; @@ -106,7 +105,7 @@ public class CurrentAccountWritePlatformServiceImpl implements CurrentAccountWri final String locale = getString(json, "locale"); LocalDate submittedOnDate = parseDate(getString(json, "submittedOnDate"), dateFormat, locale); - if (submittedOnDate == null) submittedOnDate = LocalDate.now(); + if (submittedOnDate == null) submittedOnDate = LocalDate.now(DateUtils.getDateTimeZoneOfTenant()); // accountType (Fineract enum: 1=individual, 2=group) — try int, else default 1 Integer accountTypeEnum = 1; @@ -122,11 +121,11 @@ public class CurrentAccountWritePlatformServiceImpl implements CurrentAccountWri } } - boolean msme = json.has("msme") && !json.get("msme").isJsonNull() + boolean msme = (json.has("msme") && !json.get("msme").isJsonNull()) ? json.get("msme").getAsBoolean() : product.isMsme(); - boolean autoDebitFacility = json.has("autoDebitFacility") && !json.get("autoDebitFacility").isJsonNull() + boolean autoDebitFacility = (json.has("autoDebitFacility") && !json.get("autoDebitFacility").isJsonNull()) ? json.get("autoDebitFacility").getAsBoolean() : product.isAutoDebitFacility(); - boolean balanceSwapOption = json.has("balanceSwapOption") && !json.get("balanceSwapOption").isJsonNull() + boolean balanceSwapOption = (json.has("balanceSwapOption") && !json.get("balanceSwapOption").isJsonNull()) ? json.get("balanceSwapOption").getAsBoolean() : product.isBalanceSwapOption(); final AppUser user = context.authenticatedUser(); @@ -144,7 +143,7 @@ public class CurrentAccountWritePlatformServiceImpl implements CurrentAccountWri product.getAvgBalanceCalcPeriod()); account.setSubmittedOnByUser(user); - boolean shareLinkingEnabled = json.has("shareLinkingEnabled") && !json.get("shareLinkingEnabled").isJsonNull() + boolean shareLinkingEnabled = (json.has("shareLinkingEnabled") && !json.get("shareLinkingEnabled").isJsonNull()) ? json.get("shareLinkingEnabled").getAsBoolean() : product.isShareLinkingEnabled(); account.setShareLinkingEnabled(shareLinkingEnabled); @@ -269,7 +268,7 @@ public class CurrentAccountWritePlatformServiceImpl implements CurrentAccountWri final CurrentAccount account = findAccount(accountId); final JsonObject json = command.parsedJson().getAsJsonObject(); LocalDate approvedOnDate = parseDate(getString(json, "approvedOnDate"), getString(json, "dateFormat"), getString(json, "locale")); - if (approvedOnDate == null) approvedOnDate = LocalDate.now(); + if (approvedOnDate == null) approvedOnDate = LocalDate.now(DateUtils.getDateTimeZoneOfTenant()); account.approve(approvedOnDate, user); currentAccountRepository.saveAndFlush(account); return new CommandProcessingResultBuilder().withEntityId(accountId).build(); @@ -294,11 +293,13 @@ public class CurrentAccountWritePlatformServiceImpl implements CurrentAccountWri final CurrentAccount account = findAccount(accountId); final JsonObject json = command.parsedJson().getAsJsonObject(); LocalDate activatedOnDate = parseDate(getString(json, "activatedOnDate"), getString(json, "dateFormat"), getString(json, "locale")); - if (activatedOnDate == null) activatedOnDate = LocalDate.now(); + if (activatedOnDate == null) activatedOnDate = LocalDate.now(DateUtils.getDateTimeZoneOfTenant()); // Validate minimum opening balance before activation java.math.BigDecimal openingBalanceValue = java.math.BigDecimal.ZERO; if (json.has("openingBalance") && !json.get("openingBalance").isJsonNull()) { - try { openingBalanceValue = json.get("openingBalance").getAsBigDecimal(); } catch (Exception ignored) {} + try { openingBalanceValue = json.get("openingBalance").getAsBigDecimal(); } catch (Exception ignored) { + // intentionally ignored + } } final java.math.BigDecimal minRequired = account.getMinRequiredOpeningBalance(); if (minRequired != null && minRequired.compareTo(java.math.BigDecimal.ZERO) > 0 @@ -358,7 +359,7 @@ public class CurrentAccountWritePlatformServiceImpl implements CurrentAccountWri final CurrentAccount account = findAccount(accountId); final JsonObject json = command.parsedJson().getAsJsonObject(); LocalDate rejectedOnDate = parseDate(getString(json, "rejectedOnDate"), getString(json, "dateFormat"), getString(json, "locale")); - if (rejectedOnDate == null) rejectedOnDate = LocalDate.now(); + if (rejectedOnDate == null) rejectedOnDate = LocalDate.now(DateUtils.getDateTimeZoneOfTenant()); account.reject(rejectedOnDate, user); currentAccountRepository.saveAndFlush(account); return new CommandProcessingResultBuilder().withEntityId(accountId).build(); @@ -371,7 +372,7 @@ public class CurrentAccountWritePlatformServiceImpl implements CurrentAccountWri final CurrentAccount account = findAccount(accountId); final JsonObject json = command.parsedJson().getAsJsonObject(); LocalDate withdrawnOnDate = parseDate(getString(json, "withdrawnOnDate"), getString(json, "dateFormat"), getString(json, "locale")); - if (withdrawnOnDate == null) withdrawnOnDate = LocalDate.now(); + if (withdrawnOnDate == null) withdrawnOnDate = LocalDate.now(DateUtils.getDateTimeZoneOfTenant()); account.withdraw(withdrawnOnDate, user); currentAccountRepository.saveAndFlush(account); return new CommandProcessingResultBuilder().withEntityId(accountId).build(); @@ -384,7 +385,7 @@ public class CurrentAccountWritePlatformServiceImpl implements CurrentAccountWri final CurrentAccount account = findAccount(accountId); final JsonObject json = command.parsedJson().getAsJsonObject(); LocalDate closedOnDate = parseDate(getString(json, "closedOnDate"), getString(json, "dateFormat"), getString(json, "locale")); - if (closedOnDate == null) closedOnDate = LocalDate.now(); + if (closedOnDate == null) closedOnDate = LocalDate.now(DateUtils.getDateTimeZoneOfTenant()); account.close(closedOnDate, user); currentAccountRepository.saveAndFlush(account); return new CommandProcessingResultBuilder().withEntityId(accountId).build(); @@ -449,13 +450,17 @@ public class CurrentAccountWritePlatformServiceImpl implements CurrentAccountWri try { account.setEstablishmentDate(LocalDate.parse(json.get("establishmentDate").getAsString(), DateTimeFormatter.ofPattern(dateFormat))); - } catch (Exception ignored) {} + } catch (Exception ignored) { + // intentionally ignored + } } if (json.has("startOperationDate") && !json.get("startOperationDate").isJsonNull()) { try { account.setStartOperationDate(LocalDate.parse(json.get("startOperationDate").getAsString(), DateTimeFormatter.ofPattern(dateFormat))); - } catch (Exception ignored) {} + } catch (Exception ignored) { + // intentionally ignored + } } // facility config @@ -566,7 +571,9 @@ public class CurrentAccountWritePlatformServiceImpl implements CurrentAccountWri if (jo.has("signingAuthority") && !jo.get("signingAuthority").isJsonNull()) holder.setSigningAuthority(jo.get("signingAuthority").getAsString()); if (jo.has("role") && !jo.get("role").isJsonNull()) holder.setRole(jo.get("role").getAsString()); if (jo.has("sharePercentage") && !jo.get("sharePercentage").isJsonNull()) { - try { holder.setSharePercentage(jo.get("sharePercentage").getAsBigDecimal()); } catch (Exception ignored) {} + try { holder.setSharePercentage(jo.get("sharePercentage").getAsBigDecimal()); } catch (Exception ignored) { + // intentionally ignored + } } if (jo.has("isPrimary") && !jo.get("isPrimary").isJsonNull()) holder.setPrimary(jo.get("isPrimary").getAsBoolean()); if (jo.has("isMandatory") && !jo.get("isMandatory").isJsonNull()) holder.setMandatory(jo.get("isMandatory").getAsBoolean()); @@ -584,7 +591,9 @@ public class CurrentAccountWritePlatformServiceImpl implements CurrentAccountWri if (jo.has("clientCif") && !jo.get("clientCif").isJsonNull()) partner.setClientCif(jo.get("clientCif").getAsString()); if (jo.has("clientName") && !jo.get("clientName").isJsonNull()) partner.setClientName(jo.get("clientName").getAsString()); if (jo.has("sharePercentage") && !jo.get("sharePercentage").isJsonNull()) { - try { partner.setSharePercentage(jo.get("sharePercentage").getAsBigDecimal()); } catch (Exception ignored) {} + try { partner.setSharePercentage(jo.get("sharePercentage").getAsBigDecimal()); } catch (Exception ignored) { + // intentionally ignored + } } if (jo.has("isMandatory") && !jo.get("isMandatory").isJsonNull()) partner.setMandatory(jo.get("isMandatory").getAsBoolean()); account.getPartners().add(partner); diff --git a/fineract-provider/src/main/java/org/apache/fineract/portfolio/savings/service/DepositProductReadPlatformServiceImpl.java b/fineract-provider/src/main/java/org/apache/fineract/portfolio/savings/service/DepositProductReadPlatformServiceImpl.java index 2be58645f..d431acb5b 100644 --- a/fineract-provider/src/main/java/org/apache/fineract/portfolio/savings/service/DepositProductReadPlatformServiceImpl.java +++ b/fineract-provider/src/main/java/org/apache/fineract/portfolio/savings/service/DepositProductReadPlatformServiceImpl.java @@ -19,7 +19,6 @@ package org.apache.fineract.portfolio.savings.service; import com.google.gson.Gson; -import com.google.gson.reflect.TypeToken; import java.math.BigDecimal; import java.sql.ResultSet; import java.sql.SQLException; diff --git a/fineract-provider/src/main/java/org/apache/fineract/portfolio/savings/service/FdBaseInterestRateReadPlatformServiceImpl.java b/fineract-provider/src/main/java/org/apache/fineract/portfolio/savings/service/FdBaseInterestRateReadPlatformServiceImpl.java index baf53d972..516eb97c8 100644 --- a/fineract-provider/src/main/java/org/apache/fineract/portfolio/savings/service/FdBaseInterestRateReadPlatformServiceImpl.java +++ b/fineract-provider/src/main/java/org/apache/fineract/portfolio/savings/service/FdBaseInterestRateReadPlatformServiceImpl.java @@ -23,6 +23,7 @@ import org.apache.fineract.portfolio.savings.domain.FdBaseInterestRateEffectiveR import org.apache.fineract.portfolio.savings.domain.FdBaseInterestRateSlabHistory; import org.apache.fineract.portfolio.savings.domain.FdBaseInterestRateSlabHistoryRepository; import org.springframework.transaction.annotation.Transactional; +import org.apache.fineract.infrastructure.core.service.DateUtils; @RequiredArgsConstructor public class FdBaseInterestRateReadPlatformServiceImpl implements FdBaseInterestRateReadPlatformService { @@ -51,7 +52,7 @@ public class FdBaseInterestRateReadPlatformServiceImpl implements FdBaseInterest @Transactional public FdInterestRateEffectiveData saveInterestRates(FdInterestRateSaveRequest request, Long createdById) { final String fdType = request.getFdType(); - final LocalDate today = LocalDate.now(); + final LocalDate today = LocalDate.now(DateUtils.getDateTimeZoneOfTenant()); final List activeVersions = effectiveRepository .findByFdTypeAndIsActiveTrueOrderByEffectiveFromDateDesc(fdType); @@ -64,7 +65,7 @@ public class FdBaseInterestRateReadPlatformServiceImpl implements FdBaseInterest final String label = request.getVersionLabel() != null && !request.getVersionLabel().isBlank() ? request.getVersionLabel() - : "FD " + fdType + " Rate Version " + LocalDate.now(); + : "FD " + fdType + " Rate Version " + LocalDate.now(DateUtils.getDateTimeZoneOfTenant()); FdBaseInterestRateEffective newVersion = FdBaseInterestRateEffective.create(fdType, label, today, request.getRemarks(), createdById); newVersion = effectiveRepository.saveAndFlush(newVersion); diff --git a/fineract-provider/src/main/java/org/apache/fineract/portfolio/savings/service/FixedDepositAccountInterestCalculationServiceImpl.java b/fineract-provider/src/main/java/org/apache/fineract/portfolio/savings/service/FixedDepositAccountInterestCalculationServiceImpl.java index 54355aba7..061e1ce94 100644 --- a/fineract-provider/src/main/java/org/apache/fineract/portfolio/savings/service/FixedDepositAccountInterestCalculationServiceImpl.java +++ b/fineract-provider/src/main/java/org/apache/fineract/portfolio/savings/service/FixedDepositAccountInterestCalculationServiceImpl.java @@ -62,7 +62,9 @@ public class FixedDepositAccountInterestCalculationServiceImpl implements FixedD if (dateStr != null && dateFormat != null) { submittedOnDate = LocalDate.parse(dateStr, java.time.format.DateTimeFormatter.ofPattern(dateFormat)); } - } catch (Exception ignored) {} + } catch (Exception ignored) { + // intentionally ignored + } Integer daysInYear = null; final Long daysInYearLong = this.fromApiJsonHelper.extractLongNamed("daysInYear", element); if (daysInYearLong != null) daysInYear = daysInYearLong.intValue(); diff --git a/fineract-provider/src/main/java/org/apache/fineract/portfolio/savings/service/RdBaseInterestRateReadPlatformServiceImpl.java b/fineract-provider/src/main/java/org/apache/fineract/portfolio/savings/service/RdBaseInterestRateReadPlatformServiceImpl.java index ea622e2d3..c2c25dcc6 100644 --- a/fineract-provider/src/main/java/org/apache/fineract/portfolio/savings/service/RdBaseInterestRateReadPlatformServiceImpl.java +++ b/fineract-provider/src/main/java/org/apache/fineract/portfolio/savings/service/RdBaseInterestRateReadPlatformServiceImpl.java @@ -29,6 +29,7 @@ import org.apache.fineract.portfolio.savings.domain.RdBaseInterestRateEffectiveR import org.apache.fineract.portfolio.savings.domain.RdBaseInterestRateSlabHistory; import org.apache.fineract.portfolio.savings.domain.RdBaseInterestRateSlabHistoryRepository; import org.springframework.transaction.annotation.Transactional; +import org.apache.fineract.infrastructure.core.service.DateUtils; @RequiredArgsConstructor public class RdBaseInterestRateReadPlatformServiceImpl implements RdBaseInterestRateReadPlatformService { @@ -54,7 +55,7 @@ public class RdBaseInterestRateReadPlatformServiceImpl implements RdBaseInterest validateRequest(request); final List normalizedSlabs = normalizeSlabs(request.getSlabs()); - final LocalDate today = LocalDate.now(); + final LocalDate today = LocalDate.now(DateUtils.getDateTimeZoneOfTenant()); final List activeVersions = effectiveRepository.findByIsActiveTrueOrderByEffectiveFromDateDesc(); for (RdBaseInterestRateEffective version : activeVersions) { version.deactivate(today); @@ -65,9 +66,9 @@ public class RdBaseInterestRateReadPlatformServiceImpl implements RdBaseInterest final String label = request.getVersionLabel() != null && !request.getVersionLabel().isBlank() ? request.getVersionLabel() - : "CBS Base Rate Version " + LocalDate.now(); + : "CBS Base Rate Version " + LocalDate.now(DateUtils.getDateTimeZoneOfTenant()); - RdBaseInterestRateEffective newVersion = RdBaseInterestRateEffective.create(label, LocalDate.now(), request.getRemarks(), createdById); + RdBaseInterestRateEffective newVersion = RdBaseInterestRateEffective.create(label, LocalDate.now(DateUtils.getDateTimeZoneOfTenant()), request.getRemarks(), createdById); newVersion = effectiveRepository.saveAndFlush(newVersion); final Long versionId = newVersion.getId(); diff --git a/fineract-provider/src/main/java/org/apache/fineract/portfolio/savings/service/RdInterestRateReadPlatformServiceImpl.java b/fineract-provider/src/main/java/org/apache/fineract/portfolio/savings/service/RdInterestRateReadPlatformServiceImpl.java index 830ddb9f3..d6a19aad4 100644 --- a/fineract-provider/src/main/java/org/apache/fineract/portfolio/savings/service/RdInterestRateReadPlatformServiceImpl.java +++ b/fineract-provider/src/main/java/org/apache/fineract/portfolio/savings/service/RdInterestRateReadPlatformServiceImpl.java @@ -29,6 +29,7 @@ import org.apache.fineract.portfolio.savings.domain.RdInterestRateEffectiveRepos import org.apache.fineract.portfolio.savings.domain.RdInterestRateSlabHistory; import org.apache.fineract.portfolio.savings.domain.RdInterestRateSlabHistoryRepository; import org.springframework.transaction.annotation.Transactional; +import org.apache.fineract.infrastructure.core.service.DateUtils; @RequiredArgsConstructor public class RdInterestRateReadPlatformServiceImpl implements RdInterestRateReadPlatformService { @@ -59,7 +60,7 @@ public class RdInterestRateReadPlatformServiceImpl implements RdInterestRateRead final List normalizedSlabs = normalizeSlabs(request.getSlabs()); // 1. Deactivate all current active versions for this product, preserving end dates for audit/history. - final LocalDate today = LocalDate.now(); + final LocalDate today = LocalDate.now(DateUtils.getDateTimeZoneOfTenant()); final List activeVersions = effectiveRepository .findByProductIdAndIsActiveTrueOrderByEffectiveFromDateDesc(productId); for (RdInterestRateEffective version : activeVersions) { @@ -72,10 +73,10 @@ public class RdInterestRateReadPlatformServiceImpl implements RdInterestRateRead // 2. Create the new version header String label = request.getVersionLabel() != null && !request.getVersionLabel().isBlank() ? request.getVersionLabel() - : "Rate Version " + LocalDate.now(); + : "Rate Version " + LocalDate.now(DateUtils.getDateTimeZoneOfTenant()); RdInterestRateEffective newVersion = RdInterestRateEffective.create( - productId, label, LocalDate.now(), request.getRemarks(), createdById); + productId, label, LocalDate.now(DateUtils.getDateTimeZoneOfTenant()), request.getRemarks(), createdById); newVersion = effectiveRepository.saveAndFlush(newVersion); // 3. Insert slabs for the new version diff --git a/fineract-provider/src/main/java/org/apache/fineract/portfolio/savings/service/RecurringDepositAccountInterestCalculationServiceImpl.java b/fineract-provider/src/main/java/org/apache/fineract/portfolio/savings/service/RecurringDepositAccountInterestCalculationServiceImpl.java index f9379f53a..4a7709a25 100644 --- a/fineract-provider/src/main/java/org/apache/fineract/portfolio/savings/service/RecurringDepositAccountInterestCalculationServiceImpl.java +++ b/fineract-provider/src/main/java/org/apache/fineract/portfolio/savings/service/RecurringDepositAccountInterestCalculationServiceImpl.java @@ -35,6 +35,7 @@ import org.apache.fineract.infrastructure.core.api.JsonQuery; import org.apache.fineract.infrastructure.core.serialization.FromJsonHelper; import org.apache.fineract.organisation.monetary.domain.MoneyHelper; import org.springframework.stereotype.Service; +import org.apache.fineract.infrastructure.core.service.DateUtils; @Service @RequiredArgsConstructor @@ -52,7 +53,7 @@ public class RecurringDepositAccountInterestCalculationServiceImpl implements Re element); LocalDate submittedOnDate = this.fromApiJsonHelper.extractLocalDateNamed("submittedOnDate", element); if (submittedOnDate == null) { - submittedOnDate = LocalDate.now(); + submittedOnDate = LocalDate.now(DateUtils.getDateTimeZoneOfTenant()); } BigDecimal maturityAmount = this.calculateInterestInternal(depositAmount, annualInterestRate, tenureInMonths, diff --git a/fineract-provider/src/main/java/org/apache/fineract/portfolio/savings/service/SavingsAccountEditWritePlatformServiceJpaRepositoryImpl.java b/fineract-provider/src/main/java/org/apache/fineract/portfolio/savings/service/SavingsAccountEditWritePlatformServiceJpaRepositoryImpl.java index 19c590261..241198c7c 100644 --- a/fineract-provider/src/main/java/org/apache/fineract/portfolio/savings/service/SavingsAccountEditWritePlatformServiceJpaRepositoryImpl.java +++ b/fineract-provider/src/main/java/org/apache/fineract/portfolio/savings/service/SavingsAccountEditWritePlatformServiceJpaRepositoryImpl.java @@ -146,8 +146,8 @@ public class SavingsAccountEditWritePlatformServiceJpaRepositoryImpl implements pendingEdit.setNomineeClientId(nom.has("nomineeClientId") && !nom.get("nomineeClientId").isJsonNull() ? nom.get("nomineeClientId").getAsLong() : null); pendingEdit.setRelationshipCvId(nom.has("relationshipId") && !nom.get("relationshipId").isJsonNull() ? nom.get("relationshipId").getAsLong() : null); pendingEdit.setPercentageShare(nom.has("percentageShare") && !nom.get("percentageShare").isJsonNull() ? nom.get("percentageShare").getAsBigDecimal() : null); - pendingEdit.setNomineeIsActive(nom.has("isActive") && !nom.get("isActive").isJsonNull() ? nom.get("isActive").getAsBoolean() : null); - pendingEdit.setNomineeIsMinor(nom.has("nomineeIsMinor") && !nom.get("nomineeIsMinor").isJsonNull() ? nom.get("nomineeIsMinor").getAsBoolean() : null); + pendingEdit.setNomineeIsActive((nom.has("isActive") && !nom.get("isActive").isJsonNull()) ? nom.get("isActive").getAsBoolean() : null); + pendingEdit.setNomineeIsMinor((nom.has("nomineeIsMinor") && !nom.get("nomineeIsMinor").isJsonNull()) ? nom.get("nomineeIsMinor").getAsBoolean() : null); pendingEdit.setGuardianClientId(nom.has("guardianClientId") && !nom.get("guardianClientId").isJsonNull() ? nom.get("guardianClientId").getAsLong() : null); pendingEdit.setGuardianRelationshipCvId(nom.has("guardianRelationshipId") && !nom.get("guardianRelationshipId").isJsonNull() ? nom.get("guardianRelationshipId").getAsLong() : null); pendingEdit.setEffectiveDate(nom.has("effectiveDate") && !nom.get("effectiveDate").isJsonNull() ? LocalDate.parse(nom.get("effectiveDate").getAsString()) : null); diff --git a/fineract-provider/src/main/java/org/apache/fineract/portfolio/savings/service/SavingsAccountReadPlatformServiceImpl.java b/fineract-provider/src/main/java/org/apache/fineract/portfolio/savings/service/SavingsAccountReadPlatformServiceImpl.java index 471e82962..ce7ce86fc 100644 --- a/fineract-provider/src/main/java/org/apache/fineract/portfolio/savings/service/SavingsAccountReadPlatformServiceImpl.java +++ b/fineract-provider/src/main/java/org/apache/fineract/portfolio/savings/service/SavingsAccountReadPlatformServiceImpl.java @@ -1142,7 +1142,9 @@ public class SavingsAccountReadPlatformServiceImpl implements SavingsAccountRead java.util.Map nomineeMap = gson.fromJson(nomineeDataStr, new com.google.gson.reflect.TypeToken>() {}.getType()); accountData.setNomineeData(nomineeMap); - } catch (Exception ignored) {} + } catch (Exception ignored) { + // intentionally ignored + } } // Facility config diff --git a/fineract-provider/src/main/java/org/apache/fineract/portfolio/savings/service/SavingsAccountWritePlatformServiceJpaRepositoryImpl.java b/fineract-provider/src/main/java/org/apache/fineract/portfolio/savings/service/SavingsAccountWritePlatformServiceJpaRepositoryImpl.java index 6ec884712..33a14e8c0 100644 --- a/fineract-provider/src/main/java/org/apache/fineract/portfolio/savings/service/SavingsAccountWritePlatformServiceJpaRepositoryImpl.java +++ b/fineract-provider/src/main/java/org/apache/fineract/portfolio/savings/service/SavingsAccountWritePlatformServiceJpaRepositoryImpl.java @@ -35,7 +35,6 @@ import io.github.resilience4j.retry.annotation.Retry; import java.math.BigDecimal; import java.math.MathContext; import java.time.LocalDate; -import java.time.LocalDateTime; import java.time.format.DateTimeFormatter; import java.util.ArrayList; import java.util.Collection; diff --git a/fineract-provider/src/main/java/org/apache/fineract/portfolio/savings/service/SavingsProductWritePlatformServiceJpaRepositoryImpl.java b/fineract-provider/src/main/java/org/apache/fineract/portfolio/savings/service/SavingsProductWritePlatformServiceJpaRepositoryImpl.java index 5a2ee8187..e45876e82 100644 --- a/fineract-provider/src/main/java/org/apache/fineract/portfolio/savings/service/SavingsProductWritePlatformServiceJpaRepositoryImpl.java +++ b/fineract-provider/src/main/java/org/apache/fineract/portfolio/savings/service/SavingsProductWritePlatformServiceJpaRepositoryImpl.java @@ -79,7 +79,6 @@ import org.apache.fineract.portfolio.savings.exception.SavingsProductNotFoundExc import org.apache.fineract.portfolio.savings.exception.SavingsProductSelfApprovalNotAllowedException; import org.apache.fineract.portfolio.tax.domain.TaxGroup; import org.apache.fineract.useradministration.domain.AppUser; -import org.springframework.beans.factory.annotation.Autowired; import org.springframework.dao.DataAccessException; import org.springframework.transaction.annotation.Transactional; diff --git a/fineract-provider/src/main/java/org/apache/fineract/portfolio/savings/starter/SavingsConfiguration.java b/fineract-provider/src/main/java/org/apache/fineract/portfolio/savings/starter/SavingsConfiguration.java index cb8915828..45d888cdf 100644 --- a/fineract-provider/src/main/java/org/apache/fineract/portfolio/savings/starter/SavingsConfiguration.java +++ b/fineract-provider/src/main/java/org/apache/fineract/portfolio/savings/starter/SavingsConfiguration.java @@ -94,17 +94,14 @@ import org.apache.fineract.portfolio.savings.domain.SavingsAccountTransactionRep import org.apache.fineract.portfolio.savings.domain.SavingsHelper; import org.apache.fineract.portfolio.savings.domain.SavingsProductAssembler; import org.apache.fineract.portfolio.savings.domain.SavingsProductDepositLimitKycRepository; -import org.apache.fineract.portfolio.savings.domain.SavingsProductFacilityConfig; import org.apache.fineract.portfolio.savings.domain.SavingsProductFacilityConfigRepository; import org.apache.fineract.portfolio.savings.domain.ProductPendingEditRepository; import org.apache.fineract.portfolio.savings.domain.ProductPendingEditSubmittedFieldRepository; import org.apache.fineract.portfolio.savings.domain.ProductPendingEditChargeRepository; import org.apache.fineract.portfolio.savings.domain.ProductPendingEditGlMappingRepository; import org.apache.fineract.commands.domain.CommandSourceRepository; -import org.apache.fineract.portfolio.savings.domain.SavingsProductFacilityLimit; import org.apache.fineract.portfolio.savings.domain.SavingsProductFacilityLimitRepository; import org.apache.fineract.portfolio.savings.domain.SavingsProductRepository; -import org.apache.fineract.portfolio.denominationmaster.domain.SavingsTxnDenominationRepository; import org.apache.fineract.portfolio.savings.service.FacilityChargeAutoApplyService; import org.apache.fineract.portfolio.savings.service.DepositAccountInterestRateChartReadPlatformService; import org.apache.fineract.portfolio.savings.service.DepositAccountInterestRateChartReadPlatformServiceImpl; diff --git a/fineract-provider/src/main/java/org/apache/fineract/portfolio/shareaccounts/domain/ShareAccountPendingEdit.java b/fineract-provider/src/main/java/org/apache/fineract/portfolio/shareaccounts/domain/ShareAccountPendingEdit.java index 7f18b507a..a2d033bd1 100644 --- a/fineract-provider/src/main/java/org/apache/fineract/portfolio/shareaccounts/domain/ShareAccountPendingEdit.java +++ b/fineract-provider/src/main/java/org/apache/fineract/portfolio/shareaccounts/domain/ShareAccountPendingEdit.java @@ -32,6 +32,7 @@ import org.apache.fineract.infrastructure.core.domain.AbstractPersistableCustom; import org.apache.fineract.portfolio.common.domain.PeriodFrequencyType; import org.apache.fineract.portfolio.savings.domain.SavingsAccount; import org.apache.fineract.useradministration.domain.AppUser; +import org.apache.fineract.infrastructure.core.service.DateUtils; /** * Holds a pending edit request for a Share Account's "details" fields (linked savings account, @@ -108,7 +109,7 @@ public class ShareAccountPendingEdit extends AbstractPersistableCustom { public ShareAccountPendingEdit(final ShareAccount shareAccount, final AppUser maker) { this.shareAccount = shareAccount; this.maker = maker; - this.createdOn = LocalDateTime.now(); + this.createdOn = LocalDateTime.now(DateUtils.getDateTimeZoneOfTenant()); this.status = STATUS_PENDING; this.pendingLockKey = lockKeyFor(shareAccount.getId()); } @@ -124,14 +125,14 @@ public class ShareAccountPendingEdit extends AbstractPersistableCustom { public void markApproved(final AppUser checker) { this.status = STATUS_APPROVED; this.checker = checker; - this.checkedOn = LocalDateTime.now(); + this.checkedOn = LocalDateTime.now(DateUtils.getDateTimeZoneOfTenant()); 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 = LocalDateTime.now(DateUtils.getDateTimeZoneOfTenant()); this.rejectReason = reason; this.pendingLockKey = null; } diff --git a/fineract-provider/src/main/java/org/apache/fineract/portfolio/shareaccounts/service/ShareAccountEditWritePlatformServiceJpaRepositoryImpl.java b/fineract-provider/src/main/java/org/apache/fineract/portfolio/shareaccounts/service/ShareAccountEditWritePlatformServiceJpaRepositoryImpl.java index f039e2dc7..77d7290c9 100644 --- a/fineract-provider/src/main/java/org/apache/fineract/portfolio/shareaccounts/service/ShareAccountEditWritePlatformServiceJpaRepositoryImpl.java +++ b/fineract-provider/src/main/java/org/apache/fineract/portfolio/shareaccounts/service/ShareAccountEditWritePlatformServiceJpaRepositoryImpl.java @@ -38,7 +38,6 @@ import org.apache.fineract.infrastructure.security.service.PlatformSecurityConte import org.apache.fineract.portfolio.accounts.constants.ShareAccountApiConstants; import org.apache.fineract.portfolio.common.domain.PeriodFrequencyType; import org.apache.fineract.portfolio.savings.DepositAccountType; -import org.apache.fineract.portfolio.savings.domain.SavingsAccount; import org.apache.fineract.portfolio.savings.domain.SavingsAccountRepositoryWrapper; import org.apache.fineract.portfolio.savings.exception.SavingsAccountNotFoundException; import org.apache.fineract.portfolio.savings.service.SavingsAccountReadPlatformService; diff --git a/fineract-provider/src/main/java/org/apache/fineract/portfolio/shareproducts/service/ShareProductReadPlatformServiceImpl.java b/fineract-provider/src/main/java/org/apache/fineract/portfolio/shareproducts/service/ShareProductReadPlatformServiceImpl.java index a9525484e..0651f7de2 100644 --- a/fineract-provider/src/main/java/org/apache/fineract/portfolio/shareproducts/service/ShareProductReadPlatformServiceImpl.java +++ b/fineract-provider/src/main/java/org/apache/fineract/portfolio/shareproducts/service/ShareProductReadPlatformServiceImpl.java @@ -19,7 +19,6 @@ package org.apache.fineract.portfolio.shareproducts.service; import com.google.gson.Gson; -import com.google.gson.reflect.TypeToken; import java.math.BigDecimal; import java.sql.Date; import java.sql.ResultSet; diff --git a/fineract-provider/src/main/java/org/apache/fineract/portfolio/sponsordd/api/SponsorBankApiResource.java b/fineract-provider/src/main/java/org/apache/fineract/portfolio/sponsordd/api/SponsorBankApiResource.java index 4e482007d..c006f010a 100644 --- a/fineract-provider/src/main/java/org/apache/fineract/portfolio/sponsordd/api/SponsorBankApiResource.java +++ b/fineract-provider/src/main/java/org/apache/fineract/portfolio/sponsordd/api/SponsorBankApiResource.java @@ -46,6 +46,7 @@ import org.apache.fineract.portfolio.sponsordd.domain.SponsorBank; import org.apache.fineract.portfolio.sponsordd.domain.SponsorBankRepository; import org.apache.fineract.useradministration.domain.AppUser; import org.springframework.stereotype.Component; +import org.apache.fineract.infrastructure.core.service.DateUtils; @Path("/v1/sponsorbanks") @Component @@ -106,7 +107,7 @@ public class SponsorBankApiResource { request.getBankCode(), request.getSwiftCode() != null ? request.getSwiftCode().trim().toUpperCase() : null, currentUser, - LocalDateTime.now() + LocalDateTime.now(DateUtils.getDateTimeZoneOfTenant()) ); this.sponsorBankRepository.saveAndFlush(sponsorBank); return new CommandProcessingResultBuilder().withEntityId(sponsorBank.getId()).build(); diff --git a/fineract-provider/src/main/java/org/apache/fineract/portfolio/sponsordd/service/SponsorDDIssueRequestWritePlatformServiceImpl.java b/fineract-provider/src/main/java/org/apache/fineract/portfolio/sponsordd/service/SponsorDDIssueRequestWritePlatformServiceImpl.java index 2b1ba3fb0..792daa49c 100644 --- a/fineract-provider/src/main/java/org/apache/fineract/portfolio/sponsordd/service/SponsorDDIssueRequestWritePlatformServiceImpl.java +++ b/fineract-provider/src/main/java/org/apache/fineract/portfolio/sponsordd/service/SponsorDDIssueRequestWritePlatformServiceImpl.java @@ -38,12 +38,12 @@ import org.apache.fineract.infrastructure.security.service.PlatformSecurityConte import org.apache.fineract.portfolio.sponsordd.data.SponsorDDBatchIssueResult; import org.apache.fineract.portfolio.sponsordd.data.SponsorDDSlipLine; import org.apache.fineract.useradministration.domain.AppUser; -import org.springframework.dao.EmptyResultDataAccessException; import org.springframework.jdbc.core.JdbcTemplate; import org.springframework.jdbc.support.GeneratedKeyHolder; import org.springframework.jdbc.support.KeyHolder; import org.springframework.stereotype.Service; import org.springframework.transaction.annotation.Transactional; +import org.apache.fineract.infrastructure.core.service.DateUtils; @Service @RequiredArgsConstructor @@ -135,7 +135,7 @@ public class SponsorDDIssueRequestWritePlatformServiceImpl implements SponsorDDI } final KeyHolder kh = new GeneratedKeyHolder(); - final LocalDateTime now = LocalDateTime.now(java.time.Clock.systemDefaultZone()); + final LocalDateTime now = LocalDateTime.now(DateUtils.getDateTimeZoneOfTenant()); final String finalWalkinAadhaarMasked = walkinPurchaserAadhaarMasked; final Long finalCashReceiptJournalEntryId = cashReceiptJournalEntryId; final Long finalCashierDepositRequestId = METHOD_CASH.equals(paymentMethod) ? cashierDepositRequestId : null; @@ -266,7 +266,7 @@ public class SponsorDDIssueRequestWritePlatformServiceImpl implements SponsorDDI final List> allocatedLeaflets = allocateAvailableLeaflets(inventoryId, lines.size()); - final LocalDateTime now = LocalDateTime.now(java.time.Clock.systemDefaultZone()); + final LocalDateTime now = LocalDateTime.now(DateUtils.getDateTimeZoneOfTenant()); Long batchId = null; final List resultLines = new java.util.ArrayList<>(); for (int i = 0; i < lines.size(); i++) { @@ -487,7 +487,7 @@ public class SponsorDDIssueRequestWritePlatformServiceImpl implements SponsorDDI resultingSavingsTransactionId, resultingCurrentTransactionId, resultingJournalEntryId, payableAtBranch, payableAtCity); - final LocalDateTime now = LocalDateTime.now(java.time.Clock.systemDefaultZone()); + final LocalDateTime now = LocalDateTime.now(DateUtils.getDateTimeZoneOfTenant()); this.jdbcTemplate.update( "UPDATE m_sponsor_dd_issue_request SET status = ?, checker_id = ?, checker_date = ?, " + "resulting_savings_transaction_id = ?, resulting_current_transaction_id = ?, resulting_journal_entry_id = ? " @@ -534,7 +534,7 @@ public class SponsorDDIssueRequestWritePlatformServiceImpl implements SponsorDDI faceValue.add(effectiveCharges).add(effectiveGst), null, null, issuingBranchId, issuedDate, refundComments, null); } - final LocalDateTime now = LocalDateTime.now(java.time.Clock.systemDefaultZone()); + final LocalDateTime now = LocalDateTime.now(DateUtils.getDateTimeZoneOfTenant()); this.jdbcTemplate.update( "UPDATE m_sponsor_dd_issue_request SET status = ?, checker_id = ?, checker_date = ?, rejection_reason = ?, " + "cash_refund_journal_entry_id = ? WHERE id = ?", @@ -643,7 +643,7 @@ public class SponsorDDIssueRequestWritePlatformServiceImpl implements SponsorDDI (String) request.get("payable_at_branch"), (String) request.get("payable_at_city")); } - final LocalDateTime now = LocalDateTime.now(java.time.Clock.systemDefaultZone()); + final LocalDateTime now = LocalDateTime.now(DateUtils.getDateTimeZoneOfTenant()); this.jdbcTemplate.update( "UPDATE m_sponsor_dd_issue_request SET status = ?, checker_id = ?, checker_date = ?, " + "resulting_savings_transaction_id = ?, resulting_current_transaction_id = ?, resulting_journal_entry_id = ? " @@ -674,7 +674,7 @@ public class SponsorDDIssueRequestWritePlatformServiceImpl implements SponsorDDI // No cash refund leg here - a slip only supports ACCOUNT_DEBIT/CHEQUE, neither of which moves // any money before approval (unlike the single-DD CASH path). - final LocalDateTime now = LocalDateTime.now(java.time.Clock.systemDefaultZone()); + final LocalDateTime now = LocalDateTime.now(DateUtils.getDateTimeZoneOfTenant()); this.jdbcTemplate.update( "UPDATE m_sponsor_dd_issue_request SET status = ?, checker_id = ?, checker_date = ?, rejection_reason = ? " + "WHERE batch_id = ?", @@ -740,7 +740,7 @@ public class SponsorDDIssueRequestWritePlatformServiceImpl implements SponsorDDI ps.setBigDecimal(6, effectiveGstPercentage); if (gstPayableGlAccountId != null) ps.setLong(7, gstPayableGlAccountId); else ps.setNull(7, java.sql.Types.BIGINT); if (ddLimitAmount != null) ps.setBigDecimal(8, ddLimitAmount); else ps.setNull(8, java.sql.Types.DECIMAL); - ps.setObject(9, LocalDateTime.now(java.time.Clock.systemDefaultZone())); + ps.setObject(9, LocalDateTime.now(DateUtils.getDateTimeZoneOfTenant())); return ps; }, kh); final long newId = Objects.requireNonNull(kh.getKey()).longValue(); diff --git a/fineract-provider/src/main/java/org/apache/fineract/portfolio/sponsordd/service/SponsorDDReconciliationServiceImpl.java b/fineract-provider/src/main/java/org/apache/fineract/portfolio/sponsordd/service/SponsorDDReconciliationServiceImpl.java index 3f7998fc5..214623549 100644 --- a/fineract-provider/src/main/java/org/apache/fineract/portfolio/sponsordd/service/SponsorDDReconciliationServiceImpl.java +++ b/fineract-provider/src/main/java/org/apache/fineract/portfolio/sponsordd/service/SponsorDDReconciliationServiceImpl.java @@ -25,6 +25,7 @@ import java.security.NoSuchAlgorithmException; import java.time.LocalDate; import java.time.LocalDateTime; import java.time.format.DateTimeFormatter; +import java.util.Locale; import java.util.ArrayList; import java.util.List; import java.util.Optional; @@ -50,6 +51,7 @@ 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; +import org.apache.fineract.infrastructure.core.service.DateUtils; @Service public class SponsorDDReconciliationServiceImpl implements SponsorDDReconciliationService { @@ -85,6 +87,7 @@ public class SponsorDDReconciliationServiceImpl implements SponsorDDReconciliati @Override @Transactional + @SuppressWarnings("StringSplitter") public SponsorDDRecoBatch uploadAndReconcile(final String fileName, final String fileContent) { final AppUser currentUser = this.context.authenticatedUser(); @@ -105,7 +108,7 @@ public class SponsorDDReconciliationServiceImpl implements SponsorDDReconciliati for (int i = 0; i < rows.length; i++) { final String row = rows[i].trim(); - if (row.isEmpty() || i == 0 && row.toLowerCase().contains("dd_number")) { + if (row.isEmpty() || (i == 0 && row.toLowerCase(Locale.ROOT).contains("dd_number"))) { // Skip empty lines or CSV header continue; } @@ -126,7 +129,7 @@ public class SponsorDDReconciliationServiceImpl implements SponsorDDReconciliati } // 3. Create batch record - final String batchRef = "RECO-" + LocalDate.now().toString().replace("-", "") + "-" + UUID.randomUUID().toString().substring(0, 8).toUpperCase(); + final String batchRef = "RECO-" + LocalDate.now(DateUtils.getDateTimeZoneOfTenant()).toString().replace("-", "") + "-" + UUID.randomUUID().toString().substring(0, 8).toUpperCase(); SponsorDDRecoBatch batch = new SponsorDDRecoBatch( batchRef, fileName, @@ -137,7 +140,7 @@ public class SponsorDDReconciliationServiceImpl implements SponsorDDReconciliati 0, 0, currentUser, - LocalDateTime.now(), + LocalDateTime.now(DateUtils.getDateTimeZoneOfTenant()), null, null ); @@ -177,7 +180,7 @@ public class SponsorDDReconciliationServiceImpl implements SponsorDDReconciliati leaflet.setStatus("CLEARED"); leaflet.setClearedDate(pr.clearingDate); leaflet.setLastModifiedBy(currentUser); - leaflet.setLastModifiedDate(LocalDateTime.now()); + leaflet.setLastModifiedDate(LocalDateTime.now(DateUtils.getDateTimeZoneOfTenant())); this.leafletRepository.save(leaflet); // Create clearing transaction mapping @@ -188,7 +191,7 @@ public class SponsorDDReconciliationServiceImpl implements SponsorDDReconciliati null, "CLEARING", pr.clearingAmount, - LocalDateTime.now() + LocalDateTime.now(DateUtils.getDateTimeZoneOfTenant()) ); this.transactionRepository.save(ddTxn); @@ -202,7 +205,7 @@ public class SponsorDDReconciliationServiceImpl implements SponsorDDReconciliati "127.0.0.1", null, "Sponsor clearing scroll auto-match. Ref: " + pr.clearingRef, - LocalDateTime.now() + LocalDateTime.now(DateUtils.getDateTimeZoneOfTenant()) ); this.auditLogRepository.save(auditLog); } @@ -235,7 +238,7 @@ public class SponsorDDReconciliationServiceImpl implements SponsorDDReconciliati batch.setMismatchCount(mismatchCount); batch.setStatus(mismatchCount > 0 ? "PARTIALLY_RECONCILED" : "RECONCILED"); batch.setLastModifiedBy(currentUser); - batch.setLastModifiedDate(LocalDateTime.now()); + batch.setLastModifiedDate(LocalDateTime.now(DateUtils.getDateTimeZoneOfTenant())); this.batchRepository.save(batch); return batch; @@ -275,7 +278,7 @@ public class SponsorDDReconciliationServiceImpl implements SponsorDDReconciliati leaflet.setStatus("CLEARED"); leaflet.setClearedDate(record.getClearingDate()); leaflet.setLastModifiedBy(currentUser); - leaflet.setLastModifiedDate(LocalDateTime.now()); + leaflet.setLastModifiedDate(LocalDateTime.now(DateUtils.getDateTimeZoneOfTenant())); this.leafletRepository.saveAndFlush(leaflet); // Create transaction link @@ -286,7 +289,7 @@ public class SponsorDDReconciliationServiceImpl implements SponsorDDReconciliati null, "CLEARING", record.getClearingAmount(), - LocalDateTime.now() + LocalDateTime.now(DateUtils.getDateTimeZoneOfTenant()) ); this.transactionRepository.save(ddTxn); @@ -300,7 +303,7 @@ public class SponsorDDReconciliationServiceImpl implements SponsorDDReconciliati "127.0.0.1", null, "Manual reconciliation override (Force Match) approved by checker.", - LocalDateTime.now() + LocalDateTime.now(DateUtils.getDateTimeZoneOfTenant()) ); this.auditLogRepository.save(auditLog); } @@ -308,7 +311,7 @@ public class SponsorDDReconciliationServiceImpl implements SponsorDDReconciliati record.setMatchStatus("RESOLVED"); record.setRemarks("Manually resolved by force-match override."); record.setResolvedBy(currentUser); - record.setResolvedDate(LocalDateTime.now()); + record.setResolvedDate(LocalDateTime.now(DateUtils.getDateTimeZoneOfTenant())); this.recordRepository.save(record); // Update batch counts @@ -318,7 +321,7 @@ public class SponsorDDReconciliationServiceImpl implements SponsorDDReconciliati batch.setStatus("RECONCILED"); } batch.setLastModifiedBy(currentUser); - batch.setLastModifiedDate(LocalDateTime.now()); + batch.setLastModifiedDate(LocalDateTime.now(DateUtils.getDateTimeZoneOfTenant())); this.batchRepository.save(batch); } diff --git a/fineract-provider/src/main/java/org/apache/fineract/portfolio/sponsordd/service/SponsorDDReprintRequestWritePlatformServiceImpl.java b/fineract-provider/src/main/java/org/apache/fineract/portfolio/sponsordd/service/SponsorDDReprintRequestWritePlatformServiceImpl.java index 478614383..d9fb69083 100644 --- a/fineract-provider/src/main/java/org/apache/fineract/portfolio/sponsordd/service/SponsorDDReprintRequestWritePlatformServiceImpl.java +++ b/fineract-provider/src/main/java/org/apache/fineract/portfolio/sponsordd/service/SponsorDDReprintRequestWritePlatformServiceImpl.java @@ -32,6 +32,7 @@ import org.springframework.jdbc.support.GeneratedKeyHolder; import org.springframework.jdbc.support.KeyHolder; import org.springframework.stereotype.Service; import org.springframework.transaction.annotation.Transactional; +import org.apache.fineract.infrastructure.core.service.DateUtils; @Service @RequiredArgsConstructor @@ -52,7 +53,7 @@ public class SponsorDDReprintRequestWritePlatformServiceImpl implements SponsorD throw new IllegalStateException("Only an issued Demand Draft can be printed. Current status: " + leaflet.get("status")); } final int printCount = ((Number) leaflet.get("print_count")).intValue(); - final LocalDateTime now = LocalDateTime.now(java.time.Clock.systemDefaultZone()); + final LocalDateTime now = LocalDateTime.now(DateUtils.getDateTimeZoneOfTenant()); if (printCount == 0) { this.jdbcTemplate.update( @@ -101,7 +102,7 @@ public class SponsorDDReprintRequestWritePlatformServiceImpl implements SponsorD } final KeyHolder kh = new GeneratedKeyHolder(); - final LocalDateTime now = LocalDateTime.now(java.time.Clock.systemDefaultZone()); + final LocalDateTime now = LocalDateTime.now(DateUtils.getDateTimeZoneOfTenant()); this.jdbcTemplate.update(con -> { final java.sql.PreparedStatement ps = con.prepareStatement( "INSERT INTO m_sponsor_dd_reprint_request (leaflet_id, reason, status, maker_id, created_date) " @@ -133,7 +134,7 @@ public class SponsorDDReprintRequestWritePlatformServiceImpl implements SponsorD throw new IllegalStateException("You cannot approve your own reprint request."); } - final LocalDateTime now = LocalDateTime.now(java.time.Clock.systemDefaultZone()); + final LocalDateTime now = LocalDateTime.now(DateUtils.getDateTimeZoneOfTenant()); this.jdbcTemplate.update( "UPDATE m_sponsor_dd_reprint_request SET status = ?, checker_id = ?, checker_date = ? WHERE id = ?", STATUS_APPROVED, currentUser.getId(), now, reprintRequestId); @@ -155,7 +156,7 @@ public class SponsorDDReprintRequestWritePlatformServiceImpl implements SponsorD throw new IllegalStateException("You cannot reject your own reprint request."); } - final LocalDateTime now = LocalDateTime.now(java.time.Clock.systemDefaultZone()); + final LocalDateTime now = LocalDateTime.now(DateUtils.getDateTimeZoneOfTenant()); this.jdbcTemplate.update( "UPDATE m_sponsor_dd_reprint_request SET status = ?, checker_id = ?, checker_date = ?, rejection_reason = ? WHERE id = ?", STATUS_REJECTED, currentUser.getId(), now, rejectionReason, reprintRequestId); diff --git a/fineract-provider/src/main/java/org/apache/fineract/portfolio/sponsordd/service/SponsorDDWritePlatformServiceImpl.java b/fineract-provider/src/main/java/org/apache/fineract/portfolio/sponsordd/service/SponsorDDWritePlatformServiceImpl.java index d7c85c5ed..624162726 100644 --- a/fineract-provider/src/main/java/org/apache/fineract/portfolio/sponsordd/service/SponsorDDWritePlatformServiceImpl.java +++ b/fineract-provider/src/main/java/org/apache/fineract/portfolio/sponsordd/service/SponsorDDWritePlatformServiceImpl.java @@ -21,6 +21,7 @@ package org.apache.fineract.portfolio.sponsordd.service; import java.math.BigDecimal; import java.time.LocalDate; import java.time.LocalDateTime; +import org.apache.fineract.infrastructure.core.service.DateUtils; import java.util.ArrayList; import java.util.List; import org.apache.fineract.accounting.journalentry.domain.JournalEntry; @@ -121,7 +122,7 @@ public class SponsorDDWritePlatformServiceImpl implements SponsorDDWritePlatform receivedDate, "ACTIVE", currentUser, - LocalDateTime.now(), + DateUtils.getLocalDateTimeOfTenant(), null, null ); @@ -151,7 +152,7 @@ public class SponsorDDWritePlatformServiceImpl implements SponsorDDWritePlatform null, 1, currentUser, - LocalDateTime.now(), + DateUtils.getLocalDateTimeOfTenant(), null, null ); @@ -171,7 +172,7 @@ public class SponsorDDWritePlatformServiceImpl implements SponsorDDWritePlatform "127.0.0.1", null, "Draft leaflet registered into inventory.", - LocalDateTime.now() + DateUtils.getLocalDateTimeOfTenant() ); auditLogs.add(auditLog); } @@ -234,7 +235,7 @@ public class SponsorDDWritePlatformServiceImpl implements SponsorDDWritePlatform leaflet.setIssuedDate(issuedDate); leaflet.setAdviceStatus("NOT_SENT"); leaflet.setLastModifiedBy(currentUser); - leaflet.setLastModifiedDate(LocalDateTime.now()); + leaflet.setLastModifiedDate(DateUtils.getLocalDateTimeOfTenant()); this.leafletRepository.saveAndFlush(leaflet); @@ -246,7 +247,7 @@ public class SponsorDDWritePlatformServiceImpl implements SponsorDDWritePlatform journalEntry, "ISSUANCE", faceValue, - LocalDateTime.now() + DateUtils.getLocalDateTimeOfTenant() ); this.transactionRepository.save(ddTransaction); @@ -260,7 +261,7 @@ public class SponsorDDWritePlatformServiceImpl implements SponsorDDWritePlatform "127.0.0.1", null, "Demand draft issued to customer.", - LocalDateTime.now() + DateUtils.getLocalDateTimeOfTenant() ); this.auditLogRepository.save(auditLog); @@ -297,7 +298,7 @@ public class SponsorDDWritePlatformServiceImpl implements SponsorDDWritePlatform final String preStatus = leaflet.getStatus(); leaflet.setStatus("CANCELLED"); leaflet.setLastModifiedBy(currentUser); - leaflet.setLastModifiedDate(LocalDateTime.now()); + leaflet.setLastModifiedDate(DateUtils.getLocalDateTimeOfTenant()); this.leafletRepository.saveAndFlush(leaflet); @@ -309,7 +310,7 @@ public class SponsorDDWritePlatformServiceImpl implements SponsorDDWritePlatform null, "CANCELLATION", leaflet.getFaceValue(), - LocalDateTime.now() + DateUtils.getLocalDateTimeOfTenant() ); this.transactionRepository.save(ddTransaction); @@ -323,7 +324,7 @@ public class SponsorDDWritePlatformServiceImpl implements SponsorDDWritePlatform "127.0.0.1", null, remarks != null ? remarks : "Demand draft cancelled and refunded.", - LocalDateTime.now() + DateUtils.getLocalDateTimeOfTenant() ); this.auditLogRepository.save(auditLog); @@ -347,7 +348,7 @@ public class SponsorDDWritePlatformServiceImpl implements SponsorDDWritePlatform final String preStatus = leaflet.getStatus(); leaflet.setStatus("STOPPED"); leaflet.setLastModifiedBy(currentUser); - leaflet.setLastModifiedDate(LocalDateTime.now()); + leaflet.setLastModifiedDate(DateUtils.getLocalDateTimeOfTenant()); this.leafletRepository.saveAndFlush(leaflet); @@ -359,7 +360,7 @@ public class SponsorDDWritePlatformServiceImpl implements SponsorDDWritePlatform null, "STOP_PAYMENT", leaflet.getFaceValue(), - LocalDateTime.now() + DateUtils.getLocalDateTimeOfTenant() ); this.transactionRepository.save(ddTransaction); @@ -373,7 +374,7 @@ public class SponsorDDWritePlatformServiceImpl implements SponsorDDWritePlatform "127.0.0.1", null, remarks != null ? remarks : "Stop payment instruction processed.", - LocalDateTime.now() + DateUtils.getLocalDateTimeOfTenant() ); this.auditLogRepository.save(auditLog); @@ -386,7 +387,7 @@ public class SponsorDDWritePlatformServiceImpl implements SponsorDDWritePlatform @Transactional public CommandProcessingResult sendAdvice(final Long sponsorBankId) { final AppUser currentUser = this.context.authenticatedUser(); - final LocalDateTime now = LocalDateTime.now(); + final LocalDateTime now = DateUtils.getLocalDateTimeOfTenant(); // Update m_sponsor_dd_leaflet for the sponsor bank where status is ISSUED and advice_status is NOT_SENT final String sql = "UPDATE m_sponsor_dd_leaflet leaf " diff --git a/fineract-provider/src/main/java/org/apache/fineract/useradministration/agreement/api/UserAgreementApiResource.java b/fineract-provider/src/main/java/org/apache/fineract/useradministration/agreement/api/UserAgreementApiResource.java index 832861838..4ffae883e 100644 --- a/fineract-provider/src/main/java/org/apache/fineract/useradministration/agreement/api/UserAgreementApiResource.java +++ b/fineract-provider/src/main/java/org/apache/fineract/useradministration/agreement/api/UserAgreementApiResource.java @@ -18,6 +18,8 @@ */ package org.apache.fineract.useradministration.agreement.api; +import com.google.common.base.Splitter; +import com.google.common.collect.Iterables; import com.google.gson.JsonObject; import io.swagger.v3.oas.annotations.Operation; import io.swagger.v3.oas.annotations.Parameter; @@ -155,7 +157,7 @@ public class UserAgreementApiResource { } final String fwd = req.getHeader("X-Forwarded-For"); if (fwd != null && !fwd.isBlank()) { - return fwd.split(",")[0].trim(); + return Iterables.get(Splitter.on(',').split(fwd), 0).trim(); } return req.getRemoteAddr(); } diff --git a/fineract-provider/src/main/java/org/apache/fineract/useradministration/dsc/data/BankUserDscData.java b/fineract-provider/src/main/java/org/apache/fineract/useradministration/dsc/data/BankUserDscData.java index 1b5d8b6b6..2a40065ee 100644 --- a/fineract-provider/src/main/java/org/apache/fineract/useradministration/dsc/data/BankUserDscData.java +++ b/fineract-provider/src/main/java/org/apache/fineract/useradministration/dsc/data/BankUserDscData.java @@ -19,6 +19,7 @@ package org.apache.fineract.useradministration.dsc.data; import java.time.LocalDate; +import org.apache.fineract.infrastructure.core.service.DateUtils; import java.time.OffsetDateTime; import lombok.Builder; import lombok.Getter; @@ -83,7 +84,7 @@ public class BankUserDscData { return null; } if (stored == CertStatus.ACTIVE && d.getDscExpiryDate() != null - && d.getDscExpiryDate().isBefore(LocalDate.now())) { + && d.getDscExpiryDate().isBefore(DateUtils.getLocalDateOfTenant())) { return CertStatus.EXPIRED.name(); } return stored.name(); diff --git a/fineract-provider/src/main/resources/application.properties b/fineract-provider/src/main/resources/application.properties index f78e18d81..02f4b9b34 100644 --- a/fineract-provider/src/main/resources/application.properties +++ b/fineract-provider/src/main/resources/application.properties @@ -46,7 +46,7 @@ fineract.security.oauth2.client.registrations.frontend-client.require-authorizat fineract.tenant.host=${FINERACT_DEFAULT_TENANTDB_HOSTNAME:localhost} fineract.tenant.port=${FINERACT_DEFAULT_TENANTDB_PORT:5432} fineract.tenant.username=${FINERACT_DEFAULT_TENANTDB_UID:postgres} -fineract.tenant.password=${FINERACT_DEFAULT_TENANTDB_PWD:313863} +fineract.tenant.password=${FINERACT_DEFAULT_TENANTDB_PWD:Keshav@898966} fineract.tenant.parameters=${FINERACT_DEFAULT_TENANTDB_CONN_PARAMS:} fineract.tenant.timezone=${FINERACT_DEFAULT_TENANTDB_TIMEZONE:Asia/Kolkata} fineract.tenant.identifier=${FINERACT_DEFAULT_TENANTDB_IDENTIFIER:default} @@ -407,7 +407,7 @@ server.tomcat.mbeanregistry.enabled=${FINERACT_SERVER_TOMCAT_MBEANREGISTRY_ENABL spring.datasource.hikari.driverClassName=${FINERACT_HIKARI_DRIVER_SOURCE_CLASS_NAME:org.postgresql.Driver} spring.datasource.hikari.jdbcUrl=${FINERACT_HIKARI_JDBC_URL:jdbc:postgresql://localhost:5432/fineract_tenants} spring.datasource.hikari.username=${FINERACT_HIKARI_USERNAME:postgres} -spring.datasource.hikari.password=${FINERACT_HIKARI_PASSWORD:313863} +spring.datasource.hikari.password=${FINERACT_HIKARI_PASSWORD:Keshav@898966} spring.datasource.hikari.minimumIdle=${FINERACT_HIKARI_MINIMUM_IDLE:3} spring.datasource.hikari.maximumPoolSize=${FINERACT_HIKARI_MAXIMUM_POOL_SIZE:10} spring.datasource.hikari.idleTimeout=${FINERACT_HIKARI_IDLE_TIMEOUT:60000} diff --git a/fineract-provider/src/main/resources/db/changelog/tenant/changelog-tenant.xml b/fineract-provider/src/main/resources/db/changelog/tenant/changelog-tenant.xml index 3204abe52..1c3cbca3d 100644 --- a/fineract-provider/src/main/resources/db/changelog/tenant/changelog-tenant.xml +++ b/fineract-provider/src/main/resources/db/changelog/tenant/changelog-tenant.xml @@ -469,4 +469,5 @@ + diff --git a/fineract-provider/src/main/resources/db/changelog/tenant/parts/0421_add_master_salutation_value.xml b/fineract-provider/src/main/resources/db/changelog/tenant/parts/0421_add_master_salutation_value.xml new file mode 100644 index 000000000..77423341a --- /dev/null +++ b/fineract-provider/src/main/resources/db/changelog/tenant/parts/0421_add_master_salutation_value.xml @@ -0,0 +1,43 @@ + + + + + + + + + SELECT COUNT(*) FROM m_code_value + WHERE code_id = (SELECT id FROM m_code WHERE code_name = 'Salutation') + AND code_value = 'Master' + + + + INSERT INTO m_code_value (code_id, code_value, order_position, is_active, is_mandatory) + SELECT id, 'Master', (SELECT COALESCE(MAX(order_position), 0) + 1 FROM m_code_value WHERE code_id = (SELECT id FROM m_code WHERE code_name = 'Salutation')), true, false + FROM m_code + WHERE code_name = 'Salutation'; + + + + diff --git a/fineract-savings/src/main/java/org/apache/fineract/portfolio/savings/data/FixedDepositAccountData.java b/fineract-savings/src/main/java/org/apache/fineract/portfolio/savings/data/FixedDepositAccountData.java index fd3888acb..8bea46e3a 100644 --- a/fineract-savings/src/main/java/org/apache/fineract/portfolio/savings/data/FixedDepositAccountData.java +++ b/fineract-savings/src/main/java/org/apache/fineract/portfolio/savings/data/FixedDepositAccountData.java @@ -446,6 +446,7 @@ public final class FixedDepositAccountData extends DepositAccountData { final Collection transactions, final Collection 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()); } diff --git a/fineract-savings/src/main/java/org/apache/fineract/portfolio/savings/data/SavingsProductDataValidator.java b/fineract-savings/src/main/java/org/apache/fineract/portfolio/savings/data/SavingsProductDataValidator.java index 88dfdfaa8..c3502162f 100644 --- a/fineract-savings/src/main/java/org/apache/fineract/portfolio/savings/data/SavingsProductDataValidator.java +++ b/fineract-savings/src/main/java/org/apache/fineract/portfolio/savings/data/SavingsProductDataValidator.java @@ -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; diff --git a/fineract-savings/src/main/java/org/apache/fineract/portfolio/savings/domain/ProductPendingEdit.java b/fineract-savings/src/main/java/org/apache/fineract/portfolio/savings/domain/ProductPendingEdit.java index 744f18cad..62a593c9d 100644 --- a/fineract-savings/src/main/java/org/apache/fineract/portfolio/savings/domain/ProductPendingEdit.java +++ b/fineract-savings/src/main/java/org/apache/fineract/portfolio/savings/domain/ProductPendingEdit.java @@ -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 { 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 { 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; } diff --git a/fineract-savings/src/main/java/org/apache/fineract/portfolio/savings/domain/RdInterestRateEffective.java b/fineract-savings/src/main/java/org/apache/fineract/portfolio/savings/domain/RdInterestRateEffective.java index 90c50ab02..6daf3c4c0 100644 --- a/fineract-savings/src/main/java/org/apache/fineract/portfolio/savings/domain/RdInterestRateEffective.java +++ b/fineract-savings/src/main/java/org/apache/fineract/portfolio/savings/domain/RdInterestRateEffective.java @@ -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; } } diff --git a/fineract-savings/src/main/java/org/apache/fineract/portfolio/savings/domain/RdInterestRateSlabHistory.java b/fineract-savings/src/main/java/org/apache/fineract/portfolio/savings/domain/RdInterestRateSlabHistory.java index 4bc6caeeb..9ba97e0f6 100644 --- a/fineract-savings/src/main/java/org/apache/fineract/portfolio/savings/domain/RdInterestRateSlabHistory.java +++ b/fineract-savings/src/main/java/org/apache/fineract/portfolio/savings/domain/RdInterestRateSlabHistory.java @@ -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; } } diff --git a/fineract-savings/src/main/java/org/apache/fineract/portfolio/savings/domain/SavingsAccountFacilityConfig.java b/fineract-savings/src/main/java/org/apache/fineract/portfolio/savings/domain/SavingsAccountFacilityConfig.java index bdf815d1d..dc3b0bfbd 100644 --- a/fineract-savings/src/main/java/org/apache/fineract/portfolio/savings/domain/SavingsAccountFacilityConfig.java +++ b/fineract-savings/src/main/java/org/apache/fineract/portfolio/savings/domain/SavingsAccountFacilityConfig.java @@ -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 { 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 { 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; } diff --git a/fineract-savings/src/main/java/org/apache/fineract/portfolio/savings/domain/SavingsProduct.java b/fineract-savings/src/main/java/org/apache/fineract/portfolio/savings/domain/SavingsProduct.java index 8bd5eb247..1f21f0a30 100644 --- a/fineract-savings/src/main/java/org/apache/fineract/portfolio/savings/domain/SavingsProduct.java +++ b/fineract-savings/src/main/java/org/apache/fineract/portfolio/savings/domain/SavingsProduct.java @@ -377,6 +377,7 @@ public class SavingsProduct extends AbstractPersistableCustom { 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, diff --git a/fineract-savings/src/main/java/org/apache/fineract/portfolio/savings/domain/SavingsProductDepositLimitKyc.java b/fineract-savings/src/main/java/org/apache/fineract/portfolio/savings/domain/SavingsProductDepositLimitKyc.java index 330774515..6c7483102 100644 --- a/fineract-savings/src/main/java/org/apache/fineract/portfolio/savings/domain/SavingsProductDepositLimitKyc.java +++ b/fineract-savings/src/main/java/org/apache/fineract/portfolio/savings/domain/SavingsProductDepositLimitKyc.java @@ -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 private LocalDateTime createdDate; protected SavingsProductFacilityLimit() { - this.createdDate = LocalDateTime.now(); } public SavingsProductFacilityLimit(SavingsProduct savingsProduct, String limitType, @@ -62,6 +62,7 @@ public class SavingsProductFacilityLimit extends AbstractPersistableCustom this.generalLimit = generalLimit; this.minorAccountLimit = minorAccountLimit; this.smallSavingLimit = smallSavingLimit; + this.createdDate = DateUtils.getLocalDateTimeOfTenant(); } public static SavingsProductFacilityLimit create(SavingsProduct savingsProduct, String limitType, diff --git a/fineract-savings/src/main/java/org/apache/fineract/portfolio/savings/service/FacilityChargeAutoApplyService.java b/fineract-savings/src/main/java/org/apache/fineract/portfolio/savings/service/FacilityChargeAutoApplyService.java index 36013d462..efb371213 100644 --- a/fineract-savings/src/main/java/org/apache/fineract/portfolio/savings/service/FacilityChargeAutoApplyService.java +++ b/fineract-savings/src/main/java/org/apache/fineract/portfolio/savings/service/FacilityChargeAutoApplyService.java @@ -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 charges) { - final LocalDate activationDate = account.getActivationDate(); - final List 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 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; } diff --git a/fineract-savings/src/main/java/org/apache/fineract/portfolio/savings/service/FacilityChargeSeederService.java b/fineract-savings/src/main/java/org/apache/fineract/portfolio/savings/service/FacilityChargeSeederService.java index f7fbbdb66..92c8c30e6 100644 --- a/fineract-savings/src/main/java/org/apache/fineract/portfolio/savings/service/FacilityChargeSeederService.java +++ b/fineract-savings/src/main/java/org/apache/fineract/portfolio/savings/service/FacilityChargeSeederService.java @@ -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; /** diff --git a/package-lock.json b/package-lock.json new file mode 100644 index 000000000..c757327a7 --- /dev/null +++ b/package-lock.json @@ -0,0 +1,6 @@ +{ + "name": "cbsnexora-backend", + "lockfileVersion": 3, + "requires": true, + "packages": {} +}