minor change on client
Fineract Build & Cucumber tests (without E2E tests) / verify (progressive-loan, build-progressive-loan) (push) Canceled after 0s
Fineract Cargo & Unit- & Integration tests - MariaDB / test (test-core-2) (push) Canceled after 0s
Fineract Cargo & Unit- & Integration tests - MariaDB / test (test-core-3) (push) Canceled after 0s
Fineract Cargo & Unit- & Integration tests - MariaDB / test (test-core-4) (push) Canceled after 0s
Fineract Docker Builds / build (false, docker-compose-postgresql.yml, postgresql) (push) Canceled after 0s
Fineract Build & Cucumber tests (without E2E tests) / verify (main, build-core) (push) Canceled after 0s
Fineract Build & Cucumber tests (without E2E tests) / verify (main, cucumber) (push) Canceled after 0s
Fineract Docker Builds / build (true, docker-compose.yml, mariadb) (push) Canceled after 0s
Fineract Documentation build / build (push) Canceled after 0s
Fineract E2E Tests / E2E Tests (Shard 1 of 10) (push) Canceled after 0s
Fineract E2E Tests / E2E Tests (Shard 10 of 10) (push) Canceled after 0s
Fineract E2E Tests / E2E Tests (Shard 2 of 10) (push) Canceled after 0s
Fineract E2E Tests / E2E Tests (Shard 3 of 10) (push) Canceled after 0s
Fineract E2E Tests / E2E Tests (Shard 4 of 10) (push) Canceled after 0s
Fineract E2E Tests / E2E Tests (Shard 5 of 10) (push) Canceled after 0s
Fineract E2E Tests / E2E Tests (Shard 6 of 10) (push) Canceled after 0s
Fineract E2E Tests / E2E Tests (Shard 7 of 10) (push) Canceled after 0s
Fineract E2E Tests / E2E Tests (Shard 8 of 10) (push) Canceled after 0s
Fineract E2E Tests / E2E Tests (Shard 9 of 10) (push) Canceled after 0s
Fineract Cargo & Unit- & Integration tests - MariaDB / test (test-core-1) (push) Canceled after 0s
Fineract Cargo & Unit- & Integration tests - MariaDB / test (test-core-5) (push) Canceled after 0s
Fineract Cargo & Unit- & Integration tests - MySQL / test (test-core-1) (push) Canceled after 0s
Fineract Cargo & Unit- & Integration tests - MySQL / test (test-core-2) (push) Canceled after 0s
Fineract Cargo & Unit- & Integration tests - MySQL / test (test-core-3) (push) Canceled after 0s
Fineract Cargo & Unit- & Integration tests - MySQL / test (test-core-4) (push) Canceled after 0s
Fineract Cargo & Unit- & Integration tests - MySQL / test (test-core-5) (push) Canceled after 0s
Fineract Cargo & Unit- & Integration tests - PostgreSQL / test (test-core-1) (push) Canceled after 0s
Fineract Cargo & Unit- & Integration tests - PostgreSQL / test (test-core-2) (push) Canceled after 0s
Fineract Cargo & Unit- & Integration tests - PostgreSQL / test (test-core-3) (push) Canceled after 0s
Fineract Cargo & Unit- & Integration tests - PostgreSQL / test (test-core-4) (push) Canceled after 0s
Fineract Cargo & Unit- & Integration tests - PostgreSQL / test (test-core-5) (push) Canceled after 0s
Fineract Liquibase Only mode - PostgreSQL / test (push) Canceled after 0s
Fineract Messaging Smoke Tests / Smoke Test with ActiveMQ (push) Canceled after 0s
Fineract Messaging Smoke Tests / Smoke Test with Kafka (push) Canceled after 0s
Fineract Build & Cucumber tests (without E2E tests) / verify (progressive-loan, build-progressive-loan) (push) Canceled after 0s
Fineract Cargo & Unit- & Integration tests - MariaDB / test (test-core-2) (push) Canceled after 0s
Fineract Cargo & Unit- & Integration tests - MariaDB / test (test-core-3) (push) Canceled after 0s
Fineract Cargo & Unit- & Integration tests - MariaDB / test (test-core-4) (push) Canceled after 0s
Fineract Docker Builds / build (false, docker-compose-postgresql.yml, postgresql) (push) Canceled after 0s
Fineract Build & Cucumber tests (without E2E tests) / verify (main, build-core) (push) Canceled after 0s
Fineract Build & Cucumber tests (without E2E tests) / verify (main, cucumber) (push) Canceled after 0s
Fineract Docker Builds / build (true, docker-compose.yml, mariadb) (push) Canceled after 0s
Fineract Documentation build / build (push) Canceled after 0s
Fineract E2E Tests / E2E Tests (Shard 1 of 10) (push) Canceled after 0s
Fineract E2E Tests / E2E Tests (Shard 10 of 10) (push) Canceled after 0s
Fineract E2E Tests / E2E Tests (Shard 2 of 10) (push) Canceled after 0s
Fineract E2E Tests / E2E Tests (Shard 3 of 10) (push) Canceled after 0s
Fineract E2E Tests / E2E Tests (Shard 4 of 10) (push) Canceled after 0s
Fineract E2E Tests / E2E Tests (Shard 5 of 10) (push) Canceled after 0s
Fineract E2E Tests / E2E Tests (Shard 6 of 10) (push) Canceled after 0s
Fineract E2E Tests / E2E Tests (Shard 7 of 10) (push) Canceled after 0s
Fineract E2E Tests / E2E Tests (Shard 8 of 10) (push) Canceled after 0s
Fineract E2E Tests / E2E Tests (Shard 9 of 10) (push) Canceled after 0s
Fineract Cargo & Unit- & Integration tests - MariaDB / test (test-core-1) (push) Canceled after 0s
Fineract Cargo & Unit- & Integration tests - MariaDB / test (test-core-5) (push) Canceled after 0s
Fineract Cargo & Unit- & Integration tests - MySQL / test (test-core-1) (push) Canceled after 0s
Fineract Cargo & Unit- & Integration tests - MySQL / test (test-core-2) (push) Canceled after 0s
Fineract Cargo & Unit- & Integration tests - MySQL / test (test-core-3) (push) Canceled after 0s
Fineract Cargo & Unit- & Integration tests - MySQL / test (test-core-4) (push) Canceled after 0s
Fineract Cargo & Unit- & Integration tests - MySQL / test (test-core-5) (push) Canceled after 0s
Fineract Cargo & Unit- & Integration tests - PostgreSQL / test (test-core-1) (push) Canceled after 0s
Fineract Cargo & Unit- & Integration tests - PostgreSQL / test (test-core-2) (push) Canceled after 0s
Fineract Cargo & Unit- & Integration tests - PostgreSQL / test (test-core-3) (push) Canceled after 0s
Fineract Cargo & Unit- & Integration tests - PostgreSQL / test (test-core-4) (push) Canceled after 0s
Fineract Cargo & Unit- & Integration tests - PostgreSQL / test (test-core-5) (push) Canceled after 0s
Fineract Liquibase Only mode - PostgreSQL / test (push) Canceled after 0s
Fineract Messaging Smoke Tests / Smoke Test with ActiveMQ (push) Canceled after 0s
Fineract Messaging Smoke Tests / Smoke Test with Kafka (push) Canceled after 0s
This commit is contained in:
-1
@@ -18,7 +18,6 @@
|
|||||||
*/
|
*/
|
||||||
package org.apache.fineract.accounting.journalentry;
|
package org.apache.fineract.accounting.journalentry;
|
||||||
|
|
||||||
import java.time.OffsetDateTime;
|
|
||||||
import org.apache.fineract.accounting.glaccount.domain.GLAccountType;
|
import org.apache.fineract.accounting.glaccount.domain.GLAccountType;
|
||||||
import org.apache.fineract.accounting.journalentry.data.JournalEntryData;
|
import org.apache.fineract.accounting.journalentry.data.JournalEntryData;
|
||||||
import org.apache.fineract.accounting.journalentry.domain.JournalEntry;
|
import org.apache.fineract.accounting.journalentry.domain.JournalEntry;
|
||||||
|
|||||||
+14
-14
@@ -277,14 +277,14 @@ public class ProductToGLAccountMappingHelper {
|
|||||||
}
|
}
|
||||||
|
|
||||||
final JsonArray chargeToIncomeAccountMappingArray = this.fromApiJsonHelper.extractJsonArrayNamed(arrayFragmentName, element);
|
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
|
* Variable stores a map representation of charges (key) and their associated income Id's (value) extracted from
|
||||||
* the passed in Jsoncommand
|
* the passed in Jsoncommand
|
||||||
**/
|
*/
|
||||||
final Map<Long, Long> inputChargeToIncomeAccountMap = new HashMap<>();
|
final Map<Long, Long> inputChargeToIncomeAccountMap = new HashMap<>();
|
||||||
/***
|
/*
|
||||||
* Variable stores all charges which have already been mapped to Income Accounts in the system
|
* Variable stores all charges which have already been mapped to Income Accounts in the system
|
||||||
**/
|
*/
|
||||||
final Set<Long> existingCharges = new HashSet<>();
|
final Set<Long> existingCharges = new HashSet<>();
|
||||||
if (chargeToIncomeAccountMappingArray != null) {
|
if (chargeToIncomeAccountMappingArray != null) {
|
||||||
if (changes != null) {
|
if (changes != null) {
|
||||||
@@ -301,13 +301,13 @@ public class ProductToGLAccountMappingHelper {
|
|||||||
// If input map is empty, delete all existing mappings
|
// If input map is empty, delete all existing mappings
|
||||||
if (inputChargeToIncomeAccountMap.size() == 0) {
|
if (inputChargeToIncomeAccountMap.size() == 0) {
|
||||||
this.accountMappingRepository.deleteAll(existingChargeToIncomeAccountMappings);
|
this.accountMappingRepository.deleteAll(existingChargeToIncomeAccountMappings);
|
||||||
} /**
|
} /*
|
||||||
* Else, <br/>
|
* Else, <br/>
|
||||||
* update existing mappings OR <br/>
|
* update existing mappings OR <br/>
|
||||||
* delete old mappings (which are already present, but not passed in as a part of Jsoncommand)<br/>
|
* delete old mappings (which are already present, but not passed in as a part of Jsoncommand)<br/>
|
||||||
* Create new mappings for charges that are passed in as a part of the Jsoncommand but not already present
|
* Create new mappings for charges that are passed in as a part of the Jsoncommand but not already present
|
||||||
*
|
*
|
||||||
**/
|
*/
|
||||||
else {
|
else {
|
||||||
for (final ProductToGLAccountMapping chargeToIncomeAccountMapping : existingChargeToIncomeAccountMappings) {
|
for (final ProductToGLAccountMapping chargeToIncomeAccountMapping : existingChargeToIncomeAccountMappings) {
|
||||||
final Long currentCharge = chargeToIncomeAccountMapping.getCharge().getId();
|
final Long currentCharge = chargeToIncomeAccountMapping.getCharge().getId();
|
||||||
@@ -356,14 +356,14 @@ public class ProductToGLAccountMappingHelper {
|
|||||||
.findAllPaymentTypeToFundSourceMappings(productId, portfolioProductType.getValue());
|
.findAllPaymentTypeToFundSourceMappings(productId, portfolioProductType.getValue());
|
||||||
final JsonArray paymentChannelMappingArray = this.fromApiJsonHelper
|
final JsonArray paymentChannelMappingArray = this.fromApiJsonHelper
|
||||||
.extractJsonArrayNamed(LoanProductAccountingParams.PAYMENT_CHANNEL_FUND_SOURCE_MAPPING.getValue(), element);
|
.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
|
* Variable stores a map representation of Payment channels (key) and their fund sources (value) extracted from
|
||||||
* the passed in Jsoncommand
|
* the passed in Jsoncommand
|
||||||
**/
|
*/
|
||||||
final Map<Long, Long> inputPaymentChannelFundSourceMap = new HashMap<>();
|
final Map<Long, Long> inputPaymentChannelFundSourceMap = new HashMap<>();
|
||||||
/***
|
/*
|
||||||
* Variable stores all payment types which have already been mapped to Fund Sources in the system
|
* Variable stores all payment types which have already been mapped to Fund Sources in the system
|
||||||
**/
|
*/
|
||||||
final Set<Long> existingPaymentTypes = new HashSet<>();
|
final Set<Long> existingPaymentTypes = new HashSet<>();
|
||||||
if (paymentChannelMappingArray != null) {
|
if (paymentChannelMappingArray != null) {
|
||||||
if (changes != null) {
|
if (changes != null) {
|
||||||
@@ -381,14 +381,14 @@ public class ProductToGLAccountMappingHelper {
|
|||||||
// If input map is empty, delete all existing mappings
|
// If input map is empty, delete all existing mappings
|
||||||
if (inputPaymentChannelFundSourceMap.isEmpty()) {
|
if (inputPaymentChannelFundSourceMap.isEmpty()) {
|
||||||
this.accountMappingRepository.deleteAll(existingPaymentChannelToFundSourceMappings);
|
this.accountMappingRepository.deleteAll(existingPaymentChannelToFundSourceMappings);
|
||||||
} /**
|
} /*
|
||||||
* Else, <br/>
|
* Else, <br/>
|
||||||
* update existing mappings OR <br/>
|
* update existing mappings OR <br/>
|
||||||
* delete old mappings (which re already present, but not passed in as a part of Jsoncommand)<br/>
|
* delete old mappings (which re already present, but not passed in as a part of Jsoncommand)<br/>
|
||||||
* Create new mappings for payment types that are passed in as a part of the Jsoncommand but not already
|
* Create new mappings for payment types that are passed in as a part of the Jsoncommand but not already
|
||||||
* present
|
* present
|
||||||
*
|
*
|
||||||
**/
|
*/
|
||||||
else {
|
else {
|
||||||
for (final ProductToGLAccountMapping existingPaymentChannelToFundSourceMapping : existingPaymentChannelToFundSourceMappings) {
|
for (final ProductToGLAccountMapping existingPaymentChannelToFundSourceMapping : existingPaymentChannelToFundSourceMappings) {
|
||||||
final Long currentPaymentChannelId = existingPaymentChannelToFundSourceMapping.getPaymentType().getId();
|
final Long currentPaymentChannelId = existingPaymentChannelToFundSourceMapping.getPaymentType().getId();
|
||||||
@@ -584,9 +584,9 @@ public class ProductToGLAccountMappingHelper {
|
|||||||
// based on input condition
|
// based on input condition
|
||||||
|
|
||||||
GLAccount glAccount;
|
GLAccount glAccount;
|
||||||
/**
|
/*
|
||||||
* Both CASH and Accrual placeholders have the same value for income from Interest and penalties
|
* Both CASH and Accrual placeholders have the same value for income from Interest and penalties
|
||||||
**/
|
*/
|
||||||
CashAccountsForLoan placeHolderAccountType;
|
CashAccountsForLoan placeHolderAccountType;
|
||||||
if (isPenalty) {
|
if (isPenalty) {
|
||||||
glAccount = getAccountByIdAndType(LoanProductAccountingParams.INCOME_ACCOUNT_ID.getValue(), GLAccountType.INCOME,
|
glAccount = getAccountByIdAndType(LoanProductAccountingParams.INCOME_ACCOUNT_ID.getValue(), GLAccountType.INCOME,
|
||||||
|
|||||||
+2
-2
@@ -181,12 +181,12 @@ public class TellerApiResource {
|
|||||||
@Consumes({ MediaType.APPLICATION_JSON })
|
@Consumes({ MediaType.APPLICATION_JSON })
|
||||||
@Produces(MediaType.APPLICATION_JSON)
|
@Produces(MediaType.APPLICATION_JSON)
|
||||||
@Operation(summary = "Create Cashiers", description = """
|
@Operation(summary = "Create Cashiers", description = """
|
||||||
Mandatory Fields:\s
|
Mandatory Fields:
|
||||||
Cashier/staff, Fromm Date, To Date, Full Day or From time and To time
|
Cashier/staff, Fromm Date, To Date, Full Day or From time and To time
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
Optional Fields:\s
|
Optional Fields:
|
||||||
Description/Notes""")
|
Description/Notes""")
|
||||||
@RequestBody(required = true, content = @Content(schema = @Schema(implementation = TellerApiResourceSwagger.PostTellersTellerIdCashiersRequest.class)))
|
@RequestBody(required = true, content = @Content(schema = @Schema(implementation = TellerApiResourceSwagger.PostTellersTellerIdCashiersRequest.class)))
|
||||||
@ApiResponse(responseCode = "200", description = "OK", content = @Content(schema = @Schema(implementation = TellerApiResourceSwagger.PostTellersTellerIdCashiersResponse.class)))
|
@ApiResponse(responseCode = "200", description = "OK", content = @Content(schema = @Schema(implementation = TellerApiResourceSwagger.PostTellersTellerIdCashiersResponse.class)))
|
||||||
|
|||||||
+2
-1
@@ -23,6 +23,7 @@ import jakarta.persistence.Entity;
|
|||||||
import jakarta.persistence.Table;
|
import jakarta.persistence.Table;
|
||||||
import java.time.OffsetDateTime;
|
import java.time.OffsetDateTime;
|
||||||
import org.apache.fineract.infrastructure.core.domain.AbstractAuditableWithUTCDateTimeCustom;
|
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.
|
* Simulator-side audit log for CFCFRMS (I4C/MHA) events.
|
||||||
@@ -69,7 +70,7 @@ public class CfcfrmsSimulatorLog extends AbstractAuditableWithUTCDateTimeCustom<
|
|||||||
this.eventType = eventType;
|
this.eventType = eventType;
|
||||||
this.payload = payload;
|
this.payload = payload;
|
||||||
this.responsePayload = responsePayload;
|
this.responsePayload = responsePayload;
|
||||||
this.eventTimestamp = OffsetDateTime.now();
|
this.eventTimestamp = DateUtils.getOffsetDateTimeOfTenant();
|
||||||
}
|
}
|
||||||
|
|
||||||
public CfcfrmsSimulatorLog(final String cfcfrmsRef, final String ticketId, final String bankIfsc,
|
public CfcfrmsSimulatorLog(final String cfcfrmsRef, final String ticketId, final String bankIfsc,
|
||||||
|
|||||||
+2
-1
@@ -23,6 +23,7 @@ import jakarta.persistence.Entity;
|
|||||||
import jakarta.persistence.Table;
|
import jakarta.persistence.Table;
|
||||||
import java.time.OffsetDateTime;
|
import java.time.OffsetDateTime;
|
||||||
import org.apache.fineract.infrastructure.core.domain.AbstractAuditableWithUTCDateTimeCustom;
|
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.
|
* Audit trail for every status change on a CFCFRMS complaint ticket.
|
||||||
@@ -54,7 +55,7 @@ public class ComplaintAuditLog extends AbstractAuditableWithUTCDateTimeCustom<Lo
|
|||||||
this.event = event;
|
this.event = event;
|
||||||
this.description = description;
|
this.description = description;
|
||||||
this.actor = actor;
|
this.actor = actor;
|
||||||
this.eventTimestamp = OffsetDateTime.now();
|
this.eventTimestamp = DateUtils.getOffsetDateTimeOfTenant();
|
||||||
}
|
}
|
||||||
|
|
||||||
public ComplaintAuditLog(final String ticketId, final String event, final String description,
|
public ComplaintAuditLog(final String ticketId, final String event, final String description,
|
||||||
|
|||||||
+3
-2
@@ -26,6 +26,7 @@ import jakarta.persistence.Table;
|
|||||||
import java.math.BigDecimal;
|
import java.math.BigDecimal;
|
||||||
import java.time.OffsetDateTime;
|
import java.time.OffsetDateTime;
|
||||||
import org.apache.fineract.infrastructure.core.domain.AbstractAuditableWithUTCDateTimeCustom;
|
import org.apache.fineract.infrastructure.core.domain.AbstractAuditableWithUTCDateTimeCustom;
|
||||||
|
import org.apache.fineract.infrastructure.core.service.DateUtils;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* CFCFRMS Complaint Ticket — represents a cyber fraud complaint pushed by MHA/I4C to the bank.
|
* CFCFRMS Complaint Ticket — represents a cyber fraud complaint pushed by MHA/I4C to the bank.
|
||||||
@@ -121,7 +122,7 @@ public class ComplaintTicket extends AbstractAuditableWithUTCDateTimeCustom<Long
|
|||||||
ticket.status = ComplaintStatus.RECEIVED;
|
ticket.status = ComplaintStatus.RECEIVED;
|
||||||
ticket.assignedOfficer = assignedOfficer;
|
ticket.assignedOfficer = assignedOfficer;
|
||||||
ticket.statePoliceRef = statePoliceRef;
|
ticket.statePoliceRef = statePoliceRef;
|
||||||
ticket.receivedAt = OffsetDateTime.now();
|
ticket.receivedAt = DateUtils.getOffsetDateTimeOfTenant();
|
||||||
return ticket;
|
return ticket;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -132,7 +133,7 @@ public class ComplaintTicket extends AbstractAuditableWithUTCDateTimeCustom<Long
|
|||||||
this.status = newStatus;
|
this.status = newStatus;
|
||||||
this.actionTaken = actionNote;
|
this.actionTaken = actionNote;
|
||||||
if (newStatus == ComplaintStatus.RESOLVED || newStatus == ComplaintStatus.REJECTED) {
|
if (newStatus == ComplaintStatus.RESOLVED || newStatus == ComplaintStatus.REJECTED) {
|
||||||
this.resolvedAt = OffsetDateTime.now();
|
this.resolvedAt = DateUtils.getOffsetDateTimeOfTenant();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
+2
-1
@@ -29,6 +29,7 @@ import lombok.Getter;
|
|||||||
import org.apache.commons.lang3.StringUtils;
|
import org.apache.commons.lang3.StringUtils;
|
||||||
import org.apache.fineract.infrastructure.core.api.JsonCommand;
|
import org.apache.fineract.infrastructure.core.api.JsonCommand;
|
||||||
import org.apache.fineract.infrastructure.core.domain.AbstractAuditableWithUTCDateTimeCustom;
|
import org.apache.fineract.infrastructure.core.domain.AbstractAuditableWithUTCDateTimeCustom;
|
||||||
|
import org.apache.fineract.infrastructure.core.service.DateUtils;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Form 60 declaration as per Rule 114B of Income Tax Rules, 1962.
|
* Form 60 declaration as per Rule 114B of Income Tax Rules, 1962.
|
||||||
@@ -87,7 +88,7 @@ public class ClientForm60 extends AbstractAuditableWithUTCDateTimeCustom<Long> {
|
|||||||
form.estimatedTotalIncome = command.bigDecimalValueOfParameterNamed("estimatedTotalIncome");
|
form.estimatedTotalIncome = command.bigDecimalValueOfParameterNamed("estimatedTotalIncome");
|
||||||
form.reasonForNoPan = StringUtils.defaultIfEmpty(command.stringValueOfParameterNamed("reasonForNoPan"), null);
|
form.reasonForNoPan = StringUtils.defaultIfEmpty(command.stringValueOfParameterNamed("reasonForNoPan"), null);
|
||||||
form.declaration = command.booleanPrimitiveValueOfParameterNamed("declaration");
|
form.declaration = command.booleanPrimitiveValueOfParameterNamed("declaration");
|
||||||
form.submittedOn = LocalDate.now();
|
form.submittedOn = DateUtils.getLocalDateOfTenant();
|
||||||
return form;
|
return form;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
+11
-10
@@ -32,6 +32,7 @@ import java.util.Map;
|
|||||||
import org.apache.commons.lang3.StringUtils;
|
import org.apache.commons.lang3.StringUtils;
|
||||||
import org.apache.fineract.infrastructure.core.api.JsonCommand;
|
import org.apache.fineract.infrastructure.core.api.JsonCommand;
|
||||||
import org.apache.fineract.infrastructure.core.domain.AbstractAuditableWithUTCDateTimeCustom;
|
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
|
* 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<Long> {
|
|||||||
this.gstinVerified = false;
|
this.gstinVerified = false;
|
||||||
this.cinVerified = false;
|
this.cinVerified = false;
|
||||||
this.dinVerified = false;
|
this.dinVerified = false;
|
||||||
this.initiatedOn = LocalDate.now();
|
this.initiatedOn = DateUtils.getLocalDateOfTenant();
|
||||||
}
|
}
|
||||||
|
|
||||||
public static ClientKyc initiateKyc(final Client client, final JsonCommand command) {
|
public static ClientKyc initiateKyc(final Client client, final JsonCommand command) {
|
||||||
@@ -456,13 +457,13 @@ public class ClientKyc extends AbstractAuditableWithUTCDateTimeCustom<Long> {
|
|||||||
public void markCkycUploaded(final String ckycNumber, final String batchId) {
|
public void markCkycUploaded(final String ckycNumber, final String batchId) {
|
||||||
this.ckycNumber = StringUtils.defaultIfEmpty(ckycNumber, null);
|
this.ckycNumber = StringUtils.defaultIfEmpty(ckycNumber, null);
|
||||||
this.ckycBatchId = StringUtils.defaultIfEmpty(batchId, 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. */
|
/** Called after successful 3rd-party verification of all required documents. */
|
||||||
public void markVerified(final String ckycNumber) {
|
public void markVerified(final String ckycNumber) {
|
||||||
this.kycStatus = ClientKycStatus.VERIFIED.getValue();
|
this.kycStatus = ClientKycStatus.VERIFIED.getValue();
|
||||||
this.verifiedOn = LocalDate.now();
|
this.verifiedOn = DateUtils.getLocalDateOfTenant();
|
||||||
this.ckycNumber = StringUtils.defaultIfEmpty(ckycNumber, null);
|
this.ckycNumber = StringUtils.defaultIfEmpty(ckycNumber, null);
|
||||||
|
|
||||||
final KycRiskCategory risk = KycRiskCategory.fromInt(this.riskCategory);
|
final KycRiskCategory risk = KycRiskCategory.fromInt(this.riskCategory);
|
||||||
@@ -474,14 +475,14 @@ public class ClientKyc extends AbstractAuditableWithUTCDateTimeCustom<Long> {
|
|||||||
/** Called when verification fails. */
|
/** Called when verification fails. */
|
||||||
public void markRejected(final String remarks) {
|
public void markRejected(final String remarks) {
|
||||||
this.kycStatus = ClientKycStatus.REJECTED.getValue();
|
this.kycStatus = ClientKycStatus.REJECTED.getValue();
|
||||||
this.rejectedOn = LocalDate.now();
|
this.rejectedOn = DateUtils.getLocalDateOfTenant();
|
||||||
this.remarks = StringUtils.defaultIfEmpty(remarks, this.remarks);
|
this.remarks = StringUtils.defaultIfEmpty(remarks, this.remarks);
|
||||||
}
|
}
|
||||||
|
|
||||||
public void markPanVerified(final String fullName, final String firstName, final String lastName,
|
public void markPanVerified(final String fullName, final String firstName, final String lastName,
|
||||||
final String aadhaarSeedingStatus, final String category, final String status) {
|
final String aadhaarSeedingStatus, final String category, final String status) {
|
||||||
this.panVerified = true;
|
this.panVerified = true;
|
||||||
this.panVerifiedOn = LocalDate.now();
|
this.panVerifiedOn = DateUtils.getLocalDateOfTenant();
|
||||||
this.panFullName = StringUtils.defaultIfEmpty(fullName, null);
|
this.panFullName = StringUtils.defaultIfEmpty(fullName, null);
|
||||||
this.panFirstName = StringUtils.defaultIfEmpty(firstName, null);
|
this.panFirstName = StringUtils.defaultIfEmpty(firstName, null);
|
||||||
this.panLastName = StringUtils.defaultIfEmpty(lastName, null);
|
this.panLastName = StringUtils.defaultIfEmpty(lastName, null);
|
||||||
@@ -507,28 +508,28 @@ public class ClientKyc extends AbstractAuditableWithUTCDateTimeCustom<Long> {
|
|||||||
|
|
||||||
public void markAadhaarVerified() {
|
public void markAadhaarVerified() {
|
||||||
this.aadhaarVerified = true;
|
this.aadhaarVerified = true;
|
||||||
this.aadhaarVerifiedOn = LocalDate.now();
|
this.aadhaarVerifiedOn = DateUtils.getLocalDateOfTenant();
|
||||||
}
|
}
|
||||||
|
|
||||||
public void markGstinVerified() {
|
public void markGstinVerified() {
|
||||||
this.gstinVerified = true;
|
this.gstinVerified = true;
|
||||||
this.gstinVerifiedOn = LocalDate.now();
|
this.gstinVerifiedOn = DateUtils.getLocalDateOfTenant();
|
||||||
}
|
}
|
||||||
|
|
||||||
public void markCinVerified() {
|
public void markCinVerified() {
|
||||||
this.cinVerified = true;
|
this.cinVerified = true;
|
||||||
this.cinVerifiedOn = LocalDate.now();
|
this.cinVerifiedOn = DateUtils.getLocalDateOfTenant();
|
||||||
}
|
}
|
||||||
|
|
||||||
public void markDinVerified() {
|
public void markDinVerified() {
|
||||||
this.dinVerified = true;
|
this.dinVerified = true;
|
||||||
this.dinVerifiedOn = LocalDate.now();
|
this.dinVerifiedOn = DateUtils.getLocalDateOfTenant();
|
||||||
}
|
}
|
||||||
|
|
||||||
public void markDinVerified(final String dinNumber, final String mcaResponseJson) {
|
public void markDinVerified(final String dinNumber, final String mcaResponseJson) {
|
||||||
this.dinNumber = dinNumber;
|
this.dinNumber = dinNumber;
|
||||||
this.dinVerified = true;
|
this.dinVerified = true;
|
||||||
this.dinVerifiedOn = LocalDate.now();
|
this.dinVerifiedOn = DateUtils.getLocalDateOfTenant();
|
||||||
this.isDirector = true;
|
this.isDirector = true;
|
||||||
this.dinMcaResponse = mcaResponseJson;
|
this.dinMcaResponse = mcaResponseJson;
|
||||||
}
|
}
|
||||||
|
|||||||
+2
-1
@@ -24,6 +24,7 @@ import jakarta.persistence.Table;
|
|||||||
import java.time.OffsetDateTime;
|
import java.time.OffsetDateTime;
|
||||||
import lombok.Getter;
|
import lombok.Getter;
|
||||||
import org.apache.fineract.infrastructure.core.domain.AbstractAuditableWithUTCDateTimeCustom;
|
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.
|
* Activity log for each DIP / MNRL mobile number lookup request.
|
||||||
@@ -78,6 +79,6 @@ public class MobileLookupLog extends AbstractAuditableWithUTCDateTimeCustom<Long
|
|||||||
this.rawResponse = rawResponse;
|
this.rawResponse = rawResponse;
|
||||||
this.lookupSource = lookupSource;
|
this.lookupSource = lookupSource;
|
||||||
this.clientId = clientId;
|
this.clientId = clientId;
|
||||||
this.lookedUpOn = OffsetDateTime.now();
|
this.lookedUpOn = DateUtils.getOffsetDateTimeOfTenant();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
+2
-1
@@ -23,6 +23,7 @@ import jakarta.persistence.Entity;
|
|||||||
import jakarta.persistence.Table;
|
import jakarta.persistence.Table;
|
||||||
import java.time.OffsetDateTime;
|
import java.time.OffsetDateTime;
|
||||||
import org.apache.fineract.infrastructure.core.domain.AbstractAuditableWithUTCDateTimeCustom;
|
import org.apache.fineract.infrastructure.core.domain.AbstractAuditableWithUTCDateTimeCustom;
|
||||||
|
import org.apache.fineract.infrastructure.core.service.DateUtils;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Activity log for each sanctions screening request.
|
* Activity log for each sanctions screening request.
|
||||||
@@ -73,7 +74,7 @@ public class SanctionsScreeningLog extends AbstractAuditableWithUTCDateTimeCusto
|
|||||||
this.screeningSource = screeningSource;
|
this.screeningSource = screeningSource;
|
||||||
this.clientId = clientId;
|
this.clientId = clientId;
|
||||||
this.ipAddress = ipAddress;
|
this.ipAddress = ipAddress;
|
||||||
this.screenedOn = OffsetDateTime.now();
|
this.screenedOn = DateUtils.getOffsetDateTimeOfTenant();
|
||||||
}
|
}
|
||||||
|
|
||||||
// ── Accessors ─────────────────────────────────────────────────────────────
|
// ── Accessors ─────────────────────────────────────────────────────────────
|
||||||
|
|||||||
+7
-6
@@ -18,6 +18,7 @@
|
|||||||
*/
|
*/
|
||||||
package org.apache.fineract.portfolio.search.data;
|
package org.apache.fineract.portfolio.search.data;
|
||||||
|
|
||||||
|
import java.util.Locale;
|
||||||
import org.apache.fineract.portfolio.search.SearchConstants.SearchSupportedResources;
|
import org.apache.fineract.portfolio.search.SearchConstants.SearchSupportedResources;
|
||||||
|
|
||||||
public class SearchConditions {
|
public class SearchConditions {
|
||||||
@@ -37,17 +38,17 @@ public class SearchConditions {
|
|||||||
this.searchResource = searchResource;
|
this.searchResource = searchResource;
|
||||||
this.exactMatch = exactMatch;
|
this.exactMatch = exactMatch;
|
||||||
this.clientSearch = null == searchResource
|
this.clientSearch = null == searchResource
|
||||||
|| searchResource.toLowerCase().contains(SearchSupportedResources.CLIENTS.name().toLowerCase());
|
|| searchResource.toLowerCase(Locale.ROOT).contains(SearchSupportedResources.CLIENTS.name().toLowerCase(Locale.ROOT));
|
||||||
this.groupSearch = null == searchResource
|
this.groupSearch = null == searchResource
|
||||||
|| searchResource.toLowerCase().contains(SearchSupportedResources.GROUPS.name().toLowerCase());
|
|| searchResource.toLowerCase(Locale.ROOT).contains(SearchSupportedResources.GROUPS.name().toLowerCase(Locale.ROOT));
|
||||||
this.loanSeach = null == searchResource
|
this.loanSeach = null == searchResource
|
||||||
|| searchResource.toLowerCase().contains(SearchSupportedResources.LOANS.name().toLowerCase());
|
|| searchResource.toLowerCase(Locale.ROOT).contains(SearchSupportedResources.LOANS.name().toLowerCase(Locale.ROOT));
|
||||||
this.savingSeach = null == searchResource
|
this.savingSeach = null == searchResource
|
||||||
|| searchResource.toLowerCase().contains(SearchSupportedResources.SAVINGS.name().toLowerCase());
|
|| searchResource.toLowerCase(Locale.ROOT).contains(SearchSupportedResources.SAVINGS.name().toLowerCase(Locale.ROOT));
|
||||||
this.shareSeach = null == searchResource
|
this.shareSeach = null == searchResource
|
||||||
|| searchResource.toLowerCase().contains(SearchSupportedResources.SHARES.name().toLowerCase());
|
|| searchResource.toLowerCase(Locale.ROOT).contains(SearchSupportedResources.SHARES.name().toLowerCase(Locale.ROOT));
|
||||||
this.clientIdentifierSearch = null == searchResource
|
this.clientIdentifierSearch = null == searchResource
|
||||||
|| searchResource.toLowerCase().contains(SearchSupportedResources.CLIENTIDENTIFIERS.name().toLowerCase());
|
|| searchResource.toLowerCase(Locale.ROOT).contains(SearchSupportedResources.CLIENTIDENTIFIERS.name().toLowerCase(Locale.ROOT));
|
||||||
}
|
}
|
||||||
|
|
||||||
public SearchConditions(final String searchQueryParam, final String searchResource, final Boolean clientSearch,
|
public SearchConditions(final String searchQueryParam, final String searchResource, final Boolean clientSearch,
|
||||||
|
|||||||
+1
-1
@@ -321,6 +321,6 @@ public class SearchUtil {
|
|||||||
|
|
||||||
public String camelToSnake(final String camelStr) {
|
public String camelToSnake(final String camelStr) {
|
||||||
return camelStr == null ? null
|
return camelStr == null ? null
|
||||||
: camelStr.replaceAll("([A-Z]+)([A-Z][a-z])", "$1_$2").replaceAll("([a-z])([A-Z])", "$1_$2").toLowerCase();
|
: camelStr.replaceAll("([A-Z]+)([A-Z][a-z])", "$1_$2").replaceAll("([a-z])([A-Z])", "$1_$2").toLowerCase(Locale.ROOT);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
+1
-1
@@ -39,7 +39,7 @@ public interface BankUserDscRepository extends JpaRepository<BankUserDsc, Long>
|
|||||||
|
|
||||||
/**
|
/**
|
||||||
* Login gate: returns true if the user has at least one usable DSC mapping that's also not
|
* 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
|
* 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
|
* 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
|
* accept (the verify side filters too, but the gate is what kicks the user into the DSC flow
|
||||||
|
|||||||
+4
-3
@@ -29,6 +29,7 @@ import java.time.LocalDateTime;
|
|||||||
import lombok.Getter;
|
import lombok.Getter;
|
||||||
import lombok.Setter;
|
import lombok.Setter;
|
||||||
import org.apache.fineract.infrastructure.core.domain.AbstractPersistableCustom;
|
import org.apache.fineract.infrastructure.core.domain.AbstractPersistableCustom;
|
||||||
|
import org.apache.fineract.infrastructure.core.service.DateUtils;
|
||||||
import org.apache.fineract.useradministration.domain.AppUser;
|
import org.apache.fineract.useradministration.domain.AppUser;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -452,7 +453,7 @@ public class CurrentAccountPendingEdit extends AbstractPersistableCustom<Long> {
|
|||||||
public CurrentAccountPendingEdit(final CurrentAccount currentAccount, final AppUser maker) {
|
public CurrentAccountPendingEdit(final CurrentAccount currentAccount, final AppUser maker) {
|
||||||
this.currentAccount = currentAccount;
|
this.currentAccount = currentAccount;
|
||||||
this.maker = maker;
|
this.maker = maker;
|
||||||
this.createdOn = LocalDateTime.now();
|
this.createdOn = DateUtils.getLocalDateTimeOfTenant();
|
||||||
this.status = STATUS_PENDING;
|
this.status = STATUS_PENDING;
|
||||||
this.pendingLockKey = lockKeyFor(currentAccount.getId());
|
this.pendingLockKey = lockKeyFor(currentAccount.getId());
|
||||||
}
|
}
|
||||||
@@ -582,14 +583,14 @@ public class CurrentAccountPendingEdit extends AbstractPersistableCustom<Long> {
|
|||||||
public void markApproved(final AppUser checker) {
|
public void markApproved(final AppUser checker) {
|
||||||
this.status = STATUS_APPROVED;
|
this.status = STATUS_APPROVED;
|
||||||
this.checker = checker;
|
this.checker = checker;
|
||||||
this.checkedOn = LocalDateTime.now();
|
this.checkedOn = DateUtils.getLocalDateTimeOfTenant();
|
||||||
this.pendingLockKey = null;
|
this.pendingLockKey = null;
|
||||||
}
|
}
|
||||||
|
|
||||||
public void markRejected(final AppUser checker, final String reason) {
|
public void markRejected(final AppUser checker, final String reason) {
|
||||||
this.status = STATUS_REJECTED;
|
this.status = STATUS_REJECTED;
|
||||||
this.checker = checker;
|
this.checker = checker;
|
||||||
this.checkedOn = LocalDateTime.now();
|
this.checkedOn = DateUtils.getLocalDateTimeOfTenant();
|
||||||
this.rejectReason = reason;
|
this.rejectReason = reason;
|
||||||
this.pendingLockKey = null;
|
this.pendingLockKey = null;
|
||||||
}
|
}
|
||||||
|
|||||||
+3
-1
@@ -51,7 +51,9 @@ public class CurrentAccountNumberGenerator {
|
|||||||
if (val > maxVal) {
|
if (val > maxVal) {
|
||||||
maxVal = val;
|
maxVal = val;
|
||||||
}
|
}
|
||||||
} catch (NumberFormatException ignored) {}
|
} catch (NumberFormatException ignored) {
|
||||||
|
// non-numeric suffix - skip when computing the max existing sequence
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
-2
@@ -54,7 +54,6 @@ import com.google.gson.JsonElement;
|
|||||||
import com.google.gson.reflect.TypeToken;
|
import com.google.gson.reflect.TypeToken;
|
||||||
import java.lang.reflect.Type;
|
import java.lang.reflect.Type;
|
||||||
import java.math.BigDecimal;
|
import java.math.BigDecimal;
|
||||||
import java.time.MonthDay;
|
|
||||||
import java.util.ArrayList;
|
import java.util.ArrayList;
|
||||||
import java.util.Arrays;
|
import java.util.Arrays;
|
||||||
import java.util.HashSet;
|
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.SavingsApiConstants;
|
||||||
import org.apache.fineract.portfolio.savings.SavingsCompoundingInterestPeriodType;
|
import org.apache.fineract.portfolio.savings.SavingsCompoundingInterestPeriodType;
|
||||||
import org.apache.fineract.portfolio.savings.SavingsInterestCalculationDaysInYearType;
|
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.SavingsPostingInterestPeriodType;
|
||||||
import org.apache.fineract.portfolio.currentproduct.domain.CurrentProduct;
|
import org.apache.fineract.portfolio.currentproduct.domain.CurrentProduct;
|
||||||
import org.apache.fineract.portfolio.savings.data.SavingsProductAccountingDataValidator;
|
import org.apache.fineract.portfolio.savings.data.SavingsProductAccountingDataValidator;
|
||||||
|
|||||||
-7
@@ -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.customerSegmentParamName;
|
||||||
import static org.apache.fineract.portfolio.savings.SavingsApiConstants.productCodeParamName;
|
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.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.introducerRequiredParamName;
|
||||||
import static org.apache.fineract.portfolio.savings.SavingsApiConstants.shareLinkingEnabledParamName;
|
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.nominationFacilityParamName;
|
||||||
import static org.apache.fineract.portfolio.savings.SavingsApiConstants.dormancyAlertParamName;
|
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.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.enableLockinPeriodParamName;
|
||||||
import static org.apache.fineract.portfolio.savings.SavingsApiConstants.balanceSwapOptionParamName;
|
import static org.apache.fineract.portfolio.savings.SavingsApiConstants.balanceSwapOptionParamName;
|
||||||
import static org.apache.fineract.portfolio.savings.SavingsApiConstants.msmeParamName;
|
import static org.apache.fineract.portfolio.savings.SavingsApiConstants.msmeParamName;
|
||||||
|
|||||||
+2
-1
@@ -26,6 +26,7 @@ import jakarta.persistence.OneToOne;
|
|||||||
import jakarta.persistence.Table;
|
import jakarta.persistence.Table;
|
||||||
import java.time.LocalDateTime;
|
import java.time.LocalDateTime;
|
||||||
import org.apache.fineract.infrastructure.core.domain.AbstractPersistableCustom;
|
import org.apache.fineract.infrastructure.core.domain.AbstractPersistableCustom;
|
||||||
|
import org.apache.fineract.infrastructure.core.service.DateUtils;
|
||||||
|
|
||||||
@Entity
|
@Entity
|
||||||
@Table(name = "m_current_product_deposit_limit_kyc")
|
@Table(name = "m_current_product_deposit_limit_kyc")
|
||||||
@@ -57,12 +58,12 @@ public class CurrentProductDepositLimitKyc extends AbstractPersistableCustom<Lon
|
|||||||
private LocalDateTime createdDate;
|
private LocalDateTime createdDate;
|
||||||
|
|
||||||
protected CurrentProductDepositLimitKyc() {
|
protected CurrentProductDepositLimitKyc() {
|
||||||
this.createdDate = LocalDateTime.now();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public CurrentProductDepositLimitKyc(CurrentProduct currentProduct) {
|
public CurrentProductDepositLimitKyc(CurrentProduct currentProduct) {
|
||||||
this();
|
this();
|
||||||
this.currentProduct = currentProduct;
|
this.currentProduct = currentProduct;
|
||||||
|
this.createdDate = DateUtils.getLocalDateTimeOfTenant();
|
||||||
}
|
}
|
||||||
|
|
||||||
public CurrentProduct getCurrentProduct() { return currentProduct; }
|
public CurrentProduct getCurrentProduct() { return currentProduct; }
|
||||||
|
|||||||
+2
-1
@@ -26,6 +26,7 @@ import jakarta.persistence.OneToOne;
|
|||||||
import jakarta.persistence.Table;
|
import jakarta.persistence.Table;
|
||||||
import java.time.LocalDateTime;
|
import java.time.LocalDateTime;
|
||||||
import org.apache.fineract.infrastructure.core.domain.AbstractPersistableCustom;
|
import org.apache.fineract.infrastructure.core.domain.AbstractPersistableCustom;
|
||||||
|
import org.apache.fineract.infrastructure.core.service.DateUtils;
|
||||||
|
|
||||||
@Entity
|
@Entity
|
||||||
@Table(name = "m_current_product_facility_config")
|
@Table(name = "m_current_product_facility_config")
|
||||||
@@ -87,12 +88,12 @@ public class CurrentProductFacilityConfig extends AbstractPersistableCustom<Long
|
|||||||
private LocalDateTime createdDate;
|
private LocalDateTime createdDate;
|
||||||
|
|
||||||
protected CurrentProductFacilityConfig() {
|
protected CurrentProductFacilityConfig() {
|
||||||
this.createdDate = LocalDateTime.now();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public CurrentProductFacilityConfig(CurrentProduct currentProduct) {
|
public CurrentProductFacilityConfig(CurrentProduct currentProduct) {
|
||||||
this();
|
this();
|
||||||
this.currentProduct = currentProduct;
|
this.currentProduct = currentProduct;
|
||||||
|
this.createdDate = DateUtils.getLocalDateTimeOfTenant();
|
||||||
}
|
}
|
||||||
|
|
||||||
public CurrentProduct getCurrentProduct() { return currentProduct; }
|
public CurrentProduct getCurrentProduct() { return currentProduct; }
|
||||||
|
|||||||
+2
-1
@@ -26,6 +26,7 @@ import jakarta.persistence.ManyToOne;
|
|||||||
import jakarta.persistence.Table;
|
import jakarta.persistence.Table;
|
||||||
import java.time.LocalDateTime;
|
import java.time.LocalDateTime;
|
||||||
import org.apache.fineract.infrastructure.core.domain.AbstractPersistableCustom;
|
import org.apache.fineract.infrastructure.core.domain.AbstractPersistableCustom;
|
||||||
|
import org.apache.fineract.infrastructure.core.service.DateUtils;
|
||||||
|
|
||||||
@Entity
|
@Entity
|
||||||
@Table(name = "m_current_product_facility_limits")
|
@Table(name = "m_current_product_facility_limits")
|
||||||
@@ -51,7 +52,6 @@ public class CurrentProductFacilityLimit extends AbstractPersistableCustom<Long>
|
|||||||
private LocalDateTime createdDate;
|
private LocalDateTime createdDate;
|
||||||
|
|
||||||
protected CurrentProductFacilityLimit() {
|
protected CurrentProductFacilityLimit() {
|
||||||
this.createdDate = LocalDateTime.now();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private CurrentProductFacilityLimit(CurrentProduct currentProduct, String limitType,
|
private CurrentProductFacilityLimit(CurrentProduct currentProduct, String limitType,
|
||||||
@@ -62,6 +62,7 @@ public class CurrentProductFacilityLimit extends AbstractPersistableCustom<Long>
|
|||||||
this.generalLimit = generalLimit;
|
this.generalLimit = generalLimit;
|
||||||
this.minorAccountLimit = minorAccountLimit;
|
this.minorAccountLimit = minorAccountLimit;
|
||||||
this.smallSavingLimit = smallSavingLimit;
|
this.smallSavingLimit = smallSavingLimit;
|
||||||
|
this.createdDate = DateUtils.getLocalDateTimeOfTenant();
|
||||||
}
|
}
|
||||||
|
|
||||||
public static CurrentProductFacilityLimit create(CurrentProduct currentProduct, String limitType,
|
public static CurrentProductFacilityLimit create(CurrentProduct currentProduct, String limitType,
|
||||||
|
|||||||
-2
@@ -19,13 +19,11 @@
|
|||||||
package org.apache.fineract.portfolio.currentproduct.service;
|
package org.apache.fineract.portfolio.currentproduct.service;
|
||||||
|
|
||||||
import com.google.gson.Gson;
|
import com.google.gson.Gson;
|
||||||
import com.google.gson.JsonObject;
|
|
||||||
import com.google.gson.reflect.TypeToken;
|
import com.google.gson.reflect.TypeToken;
|
||||||
import java.lang.reflect.Type;
|
import java.lang.reflect.Type;
|
||||||
import java.math.BigDecimal;
|
import java.math.BigDecimal;
|
||||||
import java.sql.ResultSet;
|
import java.sql.ResultSet;
|
||||||
import java.sql.SQLException;
|
import java.sql.SQLException;
|
||||||
import java.util.ArrayList;
|
|
||||||
import java.util.Collection;
|
import java.util.Collection;
|
||||||
import java.util.HashMap;
|
import java.util.HashMap;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
|
|||||||
+1
-1
@@ -75,7 +75,7 @@ import org.springframework.stereotype.Component;
|
|||||||
@Path("/v1/journalentries")
|
@Path("/v1/journalentries")
|
||||||
@Component
|
@Component
|
||||||
@Tag(name = "Journal Entries", description = """
|
@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""")
|
A journal entry directly changes the account balances on the general ledger""")
|
||||||
@RequiredArgsConstructor
|
@RequiredArgsConstructor
|
||||||
|
|||||||
+2
-1
@@ -21,6 +21,7 @@ package org.apache.fineract.infrastructure.email.service;
|
|||||||
import java.time.Year;
|
import java.time.Year;
|
||||||
import org.springframework.beans.factory.annotation.Value;
|
import org.springframework.beans.factory.annotation.Value;
|
||||||
import org.springframework.stereotype.Service;
|
import org.springframework.stereotype.Service;
|
||||||
|
import org.apache.fineract.infrastructure.core.service.DateUtils;
|
||||||
|
|
||||||
@Service
|
@Service
|
||||||
public class EmailTemplateServiceImpl implements EmailTemplateService {
|
public class EmailTemplateServiceImpl implements EmailTemplateService {
|
||||||
@@ -129,7 +130,7 @@ public class EmailTemplateServiceImpl implements EmailTemplateService {
|
|||||||
+ escape(supportEmail) + "</a>"
|
+ escape(supportEmail) + "</a>"
|
||||||
+ " </p>"
|
+ " </p>"
|
||||||
+ " <p style=\"margin:0;font-size:12px;color:#94a3b8;\">"
|
+ " <p style=\"margin:0;font-size:12px;color:#94a3b8;\">"
|
||||||
+ " © " + Year.now().getValue() + " " + escape(brandName) + ". All rights reserved."
|
+ " © " + Year.now(DateUtils.getDateTimeZoneOfTenant()).getValue() + " " + escape(brandName) + ". All rights reserved."
|
||||||
+ " </p>"
|
+ " </p>"
|
||||||
+ " </td></tr>"
|
+ " </td></tr>"
|
||||||
+ " </table>"
|
+ " </table>"
|
||||||
|
|||||||
+1
@@ -109,6 +109,7 @@ public class ImpsCryptoUtil {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/** Decrypt inbound payload using the CBS private key. */
|
/** Decrypt inbound payload using the CBS private key. */
|
||||||
|
@SuppressWarnings("StringSplitter")
|
||||||
public String decryptJson(String encryptedPayload) {
|
public String decryptJson(String encryptedPayload) {
|
||||||
if (cbsPrivateKey == null) {
|
if (cbsPrivateKey == null) {
|
||||||
throw new IllegalStateException("CBS private key not loaded — check fineract.imps.cbs.private-key-path");
|
throw new IllegalStateException("CBS private key not loaded — check fineract.imps.cbs.private-key-path");
|
||||||
|
|||||||
+2
-1
@@ -34,6 +34,7 @@ import org.slf4j.Logger;
|
|||||||
import org.slf4j.LoggerFactory;
|
import org.slf4j.LoggerFactory;
|
||||||
import org.springframework.stereotype.Service;
|
import org.springframework.stereotype.Service;
|
||||||
import org.springframework.transaction.annotation.Transactional;
|
import org.springframework.transaction.annotation.Transactional;
|
||||||
|
import org.apache.fineract.infrastructure.core.service.DateUtils;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* STUB implementation — returns hard-coded SUCCESS for every request and
|
* STUB implementation — returns hard-coded SUCCESS for every request and
|
||||||
@@ -108,7 +109,7 @@ public class ImpsCbsServiceImpl implements ImpsCbsService {
|
|||||||
resp.setRefId(request.getRefId());
|
resp.setRefId(request.getRefId());
|
||||||
resp.setUtr(request.getUtr());
|
resp.setUtr(request.getUtr());
|
||||||
resp.setAmount(request.getAmount());
|
resp.setAmount(request.getAmount());
|
||||||
resp.setTimeStamp(OffsetDateTime.now().format(ISO_OFFSET));
|
resp.setTimeStamp(OffsetDateTime.now(DateUtils.getDateTimeZoneOfTenant()).format(ISO_OFFSET));
|
||||||
resp.setStatus("SUCCESS");
|
resp.setStatus("SUCCESS");
|
||||||
resp.setResponseCode("00");
|
resp.setResponseCode("00");
|
||||||
AccountData payeeAcc = Optional.ofNullable(request.getPayee()).map(PartyData::getAccount).orElse(null);
|
AccountData payeeAcc = Optional.ofNullable(request.getPayee()).map(PartyData::getAccount).orElse(null);
|
||||||
|
|||||||
+2
-2
@@ -28,7 +28,6 @@ import java.util.ArrayList;
|
|||||||
import java.util.Collection;
|
import java.util.Collection;
|
||||||
import java.util.LinkedHashMap;
|
import java.util.LinkedHashMap;
|
||||||
import java.util.Map;
|
import java.util.Map;
|
||||||
import java.util.concurrent.TimeUnit;
|
|
||||||
import lombok.extern.slf4j.Slf4j;
|
import lombok.extern.slf4j.Slf4j;
|
||||||
import okhttp3.Credentials;
|
import okhttp3.Credentials;
|
||||||
import okhttp3.MediaType;
|
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.OpenProjectStatusSummaryData;
|
||||||
import org.apache.fineract.infrastructure.openproject.data.OpenProjectWorkPackageData;
|
import org.apache.fineract.infrastructure.openproject.data.OpenProjectWorkPackageData;
|
||||||
import org.springframework.stereotype.Service;
|
import org.springframework.stereotype.Service;
|
||||||
|
import org.apache.fineract.infrastructure.core.service.DateUtils;
|
||||||
|
|
||||||
@Service
|
@Service
|
||||||
@Slf4j
|
@Slf4j
|
||||||
@@ -164,7 +164,7 @@ public class OpenProjectService {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Set required custom field: "Last Follow-up Date" (customField8)
|
// 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()) {
|
if (typeName != null && !typeName.isBlank()) {
|
||||||
JsonObject links = new JsonObject();
|
JsonObject links = new JsonObject();
|
||||||
|
|||||||
+2
-1
@@ -47,6 +47,7 @@ import org.springframework.transaction.annotation.Transactional;
|
|||||||
import org.w3c.dom.Document;
|
import org.w3c.dom.Document;
|
||||||
import org.w3c.dom.Element;
|
import org.w3c.dom.Element;
|
||||||
import org.w3c.dom.NodeList;
|
import org.w3c.dom.NodeList;
|
||||||
|
import org.apache.fineract.infrastructure.core.service.DateUtils;
|
||||||
|
|
||||||
@Service
|
@Service
|
||||||
@RequiredArgsConstructor
|
@RequiredArgsConstructor
|
||||||
@@ -127,7 +128,7 @@ public class RbiFeedFetchService {
|
|||||||
NodeList items = doc.getElementsByTagName("item");
|
NodeList items = doc.getElementsByTagName("item");
|
||||||
log.debug("RBI FeedFetchService - Parsed {} items from RSS for category: {}", items.getLength(), category);
|
log.debug("RBI FeedFetchService - Parsed {} items from RSS for category: {}", items.getLength(), category);
|
||||||
List<RbiFeedItem> newItems = new ArrayList<>();
|
List<RbiFeedItem> newItems = new ArrayList<>();
|
||||||
LocalDateTime now = LocalDateTime.now();
|
LocalDateTime now = LocalDateTime.now(DateUtils.getDateTimeZoneOfTenant());
|
||||||
|
|
||||||
for (int i = 0; i < items.getLength(); i++) {
|
for (int i = 0; i < items.getLength(); i++) {
|
||||||
Element item = (Element) items.item(i);
|
Element item = (Element) items.item(i);
|
||||||
|
|||||||
+3
-1
@@ -18,6 +18,8 @@
|
|||||||
*/
|
*/
|
||||||
package org.apache.fineract.infrastructure.security.otp.api;
|
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.JsonObject;
|
||||||
import com.google.gson.JsonParser;
|
import com.google.gson.JsonParser;
|
||||||
import io.swagger.v3.oas.annotations.Operation;
|
import io.swagger.v3.oas.annotations.Operation;
|
||||||
@@ -107,7 +109,7 @@ public class EmailLoginOtpApiResource {
|
|||||||
}
|
}
|
||||||
final String fwd = req.getHeader("X-Forwarded-For");
|
final String fwd = req.getHeader("X-Forwarded-For");
|
||||||
if (fwd != null && !fwd.isBlank()) {
|
if (fwd != null && !fwd.isBlank()) {
|
||||||
return fwd.split(",")[0].trim();
|
return Iterables.get(Splitter.on(',').split(fwd), 0).trim();
|
||||||
}
|
}
|
||||||
return req.getRemoteAddr();
|
return req.getRemoteAddr();
|
||||||
}
|
}
|
||||||
|
|||||||
+3
-1
@@ -18,6 +18,8 @@
|
|||||||
*/
|
*/
|
||||||
package org.apache.fineract.infrastructure.security.otp.api;
|
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.JsonObject;
|
||||||
import com.google.gson.JsonParser;
|
import com.google.gson.JsonParser;
|
||||||
import io.swagger.v3.oas.annotations.Operation;
|
import io.swagger.v3.oas.annotations.Operation;
|
||||||
@@ -107,7 +109,7 @@ public class LoginOtpApiResource {
|
|||||||
}
|
}
|
||||||
final String fwd = req.getHeader("X-Forwarded-For");
|
final String fwd = req.getHeader("X-Forwarded-For");
|
||||||
if (fwd != null && !fwd.isBlank()) {
|
if (fwd != null && !fwd.isBlank()) {
|
||||||
return fwd.split(",")[0].trim();
|
return Iterables.get(Splitter.on(',').split(fwd), 0).trim();
|
||||||
}
|
}
|
||||||
return req.getRemoteAddr();
|
return req.getRemoteAddr();
|
||||||
}
|
}
|
||||||
|
|||||||
+2
-1
@@ -45,6 +45,7 @@ import org.springframework.beans.factory.annotation.Autowired;
|
|||||||
import org.springframework.beans.factory.annotation.Value;
|
import org.springframework.beans.factory.annotation.Value;
|
||||||
import org.springframework.stereotype.Service;
|
import org.springframework.stereotype.Service;
|
||||||
import org.springframework.transaction.annotation.Transactional;
|
import org.springframework.transaction.annotation.Transactional;
|
||||||
|
import org.apache.fineract.infrastructure.core.service.DateUtils;
|
||||||
|
|
||||||
@Service
|
@Service
|
||||||
public class EmailLoginOtpServiceImpl implements EmailLoginOtpService {
|
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.
|
// Render the branded template — same look and feel for OTP, welcome, password-reset, alerts.
|
||||||
final String html = emailTemplateService.renderOtp(recipientName, otp, validityMinutes);
|
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);
|
final boolean sent = emailSenderService.sendHtml(email, subject, html);
|
||||||
if (sent) {
|
if (sent) {
|
||||||
|
|||||||
-2
@@ -20,7 +20,6 @@ package org.apache.fineract.organisation.teller.service;
|
|||||||
|
|
||||||
import jakarta.persistence.PersistenceException;
|
import jakarta.persistence.PersistenceException;
|
||||||
import java.util.Map;
|
import java.util.Map;
|
||||||
import java.util.Set;
|
|
||||||
import lombok.AllArgsConstructor;
|
import lombok.AllArgsConstructor;
|
||||||
import lombok.extern.slf4j.Slf4j;
|
import lombok.extern.slf4j.Slf4j;
|
||||||
import org.apache.commons.lang3.exception.ExceptionUtils;
|
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.CashierTxnType;
|
||||||
import org.apache.fineract.organisation.teller.domain.Teller;
|
import org.apache.fineract.organisation.teller.domain.Teller;
|
||||||
import org.apache.fineract.organisation.teller.domain.TellerRepositoryWrapper;
|
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.CashierNotFoundException;
|
||||||
import org.apache.fineract.organisation.teller.exception.TellerAlreadyExistsException;
|
import org.apache.fineract.organisation.teller.exception.TellerAlreadyExistsException;
|
||||||
import org.apache.fineract.organisation.teller.serialization.TellerCommandFromApiJsonDeserializer;
|
import org.apache.fineract.organisation.teller.serialization.TellerCommandFromApiJsonDeserializer;
|
||||||
|
|||||||
+12
-5
@@ -33,6 +33,7 @@ import org.apache.fineract.useradministration.domain.AppUser;
|
|||||||
import org.springframework.jdbc.core.JdbcTemplate;
|
import org.springframework.jdbc.core.JdbcTemplate;
|
||||||
import org.springframework.stereotype.Component;
|
import org.springframework.stereotype.Component;
|
||||||
import org.springframework.transaction.annotation.Transactional;
|
import org.springframework.transaction.annotation.Transactional;
|
||||||
|
import org.apache.fineract.infrastructure.core.service.DateUtils;
|
||||||
|
|
||||||
@Path("/v1/cashexchange")
|
@Path("/v1/cashexchange")
|
||||||
@Component
|
@Component
|
||||||
@@ -94,7 +95,7 @@ public class CashExchangeApiResource {
|
|||||||
header.setNote(note);
|
header.setNote(note);
|
||||||
header.setCustomerIdProof(customerIdProof);
|
header.setCustomerIdProof(customerIdProof);
|
||||||
header.setIsReversed(false);
|
header.setIsReversed(false);
|
||||||
header.setCreatedAt(LocalDateTime.now());
|
header.setCreatedAt(LocalDateTime.now(DateUtils.getDateTimeZoneOfTenant()));
|
||||||
try {
|
try {
|
||||||
AppUser user = this.context.authenticatedUser();
|
AppUser user = this.context.authenticatedUser();
|
||||||
if (user != null) {
|
if (user != null) {
|
||||||
@@ -107,7 +108,9 @@ public class CashExchangeApiResource {
|
|||||||
+ "JOIN m_appuser au ON au.staff_id = ms.id WHERE au.id = ?",
|
+ "JOIN m_appuser au ON au.staff_id = ms.id WHERE au.id = ?",
|
||||||
Long.class, user.getId());
|
Long.class, user.getId());
|
||||||
header.setCashierId(cashierId);
|
header.setCashierId(cashierId);
|
||||||
} catch (Exception ignored) {}
|
} catch (Exception ignored) {
|
||||||
|
// intentionally ignored
|
||||||
|
}
|
||||||
}
|
}
|
||||||
} catch (Exception e) {
|
} catch (Exception e) {
|
||||||
// resolving the current user must never block recording the exchange
|
// resolving the current user must never block recording the exchange
|
||||||
@@ -160,14 +163,18 @@ public class CashExchangeApiResource {
|
|||||||
try {
|
try {
|
||||||
JsonObject json = JsonParser.parseString(body).getAsJsonObject();
|
JsonObject json = JsonParser.parseString(body).getAsJsonObject();
|
||||||
reason = json.has("reason") && !json.get("reason").isJsonNull() ? json.get("reason").getAsString() : null;
|
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.setIsReversed(true);
|
||||||
exchange.setReversedAt(LocalDateTime.now());
|
exchange.setReversedAt(LocalDateTime.now(DateUtils.getDateTimeZoneOfTenant()));
|
||||||
exchange.setReverseReason(reason);
|
exchange.setReverseReason(reason);
|
||||||
try {
|
try {
|
||||||
AppUser user = this.context.authenticatedUser();
|
AppUser user = this.context.authenticatedUser();
|
||||||
if (user != null) exchange.setReversedBy(user.getId());
|
if (user != null) exchange.setReversedBy(user.getId());
|
||||||
} catch (Exception ignored) {}
|
} catch (Exception ignored) {
|
||||||
|
// intentionally ignored
|
||||||
|
}
|
||||||
repository.save(exchange);
|
repository.save(exchange);
|
||||||
JsonObject result = new JsonObject();
|
JsonObject result = new JsonObject();
|
||||||
result.addProperty("resourceId", id);
|
result.addProperty("resourceId", id);
|
||||||
|
|||||||
+9
-117
@@ -59,6 +59,9 @@ import org.apache.fineract.useradministration.domain.AppUser;
|
|||||||
import org.springframework.jdbc.core.JdbcTemplate;
|
import org.springframework.jdbc.core.JdbcTemplate;
|
||||||
import org.springframework.stereotype.Component;
|
import org.springframework.stereotype.Component;
|
||||||
import org.springframework.transaction.annotation.Transactional;
|
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")
|
@Path("/v1/cashier/deposit-requests")
|
||||||
@Component
|
@Component
|
||||||
@@ -364,7 +367,7 @@ public class CashierDepositRequestApiResource {
|
|||||||
final BigDecimal amount = new BigDecimal(record.get("amount").toString());
|
final BigDecimal amount = new BigDecimal(record.get("amount").toString());
|
||||||
final Object ptId = record.get("payment_type_id");
|
final Object ptId = record.get("payment_type_id");
|
||||||
final Object txnDateObj = record.get("txn_date");
|
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 description = (String) record.get("description");
|
||||||
|
|
||||||
final String storedAccountType = (String) record.get("account_type");
|
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 BigDecimal amount = new BigDecimal(record.get("amount").toString());
|
||||||
final Object ptId = record.get("payment_type_id");
|
final Object ptId = record.get("payment_type_id");
|
||||||
final Object txnDateObj = record.get("txn_date");
|
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 description = (String) record.get("description");
|
||||||
|
|
||||||
if (savingsAccountId == null || !isCurrentAccountById(savingsAccountId)) {
|
if (savingsAccountId == null || !isCurrentAccountById(savingsAccountId)) {
|
||||||
@@ -559,7 +562,7 @@ public class CashierDepositRequestApiResource {
|
|||||||
final Long savingsAccountId, final BigDecimal amount,
|
final Long savingsAccountId, final BigDecimal amount,
|
||||||
final Object paymentTypeId, final String txnDateStr, final String note) {
|
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 String date = txnDateStr != null && !txnDateStr.isBlank() ? formatForFineract(txnDateStr) : today;
|
||||||
|
|
||||||
final JsonObject payload = new JsonObject();
|
final JsonObject payload = new JsonObject();
|
||||||
@@ -587,7 +590,7 @@ public class CashierDepositRequestApiResource {
|
|||||||
final Long currentAccountId, final BigDecimal amount,
|
final Long currentAccountId, final BigDecimal amount,
|
||||||
final Object paymentTypeId, final String txnDateStr, final String note) {
|
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 String date = txnDateStr != null && !txnDateStr.isBlank() ? formatForFineract(txnDateStr) : today;
|
||||||
|
|
||||||
final JsonObject payload = new JsonObject();
|
final JsonObject payload = new JsonObject();
|
||||||
@@ -644,7 +647,7 @@ public class CashierDepositRequestApiResource {
|
|||||||
final Object paymentTypeId, final String txnDateStr, final String note,
|
final Object paymentTypeId, final String txnDateStr, final String note,
|
||||||
final boolean isDeposit) {
|
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;
|
final String date = txnDateStr != null && !txnDateStr.isBlank() ? formatForFineract(txnDateStr) : today;
|
||||||
|
|
||||||
// Deposit (CR): cashier receives cash → credit selected GL, debit cash vault (contra)
|
// 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;
|
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<String, com.google.gson.JsonElement> 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<Long> 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
|
* Saves the denomination breakdown the cashier entered at submit time into
|
||||||
* m_savings_txn_denomination once the deposit is approved, so the cashier's
|
* 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<String, JsonElement> 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<Long> 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
|
* If a cash denomination breakdown is provided, its total must exactly equal
|
||||||
* the deposit amount — prevents the recorded vault movement from drifting
|
* 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);
|
final LocalDate ld = LocalDate.parse(isoDate, DateTimeFormatter.ISO_LOCAL_DATE);
|
||||||
return ld.format(DateTimeFormatter.ofPattern("dd MMMM yyyy"));
|
return ld.format(DateTimeFormatter.ofPattern("dd MMMM yyyy"));
|
||||||
} catch (Exception e) {
|
} catch (Exception e) {
|
||||||
return LocalDate.now().format(DateTimeFormatter.ofPattern("dd MMMM yyyy"));
|
return LocalDate.now(DateUtils.getDateTimeZoneOfTenant()).format(DateTimeFormatter.ofPattern("dd MMMM yyyy"));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
+13
-6
@@ -31,6 +31,7 @@ import org.apache.fineract.portfolio.cashintercashier.domain.CashInterCashierRep
|
|||||||
import org.apache.fineract.useradministration.domain.AppUser;
|
import org.apache.fineract.useradministration.domain.AppUser;
|
||||||
import org.springframework.stereotype.Component;
|
import org.springframework.stereotype.Component;
|
||||||
import org.springframework.transaction.annotation.Transactional;
|
import org.springframework.transaction.annotation.Transactional;
|
||||||
|
import org.apache.fineract.infrastructure.core.service.DateUtils;
|
||||||
|
|
||||||
@Path("/v1/cashintercashier")
|
@Path("/v1/cashintercashier")
|
||||||
@Component
|
@Component
|
||||||
@@ -69,7 +70,7 @@ public class CashInterCashierApiResource {
|
|||||||
}
|
}
|
||||||
|
|
||||||
final LocalDate transferDate = json.has("transferDate") && !json.get("transferDate").isJsonNull()
|
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()
|
final String fromParty = json.has("fromParty") && !json.get("fromParty").isJsonNull()
|
||||||
? json.get("fromParty").getAsString() : null;
|
? json.get("fromParty").getAsString() : null;
|
||||||
final String toParty = json.has("toParty") && !json.get("toParty").isJsonNull()
|
final String toParty = json.has("toParty") && !json.get("toParty").isJsonNull()
|
||||||
@@ -95,13 +96,15 @@ public class CashInterCashierApiResource {
|
|||||||
header.setToParty(toParty);
|
header.setToParty(toParty);
|
||||||
header.setTransferAmount(total);
|
header.setTransferAmount(total);
|
||||||
header.setNote(note);
|
header.setNote(note);
|
||||||
header.setCreatedAt(LocalDateTime.now());
|
header.setCreatedAt(LocalDateTime.now(DateUtils.getDateTimeZoneOfTenant()));
|
||||||
header.setIsReversed(false);
|
header.setIsReversed(false);
|
||||||
try {
|
try {
|
||||||
AppUser user = this.context.authenticatedUser();
|
AppUser user = this.context.authenticatedUser();
|
||||||
header.setPerformedBy(user.getId());
|
header.setPerformedBy(user.getId());
|
||||||
header.setPerformedByUsername(user.getUsername());
|
header.setPerformedByUsername(user.getUsername());
|
||||||
} catch (Exception ignored) {}
|
} catch (Exception ignored) {
|
||||||
|
// intentionally ignored
|
||||||
|
}
|
||||||
CashInterCashier saved = repository.saveAndFlush(header);
|
CashInterCashier saved = repository.saveAndFlush(header);
|
||||||
saveDetails(saved.getId(), denominations);
|
saveDetails(saved.getId(), denominations);
|
||||||
|
|
||||||
@@ -128,13 +131,17 @@ public class CashInterCashierApiResource {
|
|||||||
try {
|
try {
|
||||||
JsonObject json = JsonParser.parseString(body).getAsJsonObject();
|
JsonObject json = JsonParser.parseString(body).getAsJsonObject();
|
||||||
reason = json.has("reason") ? json.get("reason").getAsString() : null;
|
reason = json.has("reason") ? json.get("reason").getAsString() : null;
|
||||||
} catch (Exception ignored) {}
|
} catch (Exception ignored) {
|
||||||
|
// intentionally ignored
|
||||||
|
}
|
||||||
|
|
||||||
AppUser user = null;
|
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.setIsReversed(true);
|
||||||
record.setReversedAt(LocalDateTime.now());
|
record.setReversedAt(LocalDateTime.now(DateUtils.getDateTimeZoneOfTenant()));
|
||||||
record.setReverseReason(reason);
|
record.setReverseReason(reason);
|
||||||
if (user != null) record.setReversedBy(user.getId());
|
if (user != null) record.setReversedBy(user.getId());
|
||||||
repository.save(record);
|
repository.save(record);
|
||||||
|
|||||||
+9
-6
@@ -32,6 +32,7 @@ import org.apache.fineract.useradministration.domain.AppUser;
|
|||||||
import org.springframework.jdbc.core.JdbcTemplate;
|
import org.springframework.jdbc.core.JdbcTemplate;
|
||||||
import org.springframework.stereotype.Component;
|
import org.springframework.stereotype.Component;
|
||||||
import org.springframework.transaction.annotation.Transactional;
|
import org.springframework.transaction.annotation.Transactional;
|
||||||
|
import org.apache.fineract.infrastructure.core.service.DateUtils;
|
||||||
|
|
||||||
@Path("/v1/cashreconciliation")
|
@Path("/v1/cashreconciliation")
|
||||||
@Component
|
@Component
|
||||||
@@ -62,7 +63,7 @@ public class CashReconciliationApiResource {
|
|||||||
throw new PlatformDataIntegrityException("error.msg.cashreconciliation.cashier.required",
|
throw new PlatformDataIntegrityException("error.msg.cashreconciliation.cashier.required",
|
||||||
"cashierId query param is 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
|
// 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 "
|
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")
|
@Path("expected/me")
|
||||||
public String getExpectedForMe(@QueryParam("asOfDate") String asOfDate) {
|
public String getExpectedForMe(@QueryParam("asOfDate") String asOfDate) {
|
||||||
context.authenticatedUser().validateHasPermissionTo("READ_CASHRECONCILIATION");
|
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;
|
Long appUserId;
|
||||||
try {
|
try {
|
||||||
appUserId = context.authenticatedUser().getId();
|
appUserId = context.authenticatedUser().getId();
|
||||||
@@ -223,7 +224,7 @@ public class CashReconciliationApiResource {
|
|||||||
throw new PlatformDataIntegrityException("error.msg.cashreconciliation.cashier.required",
|
throw new PlatformDataIntegrityException("error.msg.cashreconciliation.cashier.required",
|
||||||
"cashierId query param is 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(
|
Integer count = jdbcTemplate.queryForObject(
|
||||||
"SELECT COUNT(*) FROM m_cash_reconciliation WHERE cashier_id = ? AND recon_date = CAST(? AS DATE)",
|
"SELECT COUNT(*) FROM m_cash_reconciliation WHERE cashier_id = ? AND recon_date = CAST(? AS DATE)",
|
||||||
Integer.class, cashierId, reconDate);
|
Integer.class, cashierId, reconDate);
|
||||||
@@ -247,7 +248,7 @@ public class CashReconciliationApiResource {
|
|||||||
"cashierId is required.");
|
"cashierId is required.");
|
||||||
}
|
}
|
||||||
final LocalDate reconDate = json.has("reconDate") && !json.get("reconDate").isJsonNull()
|
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()
|
final String cashierName = json.has("cashierName") && !json.get("cashierName").isJsonNull()
|
||||||
? json.get("cashierName").getAsString() : null;
|
? json.get("cashierName").getAsString() : null;
|
||||||
final Long tellerId = json.has("tellerId") && !json.get("tellerId").isJsonNull()
|
final Long tellerId = json.has("tellerId") && !json.get("tellerId").isJsonNull()
|
||||||
@@ -299,12 +300,14 @@ public class CashReconciliationApiResource {
|
|||||||
header.setVariance(variance);
|
header.setVariance(variance);
|
||||||
header.setStatus(status);
|
header.setStatus(status);
|
||||||
header.setNote(note);
|
header.setNote(note);
|
||||||
header.setCreatedAt(LocalDateTime.now());
|
header.setCreatedAt(LocalDateTime.now(DateUtils.getDateTimeZoneOfTenant()));
|
||||||
try {
|
try {
|
||||||
AppUser user = this.context.authenticatedUser();
|
AppUser user = this.context.authenticatedUser();
|
||||||
header.setPerformedBy(user.getId());
|
header.setPerformedBy(user.getId());
|
||||||
header.setPerformedByUsername(user.getUsername());
|
header.setPerformedByUsername(user.getUsername());
|
||||||
} catch (Exception ignored) {}
|
} catch (Exception ignored) {
|
||||||
|
// intentionally ignored
|
||||||
|
}
|
||||||
CashReconciliation saved = repository.saveAndFlush(header);
|
CashReconciliation saved = repository.saveAndFlush(header);
|
||||||
|
|
||||||
for (CashReconciliationDetail d : details) {
|
for (CashReconciliationDetail d : details) {
|
||||||
|
|||||||
+19
-10
@@ -18,6 +18,7 @@ import org.apache.fineract.portfolio.cashreport.service.CashierRoleHelper;
|
|||||||
import org.apache.fineract.portfolio.denominationmaster.service.DenominationBreakdownWriter;
|
import org.apache.fineract.portfolio.denominationmaster.service.DenominationBreakdownWriter;
|
||||||
import org.springframework.jdbc.core.JdbcTemplate;
|
import org.springframework.jdbc.core.JdbcTemplate;
|
||||||
import org.springframework.stereotype.Component;
|
import org.springframework.stereotype.Component;
|
||||||
|
import org.apache.fineract.infrastructure.core.service.DateUtils;
|
||||||
|
|
||||||
@Path("/v1/cashreports")
|
@Path("/v1/cashreports")
|
||||||
@Component
|
@Component
|
||||||
@@ -34,7 +35,7 @@ public class CashReportApiResource {
|
|||||||
@GET
|
@GET
|
||||||
@Path("closing")
|
@Path("closing")
|
||||||
public String closing(@QueryParam("date") String date) {
|
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
|
// 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, "
|
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);
|
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
|
// 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 "
|
final String sql = "SELECT MIN(ct.transfer_date) AS earliest_unsettled "
|
||||||
@@ -256,7 +257,9 @@ public class CashReportApiResource {
|
|||||||
java.sql.Date earliestDate = null;
|
java.sql.Date earliestDate = null;
|
||||||
try {
|
try {
|
||||||
earliestDate = jdbcTemplate.queryForObject(sql, java.sql.Date.class, cashierId, today, cashierId);
|
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 boolean unsettled = earliestDate != null;
|
||||||
final String unsettledSince = earliestDate != null ? earliestDate.toString() : null;
|
final String unsettledSince = earliestDate != null ? earliestDate.toString() : null;
|
||||||
@@ -265,7 +268,9 @@ public class CashReportApiResource {
|
|||||||
if (unsettled) {
|
if (unsettled) {
|
||||||
try {
|
try {
|
||||||
pendingAmount = denominationBreakdownWriter.getCashierTotalCash(cashierId);
|
pendingAmount = denominationBreakdownWriter.getCashierTotalCash(cashierId);
|
||||||
} catch (Exception ignored) {}
|
} catch (Exception ignored) {
|
||||||
|
// intentionally ignored
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Check whether today's morning cash transfer has been received
|
// Check whether today's morning cash transfer has been received
|
||||||
@@ -276,7 +281,9 @@ public class CashReportApiResource {
|
|||||||
Integer todayTransferCount = 0;
|
Integer todayTransferCount = 0;
|
||||||
try {
|
try {
|
||||||
todayTransferCount = jdbcTemplate.queryForObject(morningTransferSql, Integer.class, cashierId, today);
|
todayTransferCount = jdbcTemplate.queryForObject(morningTransferSql, Integer.class, cashierId, today);
|
||||||
} catch (Exception ignored) {}
|
} catch (Exception ignored) {
|
||||||
|
// intentionally ignored
|
||||||
|
}
|
||||||
final boolean morningTransferReceived = todayTransferCount != null && todayTransferCount > 0;
|
final boolean morningTransferReceived = todayTransferCount != null && todayTransferCount > 0;
|
||||||
|
|
||||||
result.put("cashierId", cashierId);
|
result.put("cashierId", cashierId);
|
||||||
@@ -295,7 +302,7 @@ public class CashReportApiResource {
|
|||||||
@Path("cashier-position")
|
@Path("cashier-position")
|
||||||
public String cashierPosition(@QueryParam("cashierId") Long cashierId,
|
public String cashierPosition(@QueryParam("cashierId") Long cashierId,
|
||||||
@QueryParam("asOfDate") String asOfDate) {
|
@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
|
// CASHIER role: always scope to their own position only
|
||||||
final Long scopedId = cashierRoleHelper.getCashierIdForFiltering();
|
final Long scopedId = cashierRoleHelper.getCashierIdForFiltering();
|
||||||
@@ -326,7 +333,7 @@ public class CashReportApiResource {
|
|||||||
@GET
|
@GET
|
||||||
@Path("cashier-position/me")
|
@Path("cashier-position/me")
|
||||||
public String cashierPositionMe(@QueryParam("asOfDate") String asOfDate) {
|
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;
|
Long appUserId;
|
||||||
try {
|
try {
|
||||||
appUserId = context.authenticatedUser().getId();
|
appUserId = context.authenticatedUser().getId();
|
||||||
@@ -362,7 +369,7 @@ public class CashReportApiResource {
|
|||||||
@Path("cashier-morning")
|
@Path("cashier-morning")
|
||||||
public String cashierMorning(@QueryParam("cashierId") Long cashierId,
|
public String cashierMorning(@QueryParam("cashierId") Long cashierId,
|
||||||
@QueryParam("date") String date) {
|
@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) {
|
if (cashierId == null) {
|
||||||
Map<String, Object> empty = new LinkedHashMap<>();
|
Map<String, Object> empty = new LinkedHashMap<>();
|
||||||
empty.put("cashierId", null);
|
empty.put("cashierId", null);
|
||||||
@@ -515,7 +522,9 @@ public class CashReportApiResource {
|
|||||||
cashierName = jdbcTemplate.queryForObject(
|
cashierName = jdbcTemplate.queryForObject(
|
||||||
"SELECT ms.display_name FROM m_cashiers mc JOIN m_staff ms ON ms.id = mc.staff_id WHERE mc.id = ?",
|
"SELECT ms.display_name FROM m_cashiers mc JOIN m_staff ms ON ms.id = mc.staff_id WHERE mc.id = ?",
|
||||||
String.class, cashierId);
|
String.class, cashierId);
|
||||||
} catch (Exception ignored) {}
|
} catch (Exception ignored) {
|
||||||
|
// intentionally ignored
|
||||||
|
}
|
||||||
|
|
||||||
Map<String, Object> result = new LinkedHashMap<>();
|
Map<String, Object> result = new LinkedHashMap<>();
|
||||||
result.put("cashierId", cashierId);
|
result.put("cashierId", cashierId);
|
||||||
@@ -562,7 +571,7 @@ public class CashReportApiResource {
|
|||||||
@QueryParam("offset") Integer offset,
|
@QueryParam("offset") Integer offset,
|
||||||
@QueryParam("limit") Integer limit) {
|
@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 resolvedLimit = (limit != null && limit > 0) ? limit : 20;
|
||||||
final int resolvedOffset = (offset != null && offset >= 0) ? offset : 0;
|
final int resolvedOffset = (offset != null && offset >= 0) ? offset : 0;
|
||||||
|
|
||||||
|
|||||||
+24
-11
@@ -36,6 +36,7 @@ import org.springframework.stereotype.Component;
|
|||||||
import org.springframework.transaction.PlatformTransactionManager;
|
import org.springframework.transaction.PlatformTransactionManager;
|
||||||
import org.springframework.transaction.annotation.Transactional;
|
import org.springframework.transaction.annotation.Transactional;
|
||||||
import org.springframework.transaction.support.TransactionTemplate;
|
import org.springframework.transaction.support.TransactionTemplate;
|
||||||
|
import org.apache.fineract.infrastructure.core.service.DateUtils;
|
||||||
|
|
||||||
@Path("/v1/cashsettlement")
|
@Path("/v1/cashsettlement")
|
||||||
@Component
|
@Component
|
||||||
@@ -70,7 +71,7 @@ public class CashSettlementApiResource {
|
|||||||
}
|
}
|
||||||
|
|
||||||
final LocalDate settlementDate = json.has("settlementDate") && !json.get("settlementDate").isJsonNull()
|
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()
|
final String fromParty = json.has("fromParty") && !json.get("fromParty").isJsonNull()
|
||||||
? json.get("fromParty").getAsString() : null;
|
? json.get("fromParty").getAsString() : null;
|
||||||
final String toParty = json.has("toParty") && !json.get("toParty").isJsonNull()
|
final String toParty = json.has("toParty") && !json.get("toParty").isJsonNull()
|
||||||
@@ -116,13 +117,15 @@ public class CashSettlementApiResource {
|
|||||||
header.setToParty(toParty);
|
header.setToParty(toParty);
|
||||||
header.setSettlementAmount(total);
|
header.setSettlementAmount(total);
|
||||||
header.setNote(note);
|
header.setNote(note);
|
||||||
header.setCreatedAt(LocalDateTime.now());
|
header.setCreatedAt(LocalDateTime.now(DateUtils.getDateTimeZoneOfTenant()));
|
||||||
header.setIsReversed(false);
|
header.setIsReversed(false);
|
||||||
try {
|
try {
|
||||||
AppUser user = this.context.authenticatedUser();
|
AppUser user = this.context.authenticatedUser();
|
||||||
header.setPerformedBy(user.getId());
|
header.setPerformedBy(user.getId());
|
||||||
header.setPerformedByUsername(user.getUsername());
|
header.setPerformedByUsername(user.getUsername());
|
||||||
} catch (Exception ignored) {}
|
} catch (Exception ignored) {
|
||||||
|
// intentionally ignored
|
||||||
|
}
|
||||||
|
|
||||||
// Commit header + details first, then GL dispatch separately to avoid
|
// Commit header + details first, then GL dispatch separately to avoid
|
||||||
// EclipseLink flushing pending detail rows inside Fineract's GL transaction.
|
// EclipseLink flushing pending detail rows inside Fineract's GL transaction.
|
||||||
@@ -142,7 +145,9 @@ public class CashSettlementApiResource {
|
|||||||
Long resolved = jdbcTemplate.queryForObject(
|
Long resolved = jdbcTemplate.queryForObject(
|
||||||
"SELECT teller_id FROM m_cashiers WHERE id = ?", Long.class, fromCashierId);
|
"SELECT teller_id FROM m_cashiers WHERE id = ?", Long.class, fromCashierId);
|
||||||
if (resolved != null) glTellerId = resolved;
|
if (resolved != null) glTellerId = resolved;
|
||||||
} catch (Exception ignored) {}
|
} catch (Exception ignored) {
|
||||||
|
// intentionally ignored
|
||||||
|
}
|
||||||
glDispatchService.settleCashFromCashier(glTellerId, fromCashierId, total,
|
glDispatchService.settleCashFromCashier(glTellerId, fromCashierId, total,
|
||||||
currencyCode, settlementDate.format(DateTimeFormatter.ISO_LOCAL_DATE),
|
currencyCode, settlementDate.format(DateTimeFormatter.ISO_LOCAL_DATE),
|
||||||
note != null ? note : "");
|
note != null ? note : "");
|
||||||
@@ -174,13 +179,17 @@ public class CashSettlementApiResource {
|
|||||||
try {
|
try {
|
||||||
JsonObject json = JsonParser.parseString(body).getAsJsonObject();
|
JsonObject json = JsonParser.parseString(body).getAsJsonObject();
|
||||||
reason = json.has("reason") ? json.get("reason").getAsString() : null;
|
reason = json.has("reason") ? json.get("reason").getAsString() : null;
|
||||||
} catch (Exception ignored) {}
|
} catch (Exception ignored) {
|
||||||
|
// intentionally ignored
|
||||||
|
}
|
||||||
|
|
||||||
AppUser user = null;
|
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.setIsReversed(true);
|
||||||
settlement.setReversedAt(LocalDateTime.now());
|
settlement.setReversedAt(LocalDateTime.now(DateUtils.getDateTimeZoneOfTenant()));
|
||||||
settlement.setReverseReason(reason);
|
settlement.setReverseReason(reason);
|
||||||
if (user != null) settlement.setReversedBy(user.getId());
|
if (user != null) settlement.setReversedBy(user.getId());
|
||||||
repository.save(settlement);
|
repository.save(settlement);
|
||||||
@@ -192,12 +201,16 @@ public class CashSettlementApiResource {
|
|||||||
Long resolved = jdbcTemplate.queryForObject(
|
Long resolved = jdbcTemplate.queryForObject(
|
||||||
"SELECT teller_id FROM m_cashiers WHERE id = ?", Long.class, settlement.getFromCashierId());
|
"SELECT teller_id FROM m_cashiers WHERE id = ?", Long.class, settlement.getFromCashierId());
|
||||||
if (resolved != null) glTellerId = resolved;
|
if (resolved != null) glTellerId = resolved;
|
||||||
} catch (Exception ignored) {}
|
} catch (Exception ignored) {
|
||||||
|
// intentionally ignored
|
||||||
|
}
|
||||||
glDispatchService.allocateCashToCashier(glTellerId,
|
glDispatchService.allocateCashToCashier(glTellerId,
|
||||||
settlement.getFromCashierId(), settlement.getSettlementAmount(), "INR",
|
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 : ""));
|
"Reversal of cash settlement #" + id + (reason != null ? ": " + reason : ""));
|
||||||
} catch (Exception ignored) {}
|
} catch (Exception ignored) {
|
||||||
|
// intentionally ignored
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
JsonObject result = new JsonObject();
|
JsonObject result = new JsonObject();
|
||||||
@@ -214,7 +227,7 @@ public class CashSettlementApiResource {
|
|||||||
throw new PlatformDataIntegrityException("error.msg.cashsettlement.cashier.required",
|
throw new PlatformDataIntegrityException("error.msg.cashsettlement.cashier.required",
|
||||||
"cashierId query param is 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(
|
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)",
|
"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);
|
Integer.class, cashierId, settlementDate);
|
||||||
|
|||||||
+20
-9
@@ -36,6 +36,7 @@ import org.springframework.stereotype.Component;
|
|||||||
import org.springframework.transaction.PlatformTransactionManager;
|
import org.springframework.transaction.PlatformTransactionManager;
|
||||||
import org.springframework.transaction.annotation.Transactional;
|
import org.springframework.transaction.annotation.Transactional;
|
||||||
import org.springframework.transaction.support.TransactionTemplate;
|
import org.springframework.transaction.support.TransactionTemplate;
|
||||||
|
import org.apache.fineract.infrastructure.core.service.DateUtils;
|
||||||
|
|
||||||
@Path("/v1/cashtransfer")
|
@Path("/v1/cashtransfer")
|
||||||
@Component
|
@Component
|
||||||
@@ -105,7 +106,7 @@ public class CashTransferApiResource {
|
|||||||
header.setToCashierId(toCashierId);
|
header.setToCashierId(toCashierId);
|
||||||
header.setTransferAmount(total);
|
header.setTransferAmount(total);
|
||||||
header.setNote(note);
|
header.setNote(note);
|
||||||
header.setCreatedAt(LocalDateTime.now());
|
header.setCreatedAt(LocalDateTime.now(DateUtils.getDateTimeZoneOfTenant()));
|
||||||
try {
|
try {
|
||||||
AppUser user = this.context.authenticatedUser();
|
AppUser user = this.context.authenticatedUser();
|
||||||
if (user != null) {
|
if (user != null) {
|
||||||
@@ -136,8 +137,10 @@ public class CashTransferApiResource {
|
|||||||
Long resolved = jdbcTemplate.queryForObject(
|
Long resolved = jdbcTemplate.queryForObject(
|
||||||
"SELECT teller_id FROM m_cashiers WHERE id = ?", Long.class, toCashierId);
|
"SELECT teller_id FROM m_cashiers WHERE id = ?", Long.class, toCashierId);
|
||||||
if (resolved != null) glTellerId = resolved;
|
if (resolved != null) glTellerId = resolved;
|
||||||
} catch (Exception ignored) {}
|
} catch (Exception ignored) {
|
||||||
final LocalDate txnDate = transferDate != null ? transferDate : LocalDate.now();
|
// intentionally ignored
|
||||||
|
}
|
||||||
|
final LocalDate txnDate = transferDate != null ? transferDate : LocalDate.now(DateUtils.getDateTimeZoneOfTenant());
|
||||||
glDispatchService.allocateCashToCashier(glTellerId, toCashierId, total,
|
glDispatchService.allocateCashToCashier(glTellerId, toCashierId, total,
|
||||||
currencyCode, txnDate.format(DateTimeFormatter.ISO_LOCAL_DATE),
|
currencyCode, txnDate.format(DateTimeFormatter.ISO_LOCAL_DATE),
|
||||||
note != null ? note : "");
|
note != null ? note : "");
|
||||||
@@ -169,15 +172,19 @@ public class CashTransferApiResource {
|
|||||||
try {
|
try {
|
||||||
JsonObject json = JsonParser.parseString(body).getAsJsonObject();
|
JsonObject json = JsonParser.parseString(body).getAsJsonObject();
|
||||||
reason = json.has("reason") ? json.get("reason").getAsString() : null;
|
reason = json.has("reason") ? json.get("reason").getAsString() : null;
|
||||||
} catch (Exception ignored) {}
|
} catch (Exception ignored) {
|
||||||
|
// intentionally ignored
|
||||||
|
}
|
||||||
|
|
||||||
try {
|
try {
|
||||||
AppUser user = this.context.authenticatedUser();
|
AppUser user = this.context.authenticatedUser();
|
||||||
transfer.setReversedBy(user.getId());
|
transfer.setReversedBy(user.getId());
|
||||||
} catch (Exception ignored) {}
|
} catch (Exception ignored) {
|
||||||
|
// intentionally ignored
|
||||||
|
}
|
||||||
|
|
||||||
transfer.setIsReversed(true);
|
transfer.setIsReversed(true);
|
||||||
transfer.setReversedAt(java.time.LocalDateTime.now());
|
transfer.setReversedAt(java.time.LocalDateTime.now(DateUtils.getDateTimeZoneOfTenant()));
|
||||||
transfer.setReverseReason(reason);
|
transfer.setReverseReason(reason);
|
||||||
repository.save(transfer);
|
repository.save(transfer);
|
||||||
|
|
||||||
@@ -188,12 +195,16 @@ public class CashTransferApiResource {
|
|||||||
Long resolved = jdbcTemplate.queryForObject(
|
Long resolved = jdbcTemplate.queryForObject(
|
||||||
"SELECT teller_id FROM m_cashiers WHERE id = ?", Long.class, transfer.getToCashierId());
|
"SELECT teller_id FROM m_cashiers WHERE id = ?", Long.class, transfer.getToCashierId());
|
||||||
if (resolved != null) glTellerId = resolved;
|
if (resolved != null) glTellerId = resolved;
|
||||||
} catch (Exception ignored) {}
|
} catch (Exception ignored) {
|
||||||
|
// intentionally ignored
|
||||||
|
}
|
||||||
glDispatchService.settleCashFromCashier(glTellerId,
|
glDispatchService.settleCashFromCashier(glTellerId,
|
||||||
transfer.getToCashierId(), transfer.getTransferAmount(), "INR",
|
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 : ""));
|
"Reversal of cash transfer #" + id + (reason != null ? ": " + reason : ""));
|
||||||
} catch (Exception ignored) {}
|
} catch (Exception ignored) {
|
||||||
|
// intentionally ignored
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
JsonObject result = new JsonObject();
|
JsonObject result = new JsonObject();
|
||||||
|
|||||||
+6
-3
@@ -38,6 +38,7 @@ import org.apache.fineract.portfolio.denominationmaster.domain.SavingsTxnDenomin
|
|||||||
import org.apache.fineract.useradministration.domain.AppUser;
|
import org.apache.fineract.useradministration.domain.AppUser;
|
||||||
import org.springframework.stereotype.Component;
|
import org.springframework.stereotype.Component;
|
||||||
import org.springframework.transaction.annotation.Transactional;
|
import org.springframework.transaction.annotation.Transactional;
|
||||||
|
import org.apache.fineract.infrastructure.core.service.DateUtils;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Records cashier denomination breakdown for GL account transactions (journal entries).
|
* 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 String txnDateStr = fromJsonHelper.extractStringNamed("txnDate", root);
|
||||||
final LocalDate txnDate = (txnDateStr != null && !txnDateStr.isBlank())
|
final LocalDate txnDate = (txnDateStr != null && !txnDateStr.isBlank())
|
||||||
? LocalDate.parse(txnDateStr)
|
? LocalDate.parse(txnDateStr)
|
||||||
: LocalDate.now();
|
: LocalDate.now(DateUtils.getDateTimeZoneOfTenant());
|
||||||
|
|
||||||
if (!fromJsonHelper.parameterExists("denominationBreakdown", root)) {
|
if (!fromJsonHelper.parameterExists("denominationBreakdown", root)) {
|
||||||
return "{\"result\":\"skipped\"}";
|
return "{\"result\":\"skipped\"}";
|
||||||
@@ -109,7 +110,9 @@ public class CashierGlDenominationApiResource {
|
|||||||
officerId = user.getId();
|
officerId = user.getId();
|
||||||
officerUsername = user.getUsername();
|
officerUsername = user.getUsername();
|
||||||
}
|
}
|
||||||
} catch (final Exception ignored) {}
|
} catch (final Exception ignored) {
|
||||||
|
// intentionally ignored
|
||||||
|
}
|
||||||
|
|
||||||
final String resolvedTxnType = (txnType != null && !txnType.isBlank())
|
final String resolvedTxnType = (txnType != null && !txnType.isBlank())
|
||||||
? txnType.toUpperCase()
|
? txnType.toUpperCase()
|
||||||
@@ -144,7 +147,7 @@ public class CashierGlDenominationApiResource {
|
|||||||
.count(count)
|
.count(count)
|
||||||
.totalAmount(lineTotal)
|
.totalAmount(lineTotal)
|
||||||
.txnDate(txnDate)
|
.txnDate(txnDate)
|
||||||
.createdAt(LocalDateTime.now())
|
.createdAt(LocalDateTime.now(DateUtils.getDateTimeZoneOfTenant()))
|
||||||
.txnType(resolvedTxnType)
|
.txnType(resolvedTxnType)
|
||||||
.officerId(officerId)
|
.officerId(officerId)
|
||||||
.officerUsername(officerUsername)
|
.officerUsername(officerUsername)
|
||||||
|
|||||||
+3
-2
@@ -29,6 +29,7 @@ import org.springframework.dao.IncorrectResultSizeDataAccessException;
|
|||||||
import org.springframework.jdbc.core.JdbcTemplate;
|
import org.springframework.jdbc.core.JdbcTemplate;
|
||||||
import org.springframework.stereotype.Component;
|
import org.springframework.stereotype.Component;
|
||||||
import org.springframework.transaction.annotation.Transactional;
|
import org.springframework.transaction.annotation.Transactional;
|
||||||
|
import org.apache.fineract.infrastructure.core.service.DateUtils;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Cashier Share Collection API — POST /v1/cashier/sharecollection
|
* Cashier Share Collection API — POST /v1/cashier/sharecollection
|
||||||
@@ -131,7 +132,7 @@ public class ShareCollectionApiResource {
|
|||||||
final LocalDate entryDate;
|
final LocalDate entryDate;
|
||||||
try {
|
try {
|
||||||
entryDate = transactionDateStr != null
|
entryDate = transactionDateStr != null
|
||||||
? LocalDate.parse(transactionDateStr) : LocalDate.now();
|
? LocalDate.parse(transactionDateStr) : LocalDate.now(DateUtils.getDateTimeZoneOfTenant());
|
||||||
} catch (DateTimeParseException e) {
|
} catch (DateTimeParseException e) {
|
||||||
throw new PlatformDataIntegrityException(
|
throw new PlatformDataIntegrityException(
|
||||||
"error.msg.sharecollection.date.invalid",
|
"error.msg.sharecollection.date.invalid",
|
||||||
@@ -193,7 +194,7 @@ public class ShareCollectionApiResource {
|
|||||||
final String txnId = "SC-" + shareAccountId + "-" + System.currentTimeMillis();
|
final String txnId = "SC-" + shareAccountId + "-" + System.currentTimeMillis();
|
||||||
final long userId = currentUser.getId();
|
final long userId = currentUser.getId();
|
||||||
final String collectorName = currentUser.getUsername();
|
final String collectorName = currentUser.getUsername();
|
||||||
final LocalDateTime now = LocalDateTime.now();
|
final LocalDateTime now = LocalDateTime.now(DateUtils.getDateTimeZoneOfTenant());
|
||||||
|
|
||||||
// ── Post GL journal entries ────────────────────────────────────────
|
// ── Post GL journal entries ────────────────────────────────────────
|
||||||
// Dr Cash at Vault (SHARES_REFERENCE) = totalAmount
|
// Dr Cash at Vault (SHARES_REFERENCE) = totalAmount
|
||||||
|
|||||||
-1
@@ -41,7 +41,6 @@ import org.apache.fineract.infrastructure.core.serialization.DefaultToApiJsonSer
|
|||||||
import org.apache.fineract.infrastructure.security.service.PlatformSecurityContext;
|
import org.apache.fineract.infrastructure.security.service.PlatformSecurityContext;
|
||||||
import org.apache.fineract.portfolio.cfcfrms.data.ComplaintStatsData;
|
import org.apache.fineract.portfolio.cfcfrms.data.ComplaintStatsData;
|
||||||
import org.apache.fineract.portfolio.cfcfrms.data.ComplaintTicketData;
|
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.apache.fineract.portfolio.cfcfrms.service.CfcfrmsComplaintService;
|
||||||
import org.springframework.data.domain.Page;
|
import org.springframework.data.domain.Page;
|
||||||
import org.springframework.data.domain.PageRequest;
|
import org.springframework.data.domain.PageRequest;
|
||||||
|
|||||||
+1
-1
@@ -56,7 +56,7 @@ import org.springframework.stereotype.Component;
|
|||||||
* POST /v1/simulator/cfcfrms/verify-account – Verify account at bank
|
* POST /v1/simulator/cfcfrms/verify-account – Verify account at bank
|
||||||
* POST /v1/simulator/cfcfrms/verify-transaction – Verify transaction ref
|
* 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/complaint-status/{ref} – Complaint status from CFCFRMS side
|
||||||
* GET /v1/simulator/cfcfrms/bank-performance – Bank performance metrics
|
* GET /v1/simulator/cfcfrms/bank-performance – Bank performance metrics
|
||||||
* </pre>
|
* </pre>
|
||||||
|
|||||||
+2
-1
@@ -36,6 +36,7 @@ import org.springframework.boot.context.event.ApplicationReadyEvent;
|
|||||||
import org.springframework.context.event.EventListener;
|
import org.springframework.context.event.EventListener;
|
||||||
import org.springframework.stereotype.Component;
|
import org.springframework.stereotype.Component;
|
||||||
import org.springframework.transaction.annotation.Transactional;
|
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.
|
* Seeds CFCFRMS complaint tickets, audit logs, and simulator logs on startup.
|
||||||
@@ -59,7 +60,7 @@ public class CfcfrmsDataSeeder {
|
|||||||
}
|
}
|
||||||
|
|
||||||
LOG.info("Seeding CFCFRMS complaint data...");
|
LOG.info("Seeding CFCFRMS complaint data...");
|
||||||
final OffsetDateTime now = OffsetDateTime.now();
|
final OffsetDateTime now = OffsetDateTime.now(DateUtils.getDateTimeZoneOfTenant());
|
||||||
|
|
||||||
// ─── 3 RECEIVED ──────────────────────────────────────────────
|
// ─── 3 RECEIVED ──────────────────────────────────────────────
|
||||||
seedTicket("TKT-20250318-001", "Rajesh Kumar Sharma", "9876543210",
|
seedTicket("TKT-20250318-001", "Rajesh Kumar Sharma", "9876543210",
|
||||||
|
|||||||
+3
-2
@@ -46,6 +46,7 @@ import org.springframework.data.domain.Page;
|
|||||||
import org.springframework.data.domain.Pageable;
|
import org.springframework.data.domain.Pageable;
|
||||||
import org.springframework.stereotype.Service;
|
import org.springframework.stereotype.Service;
|
||||||
import org.springframework.transaction.annotation.Transactional;
|
import org.springframework.transaction.annotation.Transactional;
|
||||||
|
import org.apache.fineract.infrastructure.core.service.DateUtils;
|
||||||
|
|
||||||
@Service
|
@Service
|
||||||
@RequiredArgsConstructor
|
@RequiredArgsConstructor
|
||||||
@@ -206,7 +207,7 @@ public class CfcfrmsComplaintServiceImpl implements CfcfrmsComplaintService {
|
|||||||
final Map<String, Object> result = new HashMap<>();
|
final Map<String, Object> result = new HashMap<>();
|
||||||
result.put("escalatedTo", nextIfsc);
|
result.put("escalatedTo", nextIfsc);
|
||||||
result.put("escalationRef", escalationRef);
|
result.put("escalationRef", escalationRef);
|
||||||
result.put("timestamp", OffsetDateTime.now().toString());
|
result.put("timestamp", OffsetDateTime.now(DateUtils.getDateTimeZoneOfTenant()).toString());
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -218,7 +219,7 @@ public class CfcfrmsComplaintServiceImpl implements CfcfrmsComplaintService {
|
|||||||
}
|
}
|
||||||
|
|
||||||
private String generateTicketId() {
|
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);
|
final int seq = (int) (ticketRepository.count() + 1);
|
||||||
return String.format("TKT-%s-%03d", date, seq);
|
return String.format("TKT-%s-%03d", date, seq);
|
||||||
}
|
}
|
||||||
|
|||||||
+8
-9
@@ -25,12 +25,10 @@ import java.time.LocalDate;
|
|||||||
import java.time.OffsetDateTime;
|
import java.time.OffsetDateTime;
|
||||||
import java.time.format.DateTimeFormatter;
|
import java.time.format.DateTimeFormatter;
|
||||||
import java.util.ArrayList;
|
import java.util.ArrayList;
|
||||||
import java.util.HashMap;
|
|
||||||
import java.util.LinkedHashMap;
|
import java.util.LinkedHashMap;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
import java.util.Map;
|
import java.util.Map;
|
||||||
import java.util.Random;
|
import java.util.Random;
|
||||||
import java.util.UUID;
|
|
||||||
import java.util.stream.Collectors;
|
import java.util.stream.Collectors;
|
||||||
import lombok.RequiredArgsConstructor;
|
import lombok.RequiredArgsConstructor;
|
||||||
import org.apache.fineract.portfolio.cfcfrms.data.CfcfrmsConstants;
|
import org.apache.fineract.portfolio.cfcfrms.data.CfcfrmsConstants;
|
||||||
@@ -44,6 +42,7 @@ import org.slf4j.Logger;
|
|||||||
import org.slf4j.LoggerFactory;
|
import org.slf4j.LoggerFactory;
|
||||||
import org.springframework.stereotype.Service;
|
import org.springframework.stereotype.Service;
|
||||||
import org.springframework.transaction.annotation.Transactional;
|
import org.springframework.transaction.annotation.Transactional;
|
||||||
|
import org.apache.fineract.infrastructure.core.service.DateUtils;
|
||||||
|
|
||||||
@Service
|
@Service
|
||||||
@RequiredArgsConstructor
|
@RequiredArgsConstructor
|
||||||
@@ -76,7 +75,7 @@ public class CfcfrmsSimulatorServiceImpl implements CfcfrmsSimulatorService {
|
|||||||
final Map<String, Object> response = new LinkedHashMap<>();
|
final Map<String, Object> response = new LinkedHashMap<>();
|
||||||
response.put("cfcfrmsRef", cfcfrmsRef);
|
response.put("cfcfrmsRef", cfcfrmsRef);
|
||||||
response.put("ticketId", ticketData.getTicketId());
|
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("bankAcknowledged", true);
|
||||||
response.put("message", "Complaint pushed to " + CfcfrmsConstants.BANK_IFSC + " successfully");
|
response.put("message", "Complaint pushed to " + CfcfrmsConstants.BANK_IFSC + " successfully");
|
||||||
return response;
|
return response;
|
||||||
@@ -85,7 +84,7 @@ public class CfcfrmsSimulatorServiceImpl implements CfcfrmsSimulatorService {
|
|||||||
@Override
|
@Override
|
||||||
public Map<String, Object> pushHoldDirective(final JsonObject json) {
|
public Map<String, Object> pushHoldDirective(final JsonObject json) {
|
||||||
final String cfcfrmsRef = getStringOrThrow(json, "cfcfrmsRef");
|
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));
|
+ "-" + String.format("%04d", RANDOM.nextInt(10000));
|
||||||
|
|
||||||
final String directiveType = getStringOrThrow(json, "directiveType");
|
final String directiveType = getStringOrThrow(json, "directiveType");
|
||||||
@@ -112,7 +111,7 @@ public class CfcfrmsSimulatorServiceImpl implements CfcfrmsSimulatorService {
|
|||||||
response.put("directiveRef", directiveRef);
|
response.put("directiveRef", directiveRef);
|
||||||
response.put("status", "DIRECTIVE_SENT");
|
response.put("status", "DIRECTIVE_SENT");
|
||||||
response.put("bankResponse", bankResponse);
|
response.put("bankResponse", bankResponse);
|
||||||
response.put("timestamp", OffsetDateTime.now().toString());
|
response.put("timestamp", OffsetDateTime.now(DateUtils.getDateTimeZoneOfTenant()).toString());
|
||||||
return response;
|
return response;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -208,7 +207,7 @@ public class CfcfrmsSimulatorServiceImpl implements CfcfrmsSimulatorService {
|
|||||||
public Map<String, Object> receiveEscalation(final JsonObject json) {
|
public Map<String, Object> receiveEscalation(final JsonObject json) {
|
||||||
final String cfcfrmsRef = getStringOrThrow(json, "cfcfrmsRef");
|
final String cfcfrmsRef = getStringOrThrow(json, "cfcfrmsRef");
|
||||||
final String ticketId = getStringOrThrow(json, "ticketId");
|
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));
|
+ "-" + String.format("%04d", RANDOM.nextInt(10000));
|
||||||
|
|
||||||
// Extract nextBank from fundsMovedTo
|
// Extract nextBank from fundsMovedTo
|
||||||
@@ -268,7 +267,7 @@ public class CfcfrmsSimulatorServiceImpl implements CfcfrmsSimulatorService {
|
|||||||
final Map<String, Object> response = new LinkedHashMap<>();
|
final Map<String, Object> response = new LinkedHashMap<>();
|
||||||
response.put("transactionFound", true);
|
response.put("transactionFound", true);
|
||||||
response.put("transactionStatus", "COMPLETED");
|
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("senderAccount", json.has("accountNumber") ? json.get("accountNumber").getAsString() : "UNKNOWN");
|
||||||
response.put("receiverAccount", 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) + "%"
|
.setScale(1, java.math.RoundingMode.HALF_UP) + "%"
|
||||||
: "0.0%";
|
: "0.0%";
|
||||||
response.put("tatComplianceRate", tatCompliance);
|
response.put("tatComplianceRate", tatCompliance);
|
||||||
response.put("lastActivityAt", OffsetDateTime.now().toString());
|
response.put("lastActivityAt", OffsetDateTime.now(DateUtils.getDateTimeZoneOfTenant()).toString());
|
||||||
return response;
|
return response;
|
||||||
}
|
}
|
||||||
|
|
||||||
// ── Helpers ──
|
// ── Helpers ──
|
||||||
|
|
||||||
private String generateCfcfrmsRef() {
|
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));
|
return "CFCFRMS-" + date + "-" + String.format("%04d", RANDOM.nextInt(10000));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
+1
-1
@@ -201,7 +201,7 @@ public class NpciInwardPushService {
|
|||||||
final String presentingBranchCode = getString(instrument, "depositBranchCode");
|
final String presentingBranchCode = getString(instrument, "depositBranchCode");
|
||||||
item.recordInwardMeta(getString(instrument, "serialNumber"), presentingBranchCode, batch.getReturnTatDeadline());
|
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()
|
? instrument.get("stopPaymentFlag").getAsBoolean()
|
||||||
: null;
|
: null;
|
||||||
item.recordSourceDetails(getString(instrument, "ctsReferenceNumber"), instrumentStopPaymentFlag,
|
item.recordSourceDetails(getString(instrument, "ctsReferenceNumber"), instrumentStopPaymentFlag,
|
||||||
|
|||||||
+11
-54
@@ -70,6 +70,7 @@ import org.apache.fineract.useradministration.domain.AppUser;
|
|||||||
import org.springframework.jdbc.core.JdbcTemplate;
|
import org.springframework.jdbc.core.JdbcTemplate;
|
||||||
import org.springframework.stereotype.Component;
|
import org.springframework.stereotype.Component;
|
||||||
import org.springframework.transaction.annotation.Transactional;
|
import org.springframework.transaction.annotation.Transactional;
|
||||||
|
import org.apache.fineract.infrastructure.core.service.DateUtils;
|
||||||
|
|
||||||
@Path("/v1/clerk/disbursement-requests")
|
@Path("/v1/clerk/disbursement-requests")
|
||||||
@Component
|
@Component
|
||||||
@@ -383,7 +384,7 @@ public class ClerkDisbursementRequestApiResource {
|
|||||||
final JsonArray creditEntries = gson.fromJson(creditEntriesJson, JsonArray.class);
|
final JsonArray creditEntries = gson.fromJson(creditEntriesJson, JsonArray.class);
|
||||||
final Object ptId = record.get("payment_type_id");
|
final Object ptId = record.get("payment_type_id");
|
||||||
final String description = (String) record.get("description");
|
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
|
final Long sourceGlId = record.get("gl_account_id") != null
|
||||||
? ((Number) record.get("gl_account_id")).longValue() : 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 entryType = entry.has("accountType") ? entry.get("accountType").getAsString() : "SAVINGS";
|
||||||
final String acNo = entry.has("accountNo") ? entry.get("accountNo").getAsString() : "?";
|
final String acNo = entry.has("accountNo") ? entry.get("accountNo").getAsString() : "?";
|
||||||
final Long entryPtId = entry.has("paymentTypeId") && !entry.get("paymentTypeId").isJsonNull()
|
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);
|
: (ptId != null ? ((Number) ptId).longValue() : null);
|
||||||
|
|
||||||
if ("GL".equals(entryType)) {
|
if ("GL".equals(entryType)) {
|
||||||
@@ -810,7 +811,7 @@ public class ClerkDisbursementRequestApiResource {
|
|||||||
? req.get("currencyCode").getAsString() : "INR";
|
? req.get("currencyCode").getAsString() : "INR";
|
||||||
final String txnDateStr = req.has("transactionDate") && !req.get("transactionDate").isJsonNull()
|
final String txnDateStr = req.has("transactionDate") && !req.get("transactionDate").isJsonNull()
|
||||||
? req.get("transactionDate").getAsString()
|
? 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()
|
final String description = req.has("description") && !req.get("description").isJsonNull()
|
||||||
? req.get("description").getAsString() : null;
|
? req.get("description").getAsString() : null;
|
||||||
|
|
||||||
@@ -830,7 +831,6 @@ public class ClerkDisbursementRequestApiResource {
|
|||||||
|
|
||||||
// Validate all entries: savings/current only (no GL), savingsAccountId present, amount > 0
|
// Validate all entries: savings/current only (no GL), savingsAccountId present, amount > 0
|
||||||
final Set<Long> drAccountIds = new LinkedHashSet<>();
|
final Set<Long> drAccountIds = new LinkedHashSet<>();
|
||||||
final Set<Long> crAccountIds = new LinkedHashSet<>();
|
|
||||||
|
|
||||||
for (final JsonObject e : drEntries) {
|
for (final JsonObject e : drEntries) {
|
||||||
final String acTyp = e.has("accountType") ? e.get("accountType").getAsString() : "SAVINGS";
|
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,
|
if (drAccountIds.contains(crId)) throw apiError(400,
|
||||||
"Account " + (e.has("accountNo") ? e.get("accountNo").getAsString() : crId)
|
"Account " + (e.has("accountNo") ? e.get("accountNo").getAsString() : crId)
|
||||||
+ " cannot appear on both DR and CR sides of the same transfer.");
|
+ " cannot appear on both DR and CR sides of the same transfer.");
|
||||||
crAccountIds.add(crId);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// Validate balanced entry: total DR == total CR
|
// Validate balanced entry: total DR == total CR
|
||||||
@@ -999,7 +998,7 @@ public class ClerkDisbursementRequestApiResource {
|
|||||||
* under concurrent inserts on the same date.
|
* under concurrent inserts on the same date.
|
||||||
*/
|
*/
|
||||||
private String generateBtVoucherNo(final long logId) {
|
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);
|
+ String.format("%05d", logId);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -1053,7 +1052,9 @@ public class ClerkDisbursementRequestApiResource {
|
|||||||
try {
|
try {
|
||||||
final Long txnIdLong = Long.parseLong(txnId);
|
final Long txnIdLong = Long.parseLong(txnId);
|
||||||
undoOps.add(() -> undoAccountTransaction(accountId, txnIdLong, isCurrentAccount));
|
undoOps.add(() -> undoAccountTransaction(accountId, txnIdLong, isCurrentAccount));
|
||||||
} catch (NumberFormatException ignored) {}
|
} catch (NumberFormatException ignored) {
|
||||||
|
// intentionally ignored
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private void undoAccountTransaction(final Long accountId, final Long transactionId,
|
private void undoAccountTransaction(final Long accountId, final Long transactionId,
|
||||||
@@ -1072,50 +1073,6 @@ public class ClerkDisbursementRequestApiResource {
|
|||||||
commandsSourceWritePlatformService.logCommandSource(cmd);
|
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) {
|
private boolean isCurrentAccountById(final Long accountId) {
|
||||||
try {
|
try {
|
||||||
final Integer count = jdbcTemplate.queryForObject(
|
final Integer count = jdbcTemplate.queryForObject(
|
||||||
@@ -1131,7 +1088,7 @@ public class ClerkDisbursementRequestApiResource {
|
|||||||
final LocalDate ld = LocalDate.parse(isoDate, DateTimeFormatter.ISO_LOCAL_DATE);
|
final LocalDate ld = LocalDate.parse(isoDate, DateTimeFormatter.ISO_LOCAL_DATE);
|
||||||
return ld.format(DateTimeFormatter.ofPattern("dd MMMM yyyy"));
|
return ld.format(DateTimeFormatter.ofPattern("dd MMMM yyyy"));
|
||||||
} catch (Exception e) {
|
} 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;
|
? (BigDecimal) accts.get(0).get("account_balance_derived") : BigDecimal.ZERO;
|
||||||
|
|
||||||
final java.sql.Date sqlDate = java.sql.Date.valueOf(txnDate);
|
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 String refNo = UUID.randomUUID().toString().replace("-", "").substring(0, 20);
|
||||||
final Long userId = currentUser.getId();
|
final Long userId = currentUser.getId();
|
||||||
|
|
||||||
@@ -1534,7 +1491,7 @@ public class ClerkDisbursementRequestApiResource {
|
|||||||
+ ". Available: " + currentBalance + ", Requested: " + amount);
|
+ ". Available: " + currentBalance + ", Requested: " + amount);
|
||||||
|
|
||||||
final java.sql.Date sqlDate = java.sql.Date.valueOf(txnDate);
|
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 String refNo = UUID.randomUUID().toString().replace("-", "").substring(0, 20);
|
||||||
final Long userId = currentUser.getId();
|
final Long userId = currentUser.getId();
|
||||||
|
|
||||||
|
|||||||
+7
-4
@@ -59,6 +59,9 @@ import org.apache.fineract.useradministration.domain.AppUser;
|
|||||||
import org.springframework.jdbc.core.JdbcTemplate;
|
import org.springframework.jdbc.core.JdbcTemplate;
|
||||||
import org.springframework.stereotype.Component;
|
import org.springframework.stereotype.Component;
|
||||||
import org.springframework.transaction.annotation.Transactional;
|
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")
|
@Path("/v1/clerk/withdrawal-requests")
|
||||||
@Component
|
@Component
|
||||||
@@ -437,7 +440,7 @@ public class ClerkWithdrawalRequestApiResource {
|
|||||||
final BigDecimal amount = new BigDecimal(record.get("amount").toString());
|
final BigDecimal amount = new BigDecimal(record.get("amount").toString());
|
||||||
final Object ptId = record.get("payment_type_id");
|
final Object ptId = record.get("payment_type_id");
|
||||||
final Object txnDateObj = record.get("txn_date");
|
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 description = (String) record.get("description");
|
||||||
|
|
||||||
String txnId = null;
|
String txnId = null;
|
||||||
@@ -713,7 +716,7 @@ public class ClerkWithdrawalRequestApiResource {
|
|||||||
final Long savingsAccountId, final BigDecimal amount,
|
final Long savingsAccountId, final BigDecimal amount,
|
||||||
final Object paymentTypeId, final String txnDateStr, final String note) {
|
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 String date = txnDateStr != null && !txnDateStr.isBlank() ? formatForFineract(txnDateStr) : today;
|
||||||
|
|
||||||
final JsonObject payload = new JsonObject();
|
final JsonObject payload = new JsonObject();
|
||||||
@@ -741,7 +744,7 @@ public class ClerkWithdrawalRequestApiResource {
|
|||||||
final Long currentAccountId, final BigDecimal amount,
|
final Long currentAccountId, final BigDecimal amount,
|
||||||
final Object paymentTypeId, final String txnDateStr, final String note) {
|
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 String date = txnDateStr != null && !txnDateStr.isBlank() ? formatForFineract(txnDateStr) : today;
|
||||||
|
|
||||||
final JsonObject payload = new JsonObject();
|
final JsonObject payload = new JsonObject();
|
||||||
@@ -780,7 +783,7 @@ public class ClerkWithdrawalRequestApiResource {
|
|||||||
final LocalDate ld = LocalDate.parse(isoDate, DateTimeFormatter.ISO_LOCAL_DATE);
|
final LocalDate ld = LocalDate.parse(isoDate, DateTimeFormatter.ISO_LOCAL_DATE);
|
||||||
return ld.format(DateTimeFormatter.ofPattern("dd MMMM yyyy"));
|
return ld.format(DateTimeFormatter.ofPattern("dd MMMM yyyy"));
|
||||||
} catch (Exception e) {
|
} catch (Exception e) {
|
||||||
return LocalDate.now().format(DateTimeFormatter.ofPattern("dd MMMM yyyy"));
|
return LocalDate.now(DateUtils.getDateTimeZoneOfTenant()).format(DateTimeFormatter.ofPattern("dd MMMM yyyy"));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
+20
-2
@@ -39,6 +39,8 @@ import jakarta.ws.rs.core.MediaType;
|
|||||||
import java.io.InputStream;
|
import java.io.InputStream;
|
||||||
import org.glassfish.jersey.media.multipart.FormDataContentDisposition;
|
import org.glassfish.jersey.media.multipart.FormDataContentDisposition;
|
||||||
import org.glassfish.jersey.media.multipart.FormDataParam;
|
import org.glassfish.jersey.media.multipart.FormDataParam;
|
||||||
|
import java.time.LocalDate;
|
||||||
|
import java.time.Period;
|
||||||
import java.util.ArrayList;
|
import java.util.ArrayList;
|
||||||
import java.util.LinkedHashMap;
|
import java.util.LinkedHashMap;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
@@ -158,7 +160,13 @@ public class ClientKycApiResource {
|
|||||||
template.put("clientTypeName", clientTypeName);
|
template.put("clientTypeName", clientTypeName);
|
||||||
template.put("legalFormId", legalFormId);
|
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);
|
return toApiJsonSerializer.serialize(template);
|
||||||
}
|
}
|
||||||
@@ -166,11 +174,21 @@ public class ClientKycApiResource {
|
|||||||
/**
|
/**
|
||||||
* Returns required KYC documents based on client type (RBI Master Direction on KYC).
|
* Returns required KYC documents based on client type (RBI Master Direction on KYC).
|
||||||
*/
|
*/
|
||||||
private List<Map<String, Object>> getRequiredDocuments(final String clientTypeName, final Integer legalFormId) {
|
private List<Map<String, Object>> getRequiredDocuments(final String clientTypeName, final Integer legalFormId,
|
||||||
|
final boolean isMinor) {
|
||||||
final List<Map<String, Object>> docs = new ArrayList<>();
|
final List<Map<String, Object>> docs = new ArrayList<>();
|
||||||
|
|
||||||
// Individual types (legalFormId=1)
|
// Individual types (legalFormId=1)
|
||||||
if (legalFormId != null && 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("Aadhaar Card", "AADHAAR", true));
|
||||||
docs.add(doc("PAN Card", "PAN", true));
|
docs.add(doc("PAN Card", "PAN", true));
|
||||||
docs.add(doc("Voter ID", "VOTER_ID", false));
|
docs.add(doc("Voter ID", "VOTER_ID", false));
|
||||||
|
|||||||
+5
-4
@@ -24,6 +24,7 @@ import java.util.concurrent.atomic.AtomicLong;
|
|||||||
import lombok.extern.slf4j.Slf4j;
|
import lombok.extern.slf4j.Slf4j;
|
||||||
import org.apache.fineract.portfolio.client.domain.ClientKyc;
|
import org.apache.fineract.portfolio.client.domain.ClientKyc;
|
||||||
import org.springframework.stereotype.Service;
|
import org.springframework.stereotype.Service;
|
||||||
|
import org.apache.fineract.infrastructure.core.service.DateUtils;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Dummy / stub implementation of {@link CkycSftpUploadService}.
|
* Dummy / stub implementation of {@link CkycSftpUploadService}.
|
||||||
@@ -60,7 +61,7 @@ public class DummyCkycSftpUploadServiceImpl implements CkycSftpUploadService {
|
|||||||
|
|
||||||
final String ckycNumber = generateCkycNumber(kyc.getClient().getId());
|
final String ckycNumber = generateCkycNumber(kyc.getClient().getId());
|
||||||
final String batchId = generateBatchId();
|
final String batchId = generateBatchId();
|
||||||
final LocalDate today = LocalDate.now();
|
final LocalDate today = LocalDate.now(DateUtils.getDateTimeZoneOfTenant());
|
||||||
|
|
||||||
return CkycUploadResult.builder()
|
return CkycUploadResult.builder()
|
||||||
.ckycNumber(ckycNumber)
|
.ckycNumber(ckycNumber)
|
||||||
@@ -82,7 +83,7 @@ public class DummyCkycSftpUploadServiceImpl implements CkycSftpUploadService {
|
|||||||
return CkycUploadResult.builder()
|
return CkycUploadResult.builder()
|
||||||
.status("FAILED")
|
.status("FAILED")
|
||||||
.remarks("Uploaded file is not a valid ZIP archive (bad magic bytes).")
|
.remarks("Uploaded file is not a valid ZIP archive (bad magic bytes).")
|
||||||
.uploadedOn(LocalDate.now())
|
.uploadedOn(LocalDate.now(DateUtils.getDateTimeZoneOfTenant()))
|
||||||
.build();
|
.build();
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -92,7 +93,7 @@ public class DummyCkycSftpUploadServiceImpl implements CkycSftpUploadService {
|
|||||||
return CkycUploadResult.builder()
|
return CkycUploadResult.builder()
|
||||||
.ckycNumber(ckycNumber)
|
.ckycNumber(ckycNumber)
|
||||||
.batchId(batchId)
|
.batchId(batchId)
|
||||||
.uploadedOn(LocalDate.now())
|
.uploadedOn(LocalDate.now(DateUtils.getDateTimeZoneOfTenant()))
|
||||||
.status("SUCCESS")
|
.status("SUCCESS")
|
||||||
.remarks("Dummy CKYC ZIP upload accepted (" + zipBytes.length + " bytes). "
|
.remarks("Dummy CKYC ZIP upload accepted (" + zipBytes.length + " bytes). "
|
||||||
+ "Replace with real CERSAI SFTP integration before go-live.")
|
+ "Replace with real CERSAI SFTP integration before go-live.")
|
||||||
@@ -112,7 +113,7 @@ public class DummyCkycSftpUploadServiceImpl implements CkycSftpUploadService {
|
|||||||
}
|
}
|
||||||
|
|
||||||
private String generateBatchId() {
|
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());
|
+ String.format("%06d", BATCH_COUNTER.getAndIncrement());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
+3
-2
@@ -50,6 +50,7 @@ import org.apache.fineract.portfolio.client.ckyc.domain.CkycBatchRepository;
|
|||||||
import org.springframework.jdbc.core.JdbcTemplate;
|
import org.springframework.jdbc.core.JdbcTemplate;
|
||||||
import org.springframework.stereotype.Service;
|
import org.springframework.stereotype.Service;
|
||||||
import org.springframework.transaction.annotation.Transactional;
|
import org.springframework.transaction.annotation.Transactional;
|
||||||
|
import org.apache.fineract.infrastructure.core.service.DateUtils;
|
||||||
|
|
||||||
@Slf4j
|
@Slf4j
|
||||||
@Service
|
@Service
|
||||||
@@ -86,11 +87,11 @@ public class CkycBatchBuilderServiceImpl implements CkycBatchBuilderService {
|
|||||||
throw new IllegalArgumentException("clientIds must not be empty");
|
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 int seq = nextBatchSequenceForToday(today);
|
||||||
final String batchId = "BATCH-" + BATCH_ID_FMT.format(today) + "-" + String.format("%03d", seq);
|
final String batchId = "BATCH-" + BATCH_ID_FMT.format(today) + "-" + String.format("%03d", seq);
|
||||||
// ZIP filename: "CERSAI-ZIP-<yyyy-MM-dd-HH-mm-ss>.zip" — hyphen-separated per spec.
|
// ZIP filename: "CERSAI-ZIP-<yyyy-MM-dd-HH-mm-ss>.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<CkycBatchManifestEntry> manifest = new ArrayList<>();
|
final List<CkycBatchManifestEntry> manifest = new ArrayList<>();
|
||||||
final ByteArrayOutputStream zipBytesOut = new ByteArrayOutputStream();
|
final ByteArrayOutputStream zipBytesOut = new ByteArrayOutputStream();
|
||||||
|
|||||||
+8
-7
@@ -26,7 +26,6 @@ import java.nio.charset.StandardCharsets;
|
|||||||
import java.time.LocalDate;
|
import java.time.LocalDate;
|
||||||
import java.time.format.DateTimeFormatter;
|
import java.time.format.DateTimeFormatter;
|
||||||
import java.util.ArrayList;
|
import java.util.ArrayList;
|
||||||
import java.util.HashMap;
|
|
||||||
import java.util.LinkedHashMap;
|
import java.util.LinkedHashMap;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
import java.util.Map;
|
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.glassfish.jersey.media.multipart.FormDataContentDisposition;
|
||||||
import org.springframework.jdbc.core.JdbcTemplate;
|
import org.springframework.jdbc.core.JdbcTemplate;
|
||||||
import org.springframework.stereotype.Service;
|
import org.springframework.stereotype.Service;
|
||||||
|
import org.apache.fineract.infrastructure.core.service.DateUtils;
|
||||||
|
|
||||||
@Slf4j
|
@Slf4j
|
||||||
@Service
|
@Service
|
||||||
@@ -219,6 +219,7 @@ public class CkycReportsReadServiceImpl implements CkycReportsReadService {
|
|||||||
// ===== Customer List =====
|
// ===== Customer List =====
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
|
@SuppressWarnings("StringSplitter")
|
||||||
public Map<String, Object> listCustomers(String name, String branch, String city, String gender, String state, String dateFrom,
|
public Map<String, Object> listCustomers(String name, String branch, String city, String gender, String state, String dateFrom,
|
||||||
String dateTo, Integer page, Integer pageSize, String sort) {
|
String dateTo, Integer page, Integer pageSize, String sort) {
|
||||||
|
|
||||||
@@ -375,13 +376,13 @@ public class CkycReportsReadServiceImpl implements CkycReportsReadService {
|
|||||||
switch (format != null ? format.toLowerCase() : "csv") {
|
switch (format != null ? format.toLowerCase() : "csv") {
|
||||||
case "txt":
|
case "txt":
|
||||||
contentType = "text/plain";
|
contentType = "text/plain";
|
||||||
filename = "ckyc_export_" + LocalDate.now() + ".txt";
|
filename = "ckyc_export_" + LocalDate.now(DateUtils.getDateTimeZoneOfTenant()) + ".txt";
|
||||||
content = buildPipeDelimitedExport(rows);
|
content = buildPipeDelimitedExport(rows);
|
||||||
break;
|
break;
|
||||||
case "csv":
|
case "csv":
|
||||||
default:
|
default:
|
||||||
contentType = "text/csv";
|
contentType = "text/csv";
|
||||||
filename = "ckyc_export_" + LocalDate.now() + ".csv";
|
filename = "ckyc_export_" + LocalDate.now(DateUtils.getDateTimeZoneOfTenant()) + ".csv";
|
||||||
content = buildCsvExport(rows);
|
content = buildCsvExport(rows);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
@@ -431,7 +432,7 @@ public class CkycReportsReadServiceImpl implements CkycReportsReadService {
|
|||||||
errors.add("Parse error: " + e.getMessage());
|
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("fileId", fileId);
|
||||||
result.put("totalRecords", totalRecords);
|
result.put("totalRecords", totalRecords);
|
||||||
result.put("customers", customers);
|
result.put("customers", customers);
|
||||||
@@ -453,9 +454,9 @@ public class CkycReportsReadServiceImpl implements CkycReportsReadService {
|
|||||||
@Override
|
@Override
|
||||||
public Response generateCkycFile(Map<String, Object> request) {
|
public Response generateCkycFile(Map<String, Object> request) {
|
||||||
// Placeholder — delegates to CkycBatchBuilderService for actual ZIP generation
|
// 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")
|
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();
|
.build();
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -572,7 +573,7 @@ public class CkycReportsReadServiceImpl implements CkycReportsReadService {
|
|||||||
|
|
||||||
private String buildPipeDelimitedExport(List<Map<String, Object>> rows) {
|
private String buildPipeDelimitedExport(List<Map<String, Object>> rows) {
|
||||||
StringBuilder sb = new StringBuilder();
|
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<String, Object> row : rows) {
|
for (Map<String, Object> row : rows) {
|
||||||
sb.append("20|");
|
sb.append("20|");
|
||||||
sb.append(val(row.get("cif"))).append("|");
|
sb.append(val(row.get("cif"))).append("|");
|
||||||
|
|||||||
+3
-2
@@ -47,6 +47,7 @@ import org.springframework.beans.factory.annotation.Value;
|
|||||||
import org.springframework.jdbc.core.JdbcTemplate;
|
import org.springframework.jdbc.core.JdbcTemplate;
|
||||||
import org.springframework.stereotype.Service;
|
import org.springframework.stereotype.Service;
|
||||||
import org.springframework.transaction.annotation.Transactional;
|
import org.springframework.transaction.annotation.Transactional;
|
||||||
|
import org.apache.fineract.infrastructure.core.service.DateUtils;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Dummy / stub implementation of {@link CkycBatchSftpUploadService}.
|
* Dummy / stub implementation of {@link CkycBatchSftpUploadService}.
|
||||||
@@ -149,10 +150,10 @@ public class DummyCkycBatchSftpUploadServiceImpl implements CkycBatchSftpUploadS
|
|||||||
}
|
}
|
||||||
|
|
||||||
// 3) Build the ACK reference and timestamp
|
// 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) + "-"
|
final String ackReference = "CERSAI-ACK-" + ACK_TS_FMT.format(now) + "-"
|
||||||
+ String.format("%04d", ACK_COUNTER.getAndIncrement());
|
+ 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
|
// 4) Parse manifest → generate a CKYC number per included client → persist on m_client_kyc
|
||||||
final List<Map<String, Object>> perClient = new ArrayList<>();
|
final List<Map<String, Object>> perClient = new ArrayList<>();
|
||||||
|
|||||||
+3
-1
@@ -18,6 +18,8 @@
|
|||||||
*/
|
*/
|
||||||
package org.apache.fineract.portfolio.client.contactverification.api;
|
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.JsonObject;
|
||||||
import com.google.gson.JsonParser;
|
import com.google.gson.JsonParser;
|
||||||
import io.swagger.v3.oas.annotations.Operation;
|
import io.swagger.v3.oas.annotations.Operation;
|
||||||
@@ -152,7 +154,7 @@ public class ClientContactVerificationApiResource {
|
|||||||
}
|
}
|
||||||
final String fwd = req.getHeader("X-Forwarded-For");
|
final String fwd = req.getHeader("X-Forwarded-For");
|
||||||
if (fwd != null && !fwd.isBlank()) {
|
if (fwd != null && !fwd.isBlank()) {
|
||||||
return fwd.split(",")[0].trim();
|
return Iterables.get(Splitter.on(',').split(fwd), 0).trim();
|
||||||
}
|
}
|
||||||
return req.getRemoteAddr();
|
return req.getRemoteAddr();
|
||||||
}
|
}
|
||||||
|
|||||||
+3
-1
@@ -18,6 +18,8 @@
|
|||||||
*/
|
*/
|
||||||
package org.apache.fineract.portfolio.client.contactverification.api;
|
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.JsonObject;
|
||||||
import com.google.gson.JsonParser;
|
import com.google.gson.JsonParser;
|
||||||
import io.swagger.v3.oas.annotations.Operation;
|
import io.swagger.v3.oas.annotations.Operation;
|
||||||
@@ -147,7 +149,7 @@ public class ClientCreationContactVerificationApiResource {
|
|||||||
}
|
}
|
||||||
final String fwd = req.getHeader("X-Forwarded-For");
|
final String fwd = req.getHeader("X-Forwarded-For");
|
||||||
if (fwd != null && !fwd.isBlank()) {
|
if (fwd != null && !fwd.isBlank()) {
|
||||||
return fwd.split(",")[0].trim();
|
return Iterables.get(Splitter.on(',').split(fwd), 0).trim();
|
||||||
}
|
}
|
||||||
return req.getRemoteAddr();
|
return req.getRemoteAddr();
|
||||||
}
|
}
|
||||||
|
|||||||
+2
-1
@@ -53,6 +53,7 @@ import org.springframework.transaction.annotation.Transactional;
|
|||||||
import org.springframework.web.client.HttpClientErrorException;
|
import org.springframework.web.client.HttpClientErrorException;
|
||||||
import org.springframework.web.client.HttpServerErrorException;
|
import org.springframework.web.client.HttpServerErrorException;
|
||||||
import org.springframework.web.client.RestTemplate;
|
import org.springframework.web.client.RestTemplate;
|
||||||
|
import org.apache.fineract.infrastructure.core.service.DateUtils;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* See {@link ClientContactOtpService}. Deliberately does NOT touch {@code LoginOtpServiceImpl} /
|
* 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));
|
log.setExpiresAt(OffsetDateTime.now(ZoneOffset.UTC).plusSeconds(ttlSeconds));
|
||||||
|
|
||||||
final String html = emailTemplateService.renderOtp(null, otp, validityMinutes);
|
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);
|
final boolean sent = emailSenderService.sendHtml(emailAddress, subject, html);
|
||||||
|
|||||||
+2
-1
@@ -34,6 +34,7 @@ import org.mapstruct.Mapper;
|
|||||||
import org.mapstruct.Mapping;
|
import org.mapstruct.Mapping;
|
||||||
import org.mapstruct.MappingTarget;
|
import org.mapstruct.MappingTarget;
|
||||||
import org.mapstruct.Named;
|
import org.mapstruct.Named;
|
||||||
|
import org.apache.fineract.infrastructure.core.service.DateUtils;
|
||||||
|
|
||||||
@Mapper(config = MapstructMapperConfig.class)
|
@Mapper(config = MapstructMapperConfig.class)
|
||||||
public interface ClientMapper {
|
public interface ClientMapper {
|
||||||
@@ -271,7 +272,7 @@ public interface ClientMapper {
|
|||||||
default void computeAge(Client source, @MappingTarget ClientData target) {
|
default void computeAge(Client source, @MappingTarget ClientData target) {
|
||||||
final LocalDate dob = source.getDateOfBirth();
|
final LocalDate dob = source.getDateOfBirth();
|
||||||
if (dob != null) {
|
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.setAgeYears(age.getYears());
|
||||||
target.setAgeMonths(age.getMonths());
|
target.setAgeMonths(age.getMonths());
|
||||||
target.setAgeDays(age.getDays());
|
target.setAgeDays(age.getDays());
|
||||||
|
|||||||
+2
-1
@@ -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.ClientRepository;
|
||||||
import org.apache.fineract.portfolio.client.domain.LegalForm;
|
import org.apache.fineract.portfolio.client.domain.LegalForm;
|
||||||
import org.springframework.stereotype.Component;
|
import org.springframework.stereotype.Component;
|
||||||
|
import org.apache.fineract.infrastructure.core.service.DateUtils;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Generates CIF numbers in the format <code>TTYYYYNNNNNN</code>:
|
* Generates CIF numbers in the format <code>TTYYYYNNNNNN</code>:
|
||||||
@@ -90,6 +91,6 @@ public class CifNumberGenerator {
|
|||||||
|
|
||||||
private int resolveYear(final Client client) {
|
private int resolveYear(final Client client) {
|
||||||
final LocalDate submittedOn = client.getSubmittedOnDate();
|
final LocalDate submittedOn = client.getSubmittedOnDate();
|
||||||
return (submittedOn != null ? submittedOn : LocalDate.now()).getYear();
|
return (submittedOn != null ? submittedOn : LocalDate.now(DateUtils.getDateTimeZoneOfTenant())).getYear();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
+2
-1
@@ -30,6 +30,7 @@ import org.slf4j.LoggerFactory;
|
|||||||
import org.springframework.beans.factory.annotation.Autowired;
|
import org.springframework.beans.factory.annotation.Autowired;
|
||||||
import org.springframework.beans.factory.annotation.Value;
|
import org.springframework.beans.factory.annotation.Value;
|
||||||
import org.springframework.stereotype.Service;
|
import org.springframework.stereotype.Service;
|
||||||
|
import org.apache.fineract.infrastructure.core.service.DateUtils;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* See {@link ClientChangeNotificationService}.
|
* See {@link ClientChangeNotificationService}.
|
||||||
@@ -88,7 +89,7 @@ public class ClientChangeNotificationServiceImpl implements ClientChangeNotifica
|
|||||||
final String alertTitle = fieldLabel + " Updated";
|
final String alertTitle = fieldLabel + " Updated";
|
||||||
final String alertMessage = "Your " + fieldLabel.toLowerCase() + " on file was changed from "
|
final String alertMessage = "Your " + fieldLabel.toLowerCase() + " on file was changed from "
|
||||||
+ describeForDisplay(fieldLabel, oldValue) + " to " + describeForDisplay(fieldLabel, newValue) + " on "
|
+ 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 html = emailTemplateService.renderAlert(recipientName, alertTitle, alertMessage);
|
||||||
final String subject = alertTitle + " - " + appName;
|
final String subject = alertTitle + " - " + appName;
|
||||||
|
|
||||||
|
|||||||
+3
-2
@@ -63,6 +63,7 @@ import org.springframework.dao.EmptyResultDataAccessException;
|
|||||||
import org.springframework.jdbc.core.JdbcTemplate;
|
import org.springframework.jdbc.core.JdbcTemplate;
|
||||||
import org.springframework.jdbc.core.RowMapper;
|
import org.springframework.jdbc.core.RowMapper;
|
||||||
import org.springframework.stereotype.Service;
|
import org.springframework.stereotype.Service;
|
||||||
|
import org.apache.fineract.infrastructure.core.service.DateUtils;
|
||||||
|
|
||||||
@Service
|
@Service
|
||||||
@RequiredArgsConstructor
|
@RequiredArgsConstructor
|
||||||
@@ -488,7 +489,7 @@ public class ClientReadPlatformServiceImpl implements ClientReadPlatformService
|
|||||||
Integer ageMonths1 = null;
|
Integer ageMonths1 = null;
|
||||||
Integer ageDays1 = null;
|
Integer ageDays1 = null;
|
||||||
if (dateOfBirth != 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();
|
ageYears1 = age.getYears();
|
||||||
ageMonths1 = age.getMonths();
|
ageMonths1 = age.getMonths();
|
||||||
ageDays1 = age.getDays();
|
ageDays1 = age.getDays();
|
||||||
@@ -879,7 +880,7 @@ public class ClientReadPlatformServiceImpl implements ClientReadPlatformService
|
|||||||
Integer ageMonths = null;
|
Integer ageMonths = null;
|
||||||
Integer ageDays = null;
|
Integer ageDays = null;
|
||||||
if (dateOfBirth != 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();
|
ageYears = age.getYears();
|
||||||
ageMonths = age.getMonths();
|
ageMonths = age.getMonths();
|
||||||
ageDays = age.getDays();
|
ageDays = age.getDays();
|
||||||
|
|||||||
+1
@@ -1786,6 +1786,7 @@ public class ClientWritePlatformServiceJpaRepositoryImpl implements ClientWriteP
|
|||||||
* verifying KYC names against ID documents). Null / blank → null so we don't accidentally
|
* verifying KYC names against ID documents). Null / blank → null so we don't accidentally
|
||||||
* persist an empty string in place of an unset field.
|
* persist an empty string in place of an unset field.
|
||||||
*/
|
*/
|
||||||
|
@SuppressWarnings("StringSplitter")
|
||||||
private static String toTitleCase(final String raw) {
|
private static String toTitleCase(final String raw) {
|
||||||
if (raw == null) {
|
if (raw == null) {
|
||||||
return null;
|
return null;
|
||||||
|
|||||||
-15
@@ -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). */
|
/** 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) {
|
private String maskAccountNumber(final String accountNumber) {
|
||||||
if (accountNumber == null || accountNumber.isBlank()) {
|
if (accountNumber == null || accountNumber.isBlank()) {
|
||||||
|
|||||||
+2
-1
@@ -26,6 +26,7 @@ import org.apache.fineract.portfolio.denominationmaster.domain.DenominationMaste
|
|||||||
import org.apache.fineract.portfolio.denominationmaster.domain.DenominationMasterRepository;
|
import org.apache.fineract.portfolio.denominationmaster.domain.DenominationMasterRepository;
|
||||||
import org.apache.fineract.useradministration.domain.AppUser;
|
import org.apache.fineract.useradministration.domain.AppUser;
|
||||||
import org.springframework.stereotype.Component;
|
import org.springframework.stereotype.Component;
|
||||||
|
import org.apache.fineract.infrastructure.core.service.DateUtils;
|
||||||
|
|
||||||
@Path("/v1/denominationmaster")
|
@Path("/v1/denominationmaster")
|
||||||
@Component
|
@Component
|
||||||
@@ -105,7 +106,7 @@ public class DenominationMasterApiResource {
|
|||||||
writeAudit("ACTIVATE", dm, null);
|
writeAudit("ACTIVATE", dm, null);
|
||||||
} else if ("deactivate".equals(command)) {
|
} else if ("deactivate".equals(command)) {
|
||||||
dm.setIsActive(false);
|
dm.setIsActive(false);
|
||||||
dm.setDiscontinuedOn(LocalDate.now());
|
dm.setDiscontinuedOn(LocalDate.now(DateUtils.getDateTimeZoneOfTenant()));
|
||||||
repository.save(dm);
|
repository.save(dm);
|
||||||
writeAudit("DEACTIVATE", dm, null);
|
writeAudit("DEACTIVATE", dm, null);
|
||||||
} else if ("restore".equals(command)) {
|
} else if ("restore".equals(command)) {
|
||||||
|
|||||||
+2
-1
@@ -15,6 +15,7 @@ import java.time.LocalDateTime;
|
|||||||
import lombok.Getter;
|
import lombok.Getter;
|
||||||
import lombok.NoArgsConstructor;
|
import lombok.NoArgsConstructor;
|
||||||
import lombok.Setter;
|
import lombok.Setter;
|
||||||
|
import org.apache.fineract.infrastructure.core.service.DateUtils;
|
||||||
|
|
||||||
@Entity
|
@Entity
|
||||||
@Table(name = "m_denomination_master_audit")
|
@Table(name = "m_denomination_master_audit")
|
||||||
@@ -77,7 +78,7 @@ public class DenominationMasterAudit {
|
|||||||
a.changes = changes;
|
a.changes = changes;
|
||||||
a.performedBy = performedBy;
|
a.performedBy = performedBy;
|
||||||
a.performedByUsername = performedByUsername;
|
a.performedByUsername = performedByUsername;
|
||||||
a.performedOn = LocalDateTime.now();
|
a.performedOn = LocalDateTime.now(DateUtils.getDateTimeZoneOfTenant());
|
||||||
return a;
|
return a;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
+4
-3
@@ -26,6 +26,7 @@ import org.apache.fineract.portfolio.denominationmaster.domain.SavingsTxnDenomin
|
|||||||
import org.apache.fineract.useradministration.domain.AppUser;
|
import org.apache.fineract.useradministration.domain.AppUser;
|
||||||
import org.springframework.jdbc.core.JdbcTemplate;
|
import org.springframework.jdbc.core.JdbcTemplate;
|
||||||
import org.springframework.stereotype.Service;
|
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
|
* Validates and persists the per-transaction cash denomination breakdown sent by the UI
|
||||||
@@ -163,7 +164,7 @@ public class DenominationBreakdownWriter {
|
|||||||
}
|
}
|
||||||
if (cashierId == null) return;
|
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 "
|
final String sql = "SELECT COUNT(*) FROM m_cash_transfer ct "
|
||||||
+ "WHERE ct.to_cashier_id = ? "
|
+ "WHERE ct.to_cashier_id = ? "
|
||||||
+ " AND ct.transfer_date < CAST(? AS DATE) "
|
+ " AND ct.transfer_date < CAST(? AS DATE) "
|
||||||
@@ -203,7 +204,7 @@ public class DenominationBreakdownWriter {
|
|||||||
}
|
}
|
||||||
if (cashierId == null) return;
|
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 "
|
final String sql = "SELECT COUNT(*) FROM m_cash_transfer ct "
|
||||||
+ "WHERE ct.to_cashier_id = ? "
|
+ "WHERE ct.to_cashier_id = ? "
|
||||||
+ " AND ct.transfer_date = CAST(? AS DATE) "
|
+ " AND ct.transfer_date = CAST(? AS DATE) "
|
||||||
@@ -511,7 +512,7 @@ public class DenominationBreakdownWriter {
|
|||||||
.count(count)
|
.count(count)
|
||||||
.totalAmount(lineTotal)
|
.totalAmount(lineTotal)
|
||||||
.txnDate(txnDate)
|
.txnDate(txnDate)
|
||||||
.createdAt(LocalDateTime.now())
|
.createdAt(LocalDateTime.now(DateUtils.getDateTimeZoneOfTenant()))
|
||||||
.txnType(resolvedTxnType)
|
.txnType(resolvedTxnType)
|
||||||
.officerId(officerId)
|
.officerId(officerId)
|
||||||
.officerUsername(officerUsername)
|
.officerUsername(officerUsername)
|
||||||
|
|||||||
+8
-1
@@ -1,6 +1,13 @@
|
|||||||
package org.apache.fineract.portfolio.election.api;
|
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.MediaType;
|
||||||
import jakarta.ws.rs.core.Response;
|
import jakarta.ws.rs.core.Response;
|
||||||
import lombok.RequiredArgsConstructor;
|
import lombok.RequiredArgsConstructor;
|
||||||
|
|||||||
+12
-2
@@ -3,7 +3,17 @@ package org.apache.fineract.portfolio.election.api;
|
|||||||
import io.swagger.v3.oas.annotations.Operation;
|
import io.swagger.v3.oas.annotations.Operation;
|
||||||
import io.swagger.v3.oas.annotations.tags.Tag;
|
import io.swagger.v3.oas.annotations.tags.Tag;
|
||||||
import jakarta.servlet.http.HttpServletRequest;
|
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.Context;
|
||||||
import jakarta.ws.rs.core.MediaType;
|
import jakarta.ws.rs.core.MediaType;
|
||||||
import jakarta.ws.rs.core.Response;
|
import jakarta.ws.rs.core.Response;
|
||||||
@@ -138,6 +148,6 @@ public class CommitteeMeetingApiResource {
|
|||||||
|
|
||||||
private String clientIp(HttpServletRequest req) {
|
private String clientIp(HttpServletRequest req) {
|
||||||
String ip = req.getHeader("X-Forwarded-For");
|
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();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
+13
-2
@@ -4,7 +4,18 @@ import io.swagger.v3.oas.annotations.Operation;
|
|||||||
import io.swagger.v3.oas.annotations.tags.Tag;
|
import io.swagger.v3.oas.annotations.tags.Tag;
|
||||||
import jakarta.servlet.http.HttpServletRequest;
|
import jakarta.servlet.http.HttpServletRequest;
|
||||||
import jakarta.validation.Valid;
|
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.Context;
|
||||||
import jakarta.ws.rs.core.MediaType;
|
import jakarta.ws.rs.core.MediaType;
|
||||||
import jakarta.ws.rs.core.Response;
|
import jakarta.ws.rs.core.Response;
|
||||||
@@ -125,6 +136,6 @@ public class DirectorAppointmentApiResource {
|
|||||||
|
|
||||||
private String clientIp(HttpServletRequest req) {
|
private String clientIp(HttpServletRequest req) {
|
||||||
String ip = req.getHeader("X-Forwarded-For");
|
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();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
+6
-2
@@ -15,6 +15,8 @@ import jakarta.ws.rs.QueryParam;
|
|||||||
import jakarta.ws.rs.core.Context;
|
import jakarta.ws.rs.core.Context;
|
||||||
import jakarta.ws.rs.core.MediaType;
|
import jakarta.ws.rs.core.MediaType;
|
||||||
import jakarta.ws.rs.core.Response;
|
import jakarta.ws.rs.core.Response;
|
||||||
|
import com.google.common.base.Splitter;
|
||||||
|
import com.google.common.collect.Iterables;
|
||||||
import lombok.RequiredArgsConstructor;
|
import lombok.RequiredArgsConstructor;
|
||||||
import org.apache.fineract.infrastructure.contentstore.service.ContentStoreService;
|
import org.apache.fineract.infrastructure.contentstore.service.ContentStoreService;
|
||||||
import org.apache.fineract.infrastructure.security.service.PlatformSecurityContext;
|
import org.apache.fineract.infrastructure.security.service.PlatformSecurityContext;
|
||||||
@@ -123,7 +125,9 @@ public class ElectionCandidateApiResource {
|
|||||||
if (existing != null && !existing.startsWith("data:") && existing.contains("|")) {
|
if (existing != null && !existing.startsWith("data:") && existing.contains("|")) {
|
||||||
String[] ep = existing.split("\\|", 2);
|
String[] ep = existing.split("\\|", 2);
|
||||||
if (ep.length == 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) {
|
private static String clientIp(HttpServletRequest req) {
|
||||||
if (req == null) return null;
|
if (req == null) return null;
|
||||||
String fwd = req.getHeader("X-Forwarded-For");
|
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();
|
return req.getRemoteAddr();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
+6
-3
@@ -5,7 +5,6 @@ import io.swagger.v3.oas.annotations.Operation;
|
|||||||
import io.swagger.v3.oas.annotations.tags.Tag;
|
import io.swagger.v3.oas.annotations.tags.Tag;
|
||||||
import jakarta.servlet.http.HttpServletRequest;
|
import jakarta.servlet.http.HttpServletRequest;
|
||||||
import jakarta.ws.rs.Consumes;
|
import jakarta.ws.rs.Consumes;
|
||||||
import jakarta.ws.rs.DELETE;
|
|
||||||
import jakarta.ws.rs.GET;
|
import jakarta.ws.rs.GET;
|
||||||
import jakarta.ws.rs.POST;
|
import jakarta.ws.rs.POST;
|
||||||
import jakarta.ws.rs.PUT;
|
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.Context;
|
||||||
import jakarta.ws.rs.core.MediaType;
|
import jakarta.ws.rs.core.MediaType;
|
||||||
import jakarta.ws.rs.core.Response;
|
import jakarta.ws.rs.core.Response;
|
||||||
|
import com.google.common.base.Splitter;
|
||||||
|
import com.google.common.collect.Iterables;
|
||||||
import lombok.RequiredArgsConstructor;
|
import lombok.RequiredArgsConstructor;
|
||||||
import org.apache.fineract.portfolio.election.data.ElectionConfigData;
|
import org.apache.fineract.portfolio.election.data.ElectionConfigData;
|
||||||
import org.apache.fineract.portfolio.election.data.ElectionConfigRequest;
|
import org.apache.fineract.portfolio.election.data.ElectionConfigRequest;
|
||||||
@@ -89,7 +90,9 @@ public class ElectionConfigApiResource {
|
|||||||
throw e;
|
throw e;
|
||||||
}
|
}
|
||||||
String updateDetails = null;
|
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,
|
electionAuditService.log(ElectionAuditAction.UPDATE_ELECTION, "ELECTION", electionId, electionId,
|
||||||
"Election updated: " + request.getTitle(), updateDetails, clientIp(httpRequest));
|
"Election updated: " + request.getTitle(), updateDetails, clientIp(httpRequest));
|
||||||
return Response.ok(Map.of("resourceId", electionId)).build();
|
return Response.ok(Map.of("resourceId", electionId)).build();
|
||||||
@@ -214,7 +217,7 @@ public class ElectionConfigApiResource {
|
|||||||
private static String clientIp(HttpServletRequest req) {
|
private static String clientIp(HttpServletRequest req) {
|
||||||
if (req == null) return null;
|
if (req == null) return null;
|
||||||
String fwd = req.getHeader("X-Forwarded-For");
|
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();
|
return req.getRemoteAddr();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
+3
-1
@@ -15,6 +15,8 @@ import jakarta.ws.rs.core.MediaType;
|
|||||||
import jakarta.ws.rs.core.Response;
|
import jakarta.ws.rs.core.Response;
|
||||||
import lombok.RequiredArgsConstructor;
|
import lombok.RequiredArgsConstructor;
|
||||||
import org.apache.fineract.portfolio.election.data.ElectionApprovalActionRequest;
|
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.ElectionApprovalStepData;
|
||||||
import org.apache.fineract.portfolio.election.data.ElectionNominationData;
|
import org.apache.fineract.portfolio.election.data.ElectionNominationData;
|
||||||
import org.apache.fineract.portfolio.election.data.ElectionNominationRequest;
|
import org.apache.fineract.portfolio.election.data.ElectionNominationRequest;
|
||||||
@@ -295,7 +297,7 @@ public class ElectionNominationApiResource {
|
|||||||
private static String clientIp(HttpServletRequest req) {
|
private static String clientIp(HttpServletRequest req) {
|
||||||
if (req == null) return null;
|
if (req == null) return null;
|
||||||
String fwd = req.getHeader("X-Forwarded-For");
|
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();
|
return req.getRemoteAddr();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
+5
-3
@@ -15,6 +15,8 @@ import jakarta.ws.rs.GET;
|
|||||||
import jakarta.ws.rs.POST;
|
import jakarta.ws.rs.POST;
|
||||||
import jakarta.ws.rs.Path;
|
import jakarta.ws.rs.Path;
|
||||||
import jakarta.ws.rs.PathParam;
|
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.Produces;
|
||||||
import jakarta.ws.rs.core.Context;
|
import jakarta.ws.rs.core.Context;
|
||||||
import jakarta.ws.rs.core.MediaType;
|
import jakarta.ws.rs.core.MediaType;
|
||||||
@@ -104,10 +106,10 @@ public class ElectionVotingApiResource {
|
|||||||
}
|
}
|
||||||
winDet.append("]");
|
winDet.append("]");
|
||||||
String declareDetails = wFirst ? null : winDet.toString();
|
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()))
|
.filter(r -> Integer.valueOf(1).equals(r.getRankPosition()) || "WON".equalsIgnoreCase(r.getResult()))
|
||||||
.map(r -> r.getCandidateName() + " won " + r.getPostName())
|
.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,
|
electionAuditService.log(ElectionAuditAction.DECLARE_RESULTS, "RESULT", electionId, electionId,
|
||||||
declareDesc, declareDetails, clientIp(httpRequest));
|
declareDesc, declareDetails, clientIp(httpRequest));
|
||||||
return Response.ok(results).build();
|
return Response.ok(results).build();
|
||||||
@@ -127,7 +129,7 @@ public class ElectionVotingApiResource {
|
|||||||
private static String clientIp(HttpServletRequest req) {
|
private static String clientIp(HttpServletRequest req) {
|
||||||
if (req == null) return null;
|
if (req == null) return null;
|
||||||
String fwd = req.getHeader("X-Forwarded-For");
|
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();
|
return req.getRemoteAddr();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
+6
-1
@@ -2,7 +2,12 @@ package org.apache.fineract.portfolio.election.api;
|
|||||||
|
|
||||||
import io.swagger.v3.oas.annotations.Operation;
|
import io.swagger.v3.oas.annotations.Operation;
|
||||||
import io.swagger.v3.oas.annotations.tags.Tag;
|
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.MediaType;
|
||||||
import jakarta.ws.rs.core.Response;
|
import jakarta.ws.rs.core.Response;
|
||||||
import lombok.RequiredArgsConstructor;
|
import lombok.RequiredArgsConstructor;
|
||||||
|
|||||||
+7
-1
@@ -2,7 +2,13 @@ package org.apache.fineract.portfolio.election.api;
|
|||||||
|
|
||||||
import io.swagger.v3.oas.annotations.Operation;
|
import io.swagger.v3.oas.annotations.Operation;
|
||||||
import io.swagger.v3.oas.annotations.tags.Tag;
|
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.MediaType;
|
||||||
import jakarta.ws.rs.core.Response;
|
import jakarta.ws.rs.core.Response;
|
||||||
import lombok.RequiredArgsConstructor;
|
import lombok.RequiredArgsConstructor;
|
||||||
|
|||||||
+8
-1
@@ -1,6 +1,13 @@
|
|||||||
package org.apache.fineract.portfolio.election.domain;
|
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.Getter;
|
||||||
import lombok.NoArgsConstructor;
|
import lombok.NoArgsConstructor;
|
||||||
import lombok.Setter;
|
import lombok.Setter;
|
||||||
|
|||||||
+8
-1
@@ -1,6 +1,13 @@
|
|||||||
package org.apache.fineract.portfolio.election.domain;
|
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.Getter;
|
||||||
import lombok.NoArgsConstructor;
|
import lombok.NoArgsConstructor;
|
||||||
import lombok.Setter;
|
import lombok.Setter;
|
||||||
|
|||||||
+9
-1
@@ -1,6 +1,14 @@
|
|||||||
package org.apache.fineract.portfolio.election.domain;
|
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.Getter;
|
||||||
import lombok.NoArgsConstructor;
|
import lombok.NoArgsConstructor;
|
||||||
import lombok.Setter;
|
import lombok.Setter;
|
||||||
|
|||||||
+1
-1
@@ -26,7 +26,7 @@ public class CommitteeMember {
|
|||||||
private Long directorAppointmentId;
|
private Long directorAppointmentId;
|
||||||
|
|
||||||
@Column(name = "added_date", nullable = false)
|
@Column(name = "added_date", nullable = false)
|
||||||
private LocalDate addedDate = LocalDate.now();
|
private LocalDate addedDate;
|
||||||
|
|
||||||
public static CommitteeMember create(Committee committee, Long directorAppointmentId) {
|
public static CommitteeMember create(Committee committee, Long directorAppointmentId) {
|
||||||
CommitteeMember m = new CommitteeMember();
|
CommitteeMember m = new CommitteeMember();
|
||||||
|
|||||||
+10
-3
@@ -1,6 +1,12 @@
|
|||||||
package org.apache.fineract.portfolio.election.domain;
|
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.Getter;
|
||||||
import lombok.NoArgsConstructor;
|
import lombok.NoArgsConstructor;
|
||||||
import lombok.Setter;
|
import lombok.Setter;
|
||||||
@@ -8,6 +14,7 @@ import org.apache.fineract.infrastructure.core.domain.AbstractPersistableCustom;
|
|||||||
|
|
||||||
import java.time.LocalDate;
|
import java.time.LocalDate;
|
||||||
import java.time.LocalDateTime;
|
import java.time.LocalDateTime;
|
||||||
|
import org.apache.fineract.infrastructure.core.service.DateUtils;
|
||||||
|
|
||||||
@Entity
|
@Entity
|
||||||
@Table(name = "m_election_director_appointment")
|
@Table(name = "m_election_director_appointment")
|
||||||
@@ -58,12 +65,12 @@ public class DirectorAppointment extends AbstractPersistableCustom<Long> {
|
|||||||
|
|
||||||
@PrePersist
|
@PrePersist
|
||||||
void onPersist() {
|
void onPersist() {
|
||||||
this.createdDate = LocalDateTime.now();
|
this.createdDate = LocalDateTime.now(DateUtils.getDateTimeZoneOfTenant());
|
||||||
}
|
}
|
||||||
|
|
||||||
@PreUpdate
|
@PreUpdate
|
||||||
void onUpdate() {
|
void onUpdate() {
|
||||||
this.lastModifiedDate = LocalDateTime.now();
|
this.lastModifiedDate = LocalDateTime.now(DateUtils.getDateTimeZoneOfTenant());
|
||||||
}
|
}
|
||||||
|
|
||||||
public static DirectorAppointment create(Long electionId, Long candidateId,
|
public static DirectorAppointment create(Long electionId, Long candidateId,
|
||||||
|
|||||||
+1
@@ -14,6 +14,7 @@ import java.util.List;
|
|||||||
@Repository
|
@Repository
|
||||||
public interface DirectorAppointmentRepository extends JpaRepository<DirectorAppointment, Long> {
|
public interface DirectorAppointmentRepository extends JpaRepository<DirectorAppointment, Long> {
|
||||||
|
|
||||||
|
@Override
|
||||||
Page<DirectorAppointment> findAll(Pageable pageable);
|
Page<DirectorAppointment> findAll(Pageable pageable);
|
||||||
|
|
||||||
Page<DirectorAppointment> findByStatus(DirectorAppointmentStatus status, Pageable pageable);
|
Page<DirectorAppointment> findByStatus(DirectorAppointmentStatus status, Pageable pageable);
|
||||||
|
|||||||
+11
-3
@@ -1,12 +1,20 @@
|
|||||||
package org.apache.fineract.portfolio.election.domain;
|
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.Getter;
|
||||||
import lombok.NoArgsConstructor;
|
import lombok.NoArgsConstructor;
|
||||||
import lombok.Setter;
|
import lombok.Setter;
|
||||||
import org.apache.fineract.infrastructure.core.domain.AbstractPersistableCustom;
|
import org.apache.fineract.infrastructure.core.domain.AbstractPersistableCustom;
|
||||||
|
|
||||||
import java.time.LocalDateTime;
|
import java.time.LocalDateTime;
|
||||||
|
import org.apache.fineract.infrastructure.core.service.DateUtils;
|
||||||
|
|
||||||
@Entity
|
@Entity
|
||||||
@Table(name = "m_election_approval_step")
|
@Table(name = "m_election_approval_step")
|
||||||
@@ -63,7 +71,7 @@ public class ElectionApprovalStep extends AbstractPersistableCustom<Long> {
|
|||||||
this.approverUserId = approverUserId;
|
this.approverUserId = approverUserId;
|
||||||
this.status = ApprovalStepStatus.APPROVED;
|
this.status = ApprovalStepStatus.APPROVED;
|
||||||
this.remarks = remarks;
|
this.remarks = remarks;
|
||||||
this.actionDate = LocalDateTime.now();
|
this.actionDate = LocalDateTime.now(DateUtils.getDateTimeZoneOfTenant());
|
||||||
this.familyDetailsVerified = familyVerified;
|
this.familyDetailsVerified = familyVerified;
|
||||||
this.familyDetailsJson = familyJson;
|
this.familyDetailsJson = familyJson;
|
||||||
}
|
}
|
||||||
@@ -72,6 +80,6 @@ public class ElectionApprovalStep extends AbstractPersistableCustom<Long> {
|
|||||||
this.approverUserId = approverUserId;
|
this.approverUserId = approverUserId;
|
||||||
this.status = ApprovalStepStatus.REJECTED;
|
this.status = ApprovalStepStatus.REJECTED;
|
||||||
this.remarks = remarks;
|
this.remarks = remarks;
|
||||||
this.actionDate = LocalDateTime.now();
|
this.actionDate = LocalDateTime.now(DateUtils.getDateTimeZoneOfTenant());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
+2
-1
@@ -14,6 +14,7 @@ import lombok.NoArgsConstructor;
|
|||||||
import lombok.Setter;
|
import lombok.Setter;
|
||||||
|
|
||||||
import java.time.LocalDateTime;
|
import java.time.LocalDateTime;
|
||||||
|
import org.apache.fineract.infrastructure.core.service.DateUtils;
|
||||||
|
|
||||||
@Entity
|
@Entity
|
||||||
@Table(name = "m_election_audit_log")
|
@Table(name = "m_election_audit_log")
|
||||||
@@ -63,6 +64,6 @@ public class ElectionAuditLog {
|
|||||||
|
|
||||||
@PrePersist
|
@PrePersist
|
||||||
void prePersist() {
|
void prePersist() {
|
||||||
if (createdAt == null) createdAt = LocalDateTime.now();
|
if (createdAt == null) createdAt = LocalDateTime.now(DateUtils.getDateTimeZoneOfTenant());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
+9
-2
@@ -1,12 +1,19 @@
|
|||||||
package org.apache.fineract.portfolio.election.domain;
|
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.Getter;
|
||||||
import lombok.NoArgsConstructor;
|
import lombok.NoArgsConstructor;
|
||||||
import lombok.Setter;
|
import lombok.Setter;
|
||||||
import org.apache.fineract.infrastructure.core.domain.AbstractPersistableCustom;
|
import org.apache.fineract.infrastructure.core.domain.AbstractPersistableCustom;
|
||||||
|
|
||||||
import java.time.LocalDateTime;
|
import java.time.LocalDateTime;
|
||||||
|
import org.apache.fineract.infrastructure.core.service.DateUtils;
|
||||||
|
|
||||||
@Entity
|
@Entity
|
||||||
@Table(name = "m_election_candidate")
|
@Table(name = "m_election_candidate")
|
||||||
@@ -67,7 +74,7 @@ public class ElectionCandidate extends AbstractPersistableCustom<Long> {
|
|||||||
candidate.candidateName = candidateName;
|
candidate.candidateName = candidateName;
|
||||||
candidate.serialNumber = serialNumber;
|
candidate.serialNumber = serialNumber;
|
||||||
candidate.approvedBy = approvedBy;
|
candidate.approvedBy = approvedBy;
|
||||||
candidate.approvedDate = LocalDateTime.now();
|
candidate.approvedDate = LocalDateTime.now(DateUtils.getDateTimeZoneOfTenant());
|
||||||
candidate.isActive = true;
|
candidate.isActive = true;
|
||||||
return candidate;
|
return candidate;
|
||||||
}
|
}
|
||||||
|
|||||||
+11
-3
@@ -1,6 +1,13 @@
|
|||||||
package org.apache.fineract.portfolio.election.domain;
|
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.Getter;
|
||||||
import lombok.NoArgsConstructor;
|
import lombok.NoArgsConstructor;
|
||||||
import lombok.Setter;
|
import lombok.Setter;
|
||||||
@@ -8,6 +15,7 @@ import org.apache.fineract.infrastructure.core.domain.AbstractPersistableCustom;
|
|||||||
|
|
||||||
import java.math.BigDecimal;
|
import java.math.BigDecimal;
|
||||||
import java.time.LocalDateTime;
|
import java.time.LocalDateTime;
|
||||||
|
import org.apache.fineract.infrastructure.core.service.DateUtils;
|
||||||
|
|
||||||
@Entity
|
@Entity
|
||||||
@Table(name = "m_election_ceo_precheck")
|
@Table(name = "m_election_ceo_precheck")
|
||||||
@@ -152,13 +160,13 @@ public class ElectionCeoPrecheck extends AbstractPersistableCustom<Long> {
|
|||||||
|
|
||||||
public void generateNoDueCertificate(String certificateNumber) {
|
public void generateNoDueCertificate(String certificateNumber) {
|
||||||
this.noDueCertificateNumber = certificateNumber;
|
this.noDueCertificateNumber = certificateNumber;
|
||||||
this.noDueGeneratedDate = LocalDateTime.now();
|
this.noDueGeneratedDate = LocalDateTime.now(DateUtils.getDateTimeZoneOfTenant());
|
||||||
this.noDueCheckResult = CheckResult.PASS;
|
this.noDueCheckResult = CheckResult.PASS;
|
||||||
}
|
}
|
||||||
|
|
||||||
public void finalise(Long checkedBy, String remarks) {
|
public void finalise(Long checkedBy, String remarks) {
|
||||||
this.checkedBy = checkedBy;
|
this.checkedBy = checkedBy;
|
||||||
this.checkedDate = LocalDateTime.now();
|
this.checkedDate = LocalDateTime.now(DateUtils.getDateTimeZoneOfTenant());
|
||||||
this.remarks = remarks;
|
this.remarks = remarks;
|
||||||
// NDC is generated manually after pre-check; only automated checks determine overall result
|
// NDC is generated manually after pre-check; only automated checks determine overall result
|
||||||
boolean autoChecksPass = directorLoanCheckResult == CheckResult.PASS
|
boolean autoChecksPass = directorLoanCheckResult == CheckResult.PASS
|
||||||
|
|||||||
+10
-2
@@ -1,6 +1,13 @@
|
|||||||
package org.apache.fineract.portfolio.election.domain;
|
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.Getter;
|
||||||
import lombok.NoArgsConstructor;
|
import lombok.NoArgsConstructor;
|
||||||
import lombok.Setter;
|
import lombok.Setter;
|
||||||
@@ -9,6 +16,7 @@ import org.apache.fineract.infrastructure.core.domain.AbstractAuditableWithUTCDa
|
|||||||
import java.time.LocalDate;
|
import java.time.LocalDate;
|
||||||
import java.util.ArrayList;
|
import java.util.ArrayList;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
|
import org.apache.fineract.infrastructure.core.service.DateUtils;
|
||||||
|
|
||||||
@Entity
|
@Entity
|
||||||
@Table(name = "m_election_config")
|
@Table(name = "m_election_config")
|
||||||
@@ -78,7 +86,7 @@ public class ElectionConfig extends AbstractAuditableWithUTCDateTimeCustom<Long>
|
|||||||
}
|
}
|
||||||
|
|
||||||
public boolean isNominationOpen() {
|
public boolean isNominationOpen() {
|
||||||
LocalDate today = LocalDate.now();
|
LocalDate today = LocalDate.now(DateUtils.getDateTimeZoneOfTenant());
|
||||||
return status == ElectionStatus.ACTIVE
|
return status == ElectionStatus.ACTIVE
|
||||||
&& !today.isBefore(nominationStartDate)
|
&& !today.isBefore(nominationStartDate)
|
||||||
&& !today.isAfter(nominationEndDate);
|
&& !today.isAfter(nominationEndDate);
|
||||||
|
|||||||
+10
-2
@@ -1,12 +1,20 @@
|
|||||||
package org.apache.fineract.portfolio.election.domain;
|
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.Getter;
|
||||||
import lombok.NoArgsConstructor;
|
import lombok.NoArgsConstructor;
|
||||||
import lombok.Setter;
|
import lombok.Setter;
|
||||||
import org.apache.fineract.infrastructure.core.domain.AbstractPersistableCustom;
|
import org.apache.fineract.infrastructure.core.domain.AbstractPersistableCustom;
|
||||||
|
|
||||||
import java.time.LocalDateTime;
|
import java.time.LocalDateTime;
|
||||||
|
import org.apache.fineract.infrastructure.core.service.DateUtils;
|
||||||
|
|
||||||
@Entity
|
@Entity
|
||||||
@Table(name = "m_election_eligibility_check")
|
@Table(name = "m_election_eligibility_check")
|
||||||
@@ -71,7 +79,7 @@ public class ElectionEligibilityCheck extends AbstractPersistableCustom<Long> {
|
|||||||
|
|
||||||
public void complete(Long checkedBy, String remarks, boolean passed) {
|
public void complete(Long checkedBy, String remarks, boolean passed) {
|
||||||
this.checkedBy = checkedBy;
|
this.checkedBy = checkedBy;
|
||||||
this.checkedDate = LocalDateTime.now();
|
this.checkedDate = LocalDateTime.now(DateUtils.getDateTimeZoneOfTenant());
|
||||||
this.remarks = remarks;
|
this.remarks = remarks;
|
||||||
this.overallResult = passed ? CheckResult.PASS : CheckResult.FAIL;
|
this.overallResult = passed ? CheckResult.PASS : CheckResult.FAIL;
|
||||||
this.ageEligible = passed;
|
this.ageEligible = passed;
|
||||||
|
|||||||
+13
-2
@@ -1,6 +1,16 @@
|
|||||||
package org.apache.fineract.portfolio.election.domain;
|
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.Getter;
|
||||||
import lombok.NoArgsConstructor;
|
import lombok.NoArgsConstructor;
|
||||||
import lombok.Setter;
|
import lombok.Setter;
|
||||||
@@ -10,6 +20,7 @@ import java.time.LocalDate;
|
|||||||
import java.time.LocalDateTime;
|
import java.time.LocalDateTime;
|
||||||
import java.util.ArrayList;
|
import java.util.ArrayList;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
|
import org.apache.fineract.infrastructure.core.service.DateUtils;
|
||||||
|
|
||||||
@Entity
|
@Entity
|
||||||
@Table(name = "m_election_nomination",
|
@Table(name = "m_election_nomination",
|
||||||
@@ -121,7 +132,7 @@ public class ElectionNomination extends AbstractAuditableWithUTCDateTimeCustom<L
|
|||||||
public void submit(String applicationNumber) {
|
public void submit(String applicationNumber) {
|
||||||
this.applicationNumber = applicationNumber;
|
this.applicationNumber = applicationNumber;
|
||||||
this.status = NominationStatus.SUBMITTED;
|
this.status = NominationStatus.SUBMITTED;
|
||||||
this.submittedDate = LocalDateTime.now();
|
this.submittedDate = LocalDateTime.now(DateUtils.getDateTimeZoneOfTenant());
|
||||||
}
|
}
|
||||||
|
|
||||||
public void markUnderReview() {
|
public void markUnderReview() {
|
||||||
|
|||||||
+6
-1
@@ -1,6 +1,11 @@
|
|||||||
package org.apache.fineract.portfolio.election.domain;
|
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 lombok.Getter;
|
import lombok.Getter;
|
||||||
import lombok.NoArgsConstructor;
|
import lombok.NoArgsConstructor;
|
||||||
import lombok.Setter;
|
import lombok.Setter;
|
||||||
|
|||||||
+8
-2
@@ -1,12 +1,18 @@
|
|||||||
package org.apache.fineract.portfolio.election.domain;
|
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 lombok.Getter;
|
import lombok.Getter;
|
||||||
import lombok.NoArgsConstructor;
|
import lombok.NoArgsConstructor;
|
||||||
import lombok.Setter;
|
import lombok.Setter;
|
||||||
import org.apache.fineract.infrastructure.core.domain.AbstractPersistableCustom;
|
import org.apache.fineract.infrastructure.core.domain.AbstractPersistableCustom;
|
||||||
|
|
||||||
import java.time.LocalDateTime;
|
import java.time.LocalDateTime;
|
||||||
|
import org.apache.fineract.infrastructure.core.service.DateUtils;
|
||||||
|
|
||||||
@Entity
|
@Entity
|
||||||
@Table(name = "m_election_result")
|
@Table(name = "m_election_result")
|
||||||
@@ -53,7 +59,7 @@ public class ElectionResult extends AbstractPersistableCustom<Long> {
|
|||||||
r.result = result;
|
r.result = result;
|
||||||
r.rankPosition = rankPosition;
|
r.rankPosition = rankPosition;
|
||||||
r.declaredBy = declaredBy;
|
r.declaredBy = declaredBy;
|
||||||
r.declaredDate = LocalDateTime.now();
|
r.declaredDate = LocalDateTime.now(DateUtils.getDateTimeZoneOfTenant());
|
||||||
return r;
|
return r;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
+9
-2
@@ -1,12 +1,19 @@
|
|||||||
package org.apache.fineract.portfolio.election.domain;
|
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.Getter;
|
||||||
import lombok.NoArgsConstructor;
|
import lombok.NoArgsConstructor;
|
||||||
import lombok.Setter;
|
import lombok.Setter;
|
||||||
import org.apache.fineract.infrastructure.core.domain.AbstractPersistableCustom;
|
import org.apache.fineract.infrastructure.core.domain.AbstractPersistableCustom;
|
||||||
|
|
||||||
import java.time.LocalDateTime;
|
import java.time.LocalDateTime;
|
||||||
|
import org.apache.fineract.infrastructure.core.service.DateUtils;
|
||||||
|
|
||||||
@Entity
|
@Entity
|
||||||
@Table(name = "m_election_vote",
|
@Table(name = "m_election_vote",
|
||||||
@@ -50,7 +57,7 @@ public class ElectionVote extends AbstractPersistableCustom<Long> {
|
|||||||
vote.electionPost = post;
|
vote.electionPost = post;
|
||||||
vote.voterMemberId = voterMemberId;
|
vote.voterMemberId = voterMemberId;
|
||||||
vote.candidate = candidate;
|
vote.candidate = candidate;
|
||||||
vote.voteTimestamp = LocalDateTime.now();
|
vote.voteTimestamp = LocalDateTime.now(DateUtils.getDateTimeZoneOfTenant());
|
||||||
vote.boothId = boothId;
|
vote.boothId = boothId;
|
||||||
vote.ipAddress = ipAddress;
|
vote.ipAddress = ipAddress;
|
||||||
return vote;
|
return vote;
|
||||||
|
|||||||
+10
-2
@@ -1,11 +1,19 @@
|
|||||||
package org.apache.fineract.portfolio.election.domain;
|
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.Getter;
|
||||||
import lombok.NoArgsConstructor;
|
import lombok.NoArgsConstructor;
|
||||||
import lombok.Setter;
|
import lombok.Setter;
|
||||||
|
|
||||||
import java.time.LocalDateTime;
|
import java.time.LocalDateTime;
|
||||||
|
import org.apache.fineract.infrastructure.core.service.DateUtils;
|
||||||
|
|
||||||
@Entity
|
@Entity
|
||||||
@Table(name = "m_election_meeting_agenda_resolution")
|
@Table(name = "m_election_meeting_agenda_resolution")
|
||||||
@@ -41,7 +49,7 @@ public class MeetingAgendaResolution {
|
|||||||
r.agendaId = agendaId;
|
r.agendaId = agendaId;
|
||||||
r.resolution = resolution;
|
r.resolution = resolution;
|
||||||
r.discussionNotes = notes;
|
r.discussionNotes = notes;
|
||||||
r.resolvedAt = LocalDateTime.now();
|
r.resolvedAt = LocalDateTime.now(DateUtils.getDateTimeZoneOfTenant());
|
||||||
return r;
|
return r;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
+11
-2
@@ -1,11 +1,20 @@
|
|||||||
package org.apache.fineract.portfolio.election.domain;
|
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.Getter;
|
||||||
import lombok.NoArgsConstructor;
|
import lombok.NoArgsConstructor;
|
||||||
import lombok.Setter;
|
import lombok.Setter;
|
||||||
|
|
||||||
import java.time.LocalDateTime;
|
import java.time.LocalDateTime;
|
||||||
|
import org.apache.fineract.infrastructure.core.service.DateUtils;
|
||||||
|
|
||||||
@Entity
|
@Entity
|
||||||
@Table(name = "m_election_meeting_member_vote",
|
@Table(name = "m_election_meeting_member_vote",
|
||||||
@@ -46,7 +55,7 @@ public class MeetingMemberVote {
|
|||||||
v.agendaId = agendaId;
|
v.agendaId = agendaId;
|
||||||
v.memberId = memberId;
|
v.memberId = memberId;
|
||||||
v.vote = vote;
|
v.vote = vote;
|
||||||
v.votedAt = LocalDateTime.now();
|
v.votedAt = LocalDateTime.now(DateUtils.getDateTimeZoneOfTenant());
|
||||||
v.remark = (remark != null && !remark.isBlank()) ? remark.trim() : null;
|
v.remark = (remark != null && !remark.isBlank()) ? remark.trim() : null;
|
||||||
return v;
|
return v;
|
||||||
}
|
}
|
||||||
|
|||||||
+7
-3
@@ -1,12 +1,16 @@
|
|||||||
package org.apache.fineract.portfolio.election.domain;
|
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.Getter;
|
||||||
import lombok.NoArgsConstructor;
|
import lombok.NoArgsConstructor;
|
||||||
import lombok.Setter;
|
import lombok.Setter;
|
||||||
|
|
||||||
import java.time.LocalDateTime;
|
import java.time.LocalDateTime;
|
||||||
import java.util.UUID;
|
import java.util.UUID;
|
||||||
|
import org.apache.fineract.infrastructure.core.service.DateUtils;
|
||||||
|
|
||||||
@Entity
|
@Entity
|
||||||
@Table(name = "m_election_meeting_vote_token")
|
@Table(name = "m_election_meeting_vote_token")
|
||||||
@@ -49,12 +53,12 @@ public class MeetingVoteToken {
|
|||||||
t.memberName = memberName;
|
t.memberName = memberName;
|
||||||
t.designation = designation;
|
t.designation = designation;
|
||||||
t.used = false;
|
t.used = false;
|
||||||
t.createdAt = LocalDateTime.now();
|
t.createdAt = LocalDateTime.now(DateUtils.getDateTimeZoneOfTenant());
|
||||||
t.expiresAt = t.createdAt.plusDays(validDays);
|
t.expiresAt = t.createdAt.plusDays(validDays);
|
||||||
return t;
|
return t;
|
||||||
}
|
}
|
||||||
|
|
||||||
public boolean isExpired() {
|
public boolean isExpired() {
|
||||||
return LocalDateTime.now().isAfter(expiresAt);
|
return LocalDateTime.now(DateUtils.getDateTimeZoneOfTenant()).isAfter(expiresAt);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
+3
-2
@@ -32,6 +32,7 @@ import java.time.format.DateTimeFormatter;
|
|||||||
import java.util.ArrayList;
|
import java.util.ArrayList;
|
||||||
import java.util.Collections;
|
import java.util.Collections;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
|
import org.apache.fineract.infrastructure.core.service.DateUtils;
|
||||||
|
|
||||||
@Slf4j
|
@Slf4j
|
||||||
@Service
|
@Service
|
||||||
@@ -215,7 +216,7 @@ public class CommitteeMeetingServiceImpl implements CommitteeMeetingService {
|
|||||||
|
|
||||||
private String buildMeetingInviteHtml(String recipientName, String committeeName, CommitteeMeeting meeting, boolean isUpdate) {
|
private String buildMeetingInviteHtml(String recipientName, String committeeName, CommitteeMeeting meeting, boolean isUpdate) {
|
||||||
DateTimeFormatter dateFmt = DateTimeFormatter.ofPattern("dd MMMM yyyy");
|
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 dateStr = meeting.getMeetingDate() != null ? meeting.getMeetingDate().format(dateFmt) : "—";
|
||||||
String timeStr = meeting.getMeetingTime() != null ? meeting.getMeetingTime() : "—";
|
String timeStr = meeting.getMeetingTime() != null ? meeting.getMeetingTime() : "—";
|
||||||
boolean isOnline = meeting.getMode() == CommitteeMeetingMode.ONLINE;
|
boolean isOnline = meeting.getMode() == CommitteeMeetingMode.ONLINE;
|
||||||
@@ -381,7 +382,7 @@ public class CommitteeMeetingServiceImpl implements CommitteeMeetingService {
|
|||||||
if (date == null) {
|
if (date == null) {
|
||||||
throw new IllegalArgumentException("Meeting date is required");
|
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");
|
throw new IllegalArgumentException("Meeting date cannot be in the past");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
+2
-1
@@ -26,6 +26,7 @@ import java.util.List;
|
|||||||
import java.util.Map;
|
import java.util.Map;
|
||||||
import java.util.Set;
|
import java.util.Set;
|
||||||
import java.util.stream.Collectors;
|
import java.util.stream.Collectors;
|
||||||
|
import org.apache.fineract.infrastructure.core.service.DateUtils;
|
||||||
|
|
||||||
@Service
|
@Service
|
||||||
@RequiredArgsConstructor
|
@RequiredArgsConstructor
|
||||||
@@ -132,7 +133,7 @@ public class CommitteeServiceImpl implements CommitteeService {
|
|||||||
|
|
||||||
@Override
|
@Override
|
||||||
public List<DirectorAppointmentData> getCurrentElectionDirectors() {
|
public List<DirectorAppointmentData> 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
|
// fallback: most recent RESULT_DECLARED election if none has active duration
|
||||||
if (currentElection.isEmpty()) {
|
if (currentElection.isEmpty()) {
|
||||||
|
|||||||
+9
-8
@@ -28,6 +28,7 @@ import java.util.List;
|
|||||||
import java.util.Map;
|
import java.util.Map;
|
||||||
import java.util.Set;
|
import java.util.Set;
|
||||||
import java.util.stream.Collectors;
|
import java.util.stream.Collectors;
|
||||||
|
import org.apache.fineract.infrastructure.core.service.DateUtils;
|
||||||
|
|
||||||
@Service
|
@Service
|
||||||
@RequiredArgsConstructor
|
@RequiredArgsConstructor
|
||||||
@@ -109,12 +110,12 @@ public class DirectorAppointmentServiceImpl implements DirectorAppointmentServic
|
|||||||
@Transactional
|
@Transactional
|
||||||
@Scheduled(cron = "0 0 0 * * *")
|
@Scheduled(cron = "0 0 0 * * *")
|
||||||
public void autoExpireByTenure() {
|
public void autoExpireByTenure() {
|
||||||
int updated = repository.expireByTenureDate(LocalDate.now());
|
int updated = repository.expireByTenureDate(LocalDate.now(DateUtils.getDateTimeZoneOfTenant()));
|
||||||
if (updated > 0) {
|
if (updated > 0) {
|
||||||
log.info("Auto-expired {} director appointment(s) whose tenure ended.", updated);
|
log.info("Auto-expired {} director appointment(s) whose tenure ended.", updated);
|
||||||
auditService.log(ElectionAuditAction.UPDATE_DIRECTOR_APPOINTMENT, "DIRECTOR_APPOINTMENT", null, null,
|
auditService.log(ElectionAuditAction.UPDATE_DIRECTOR_APPOINTMENT, "DIRECTOR_APPOINTMENT", null, null,
|
||||||
"Scheduler auto-expired " + updated + " director appointment(s)",
|
"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;
|
DirectorAppointmentStatus statusEnum = null;
|
||||||
if (status != null && !status.isBlank()) {
|
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) {
|
if (electionId != null && statusEnum != null) {
|
||||||
@@ -177,7 +180,9 @@ public class DirectorAppointmentServiceImpl implements DirectorAppointmentServic
|
|||||||
if (req.getAppointmentDate() != null) d.setAppointmentDate(req.getAppointmentDate());
|
if (req.getAppointmentDate() != null) d.setAppointmentDate(req.getAppointmentDate());
|
||||||
if (req.getRemarks() != null) d.setRemarks(req.getRemarks());
|
if (req.getRemarks() != null) d.setRemarks(req.getRemarks());
|
||||||
if (req.getStatus() != null) {
|
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.getCandidateName() != null) d.setCandidateName(req.getCandidateName());
|
||||||
if (req.getPostName() != null) d.setPostName(req.getPostName());
|
if (req.getPostName() != null) d.setPostName(req.getPostName());
|
||||||
@@ -234,10 +239,6 @@ public class DirectorAppointmentServiceImpl implements DirectorAppointmentServic
|
|||||||
return toData(d, null, null);
|
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) {
|
private DirectorAppointmentData toData(DirectorAppointment d, String electionTitle, Long memberId) {
|
||||||
return DirectorAppointmentData.builder()
|
return DirectorAppointmentData.builder()
|
||||||
.id(d.getId())
|
.id(d.getId())
|
||||||
|
|||||||
+2
-1
@@ -15,6 +15,7 @@ import java.time.Period;
|
|||||||
import java.util.ArrayList;
|
import java.util.ArrayList;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
import java.util.Map;
|
import java.util.Map;
|
||||||
|
import org.apache.fineract.infrastructure.core.service.DateUtils;
|
||||||
|
|
||||||
@Slf4j
|
@Slf4j
|
||||||
@Service
|
@Service
|
||||||
@@ -318,7 +319,7 @@ public class ElectionAnalyticsServiceImpl implements ElectionAnalyticsService {
|
|||||||
Object dob = info.get("date_of_birth");
|
Object dob = info.get("date_of_birth");
|
||||||
if (dob instanceof java.sql.Date) {
|
if (dob instanceof java.sql.Date) {
|
||||||
LocalDate dobDate = ((java.sql.Date) dob).toLocalDate();
|
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 ─────────────────────────────────────────────────────────
|
// ── Voter pool ─────────────────────────────────────────────────────────
|
||||||
|
|||||||
+3
-2
@@ -16,6 +16,7 @@ import java.time.LocalDate;
|
|||||||
import java.util.ArrayList;
|
import java.util.ArrayList;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
import java.util.Map;
|
import java.util.Map;
|
||||||
|
import org.apache.fineract.infrastructure.core.service.DateUtils;
|
||||||
|
|
||||||
@Slf4j
|
@Slf4j
|
||||||
@Service
|
@Service
|
||||||
@@ -104,7 +105,7 @@ public class ElectionCeoPreCheckServiceImpl implements ElectionCeoPreCheckServic
|
|||||||
if (status == null || status != 300) {
|
if (status == null || status != 300) {
|
||||||
String label = statusLabel(status);
|
String label = statusLabel(status);
|
||||||
precheck.completeKycCheck(CheckResult.FAIL, "KYC not verified (status: " + label + ")");
|
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);
|
precheck.completeKycCheck(CheckResult.FAIL, "KYC expired on " + expiry);
|
||||||
} else {
|
} else {
|
||||||
String expiryNote = expiry != null ? ", expires " + expiry : "";
|
String expiryNote = expiry != null ? ", expires " + expiry : "";
|
||||||
@@ -155,7 +156,7 @@ public class ElectionCeoPreCheckServiceImpl implements ElectionCeoPreCheckServic
|
|||||||
issues.add(name + ": No KYC record");
|
issues.add(name + ": No KYC record");
|
||||||
} else if (status != 300) {
|
} else if (status != 300) {
|
||||||
issues.add(name + ": KYC not verified (" + statusLabel(status) + ")");
|
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);
|
issues.add(name + ": KYC expired on " + expiry);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
+2
-1
@@ -8,6 +8,7 @@ import org.springframework.stereotype.Service;
|
|||||||
|
|
||||||
import java.time.LocalDate;
|
import java.time.LocalDate;
|
||||||
import java.time.format.DateTimeFormatter;
|
import java.time.format.DateTimeFormatter;
|
||||||
|
import org.apache.fineract.infrastructure.core.service.DateUtils;
|
||||||
|
|
||||||
@Slf4j
|
@Slf4j
|
||||||
@Service
|
@Service
|
||||||
@@ -18,7 +19,7 @@ public class ElectionNoDueCertificateServiceImpl implements ElectionNoDueCertifi
|
|||||||
|
|
||||||
@Override
|
@Override
|
||||||
public String generateCertificateNumber(ElectionNomination nomination) {
|
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());
|
return "NDC-" + datePart + "-" + String.format("%06d", nomination.getId());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
+2
-1
@@ -36,6 +36,7 @@ import java.util.HashMap;
|
|||||||
import java.util.List;
|
import java.util.List;
|
||||||
import java.util.Map;
|
import java.util.Map;
|
||||||
import java.util.stream.Collectors;
|
import java.util.stream.Collectors;
|
||||||
|
import org.apache.fineract.infrastructure.core.service.DateUtils;
|
||||||
|
|
||||||
@Service
|
@Service
|
||||||
@RequiredArgsConstructor
|
@RequiredArgsConstructor
|
||||||
@@ -315,7 +316,7 @@ public class ElectionReadPlatformServiceImpl implements ElectionReadPlatformServ
|
|||||||
private ElectionNominationData toNominationData(ElectionNomination n) {
|
private ElectionNominationData toNominationData(ElectionNomination n) {
|
||||||
Integer age = null;
|
Integer age = null;
|
||||||
if (n.getDateOfBirth() != 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()
|
return ElectionNominationData.builder()
|
||||||
.id(n.getId())
|
.id(n.getId())
|
||||||
|
|||||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user