diff --git a/fineract-provider/src/main/java/org/apache/fineract/commands/domain/CommandSource.java b/fineract-provider/src/main/java/org/apache/fineract/commands/domain/CommandSource.java index 75a368eb8..bfd66e18a 100644 --- a/fineract-provider/src/main/java/org/apache/fineract/commands/domain/CommandSource.java +++ b/fineract-provider/src/main/java/org/apache/fineract/commands/domain/CommandSource.java @@ -18,8 +18,7 @@ */ package org.apache.fineract.commands.domain; -import java.time.LocalDateTime; -import java.time.ZonedDateTime; +import java.time.OffsetDateTime; import javax.persistence.Column; import javax.persistence.Entity; import javax.persistence.JoinColumn; @@ -72,16 +71,24 @@ public class CommandSource extends AbstractPersistableCustom { @JoinColumn(name = "maker_id", nullable = false) private AppUser maker; - @Column(name = "made_on_date", nullable = false) - private LocalDateTime madeOnDate; + /* + * Deprecated: Columns and data left untouched to help migration. + * + * @Column(name = "made_on_date", nullable = false) private LocalDateTime madeOnDate; + * + * @Column(name = "checked_on_date", nullable = true) private LocalDateTime checkedOnDate; + */ + + @Column(name = "made_on_date_utc", nullable = false) + private OffsetDateTime madeOnDate; + + @Column(name = "checked_on_date_utc") + private OffsetDateTime checkedOnDate; @ManyToOne @JoinColumn(name = "checker_id", nullable = true) private AppUser checker; - @Column(name = "checked_on_date", nullable = true) - private LocalDateTime checkedOnDate; - @Column(name = "processing_result_enum", nullable = false) private Integer processingResult; @@ -99,7 +106,7 @@ public class CommandSource extends AbstractPersistableCustom { public static CommandSource fullEntryFrom(final CommandWrapper wrapper, final JsonCommand command, final AppUser maker) { return new CommandSource(wrapper.actionName(), wrapper.entityName(), wrapper.getHref(), command.entityId(), command.subentityId(), - command.json(), maker, ZonedDateTime.now(DateUtils.getDateTimeZoneOfTenant())); + command.json(), maker); } protected CommandSource() { @@ -107,7 +114,7 @@ public class CommandSource extends AbstractPersistableCustom { } private CommandSource(final String actionName, final String entityName, final String href, final Long resourceId, - final Long subresourceId, final String commandSerializedAsJson, final AppUser maker, final ZonedDateTime madeOnDateTime) { + final Long subresourceId, final String commandSerializedAsJson, final AppUser maker) { this.actionName = actionName; this.entityName = entityName; this.resourceGetUrl = href; @@ -115,7 +122,7 @@ public class CommandSource extends AbstractPersistableCustom { this.subresourceId = subresourceId; this.commandAsJson = commandSerializedAsJson; this.maker = maker; - this.madeOnDate = madeOnDateTime != null ? madeOnDateTime.toLocalDateTime() : null; + this.madeOnDate = DateUtils.getOffsetDateTimeOfTenant(); this.processingResult = CommandProcessingResultType.PROCESSED.getValue(); } @@ -135,15 +142,15 @@ public class CommandSource extends AbstractPersistableCustom { this.organisationCreditBureauId = organisationCreditBureauId; } - public void markAsChecked(final AppUser checker, final ZonedDateTime checkedOnDate) { + public void markAsChecked(final AppUser checker) { this.checker = checker; - this.checkedOnDate = checkedOnDate != null ? checkedOnDate.toLocalDateTime() : null; + this.checkedOnDate = DateUtils.getOffsetDateTimeOfTenant(); this.processingResult = CommandProcessingResultType.PROCESSED.getValue(); } - public void markAsRejected(final AppUser checker, final ZonedDateTime checkedOnDate) { + public void markAsRejected(final AppUser checker) { this.checker = checker; - this.checkedOnDate = checkedOnDate != null ? checkedOnDate.toLocalDateTime() : null; + this.checkedOnDate = DateUtils.getOffsetDateTimeOfTenant(); this.processingResult = CommandProcessingResultType.REJECTED.getValue(); } diff --git a/fineract-provider/src/main/java/org/apache/fineract/commands/service/AuditReadPlatformServiceImpl.java b/fineract-provider/src/main/java/org/apache/fineract/commands/service/AuditReadPlatformServiceImpl.java index 8aa3bf7a6..2f63ef1fe 100644 --- a/fineract-provider/src/main/java/org/apache/fineract/commands/service/AuditReadPlatformServiceImpl.java +++ b/fineract-provider/src/main/java/org/apache/fineract/commands/service/AuditReadPlatformServiceImpl.java @@ -24,6 +24,7 @@ import com.google.gson.JsonObject; import java.lang.reflect.Type; import java.sql.ResultSet; import java.sql.SQLException; +import java.time.OffsetDateTime; import java.time.ZonedDateTime; import java.util.Arrays; import java.util.Collection; @@ -105,8 +106,8 @@ public class AuditReadPlatformServiceImpl implements AuditReadPlatformService { String partSql = " aud.id as id, aud.action_name as actionName, aud.entity_name as entityName," + " aud.resource_id as resourceId, aud.subresource_id as subresourceId,aud.client_id as clientId, aud.loan_id as loanId," - + " mk.username as maker, aud.made_on_date as madeOnDate, " + " aud.api_get_url as resourceGetUrl, " - + "ck.username as checker, aud.checked_on_date as checkedOnDate, ev.enum_message_property as processingResult " + + " mk.username as maker, aud.made_on_date as madeOnDate, aud.made_on_date_utc as madeOnDateUTC, aud.api_get_url as resourceGetUrl, " + + "ck.username as checker, aud.checked_on_date as checkedOnDate, aud.checked_on_date_utc as checkedOnDateUTC, ev.enum_message_property as processingResult " + commandAsJsonString + ", " + " o.name as officeName, gl.level_name as groupLevelName, g.display_name as groupName, c.display_name as clientName, " + " l.account_no as loanAccountNo, s.account_no as savingsAccountNo " + " from m_portfolio_command_source aud " @@ -136,9 +137,11 @@ public class AuditReadPlatformServiceImpl implements AuditReadPlatformService { final Long loanId = JdbcSupport.getLong(rs, "loanId"); final Long subresourceId = JdbcSupport.getLong(rs, "subresourceId"); final String maker = rs.getString("maker"); - final ZonedDateTime madeOnDate = JdbcSupport.getDateTime(rs, "madeOnDate"); + final ZonedDateTime madeOnDateTenant = JdbcSupport.getDateTime(rs, "madeOnDate"); + final OffsetDateTime madeOnDateUTC = JdbcSupport.getOffsetDateTime(rs, "madeOnDateUTC"); final String checker = rs.getString("checker"); - final ZonedDateTime checkedOnDate = JdbcSupport.getDateTime(rs, "checkedOnDate"); + final ZonedDateTime checkedOnDateTenant = JdbcSupport.getDateTime(rs, "checkedOnDate"); + final OffsetDateTime checkedOnDateUTC = JdbcSupport.getOffsetDateTime(rs, "checkedOnDateUTC"); final String processingResult = rs.getString("processingResult"); final String resourceGetUrl = rs.getString("resourceGetUrl"); String commandAsJson; @@ -156,6 +159,9 @@ public class AuditReadPlatformServiceImpl implements AuditReadPlatformService { final String loanAccountNo = rs.getString("loanAccountNo"); final String savingsAccountNo = rs.getString("savingsAccountNo"); + ZonedDateTime madeOnDate = madeOnDateUTC != null ? madeOnDateUTC.toZonedDateTime() : madeOnDateTenant; + ZonedDateTime checkedOnDate = checkedOnDateUTC != null ? checkedOnDateUTC.toZonedDateTime() : checkedOnDateTenant; + return new AuditData(id, actionName, entityName, resourceId, subresourceId, maker, madeOnDate, checker, checkedOnDate, processingResult, commandAsJson, officeName, groupLevelName, groupName, clientName, loanAccountNo, savingsAccountNo, clientId, loanId, resourceGetUrl); diff --git a/fineract-provider/src/main/java/org/apache/fineract/commands/service/PortfolioCommandSourceWritePlatformServiceImpl.java b/fineract-provider/src/main/java/org/apache/fineract/commands/service/PortfolioCommandSourceWritePlatformServiceImpl.java index d6d3cd0a2..ad64791a1 100644 --- a/fineract-provider/src/main/java/org/apache/fineract/commands/service/PortfolioCommandSourceWritePlatformServiceImpl.java +++ b/fineract-provider/src/main/java/org/apache/fineract/commands/service/PortfolioCommandSourceWritePlatformServiceImpl.java @@ -21,7 +21,6 @@ package org.apache.fineract.commands.service; import com.google.gson.JsonElement; import edu.umd.cs.findbugs.annotations.SuppressFBWarnings; import java.security.SecureRandom; -import java.time.ZonedDateTime; import lombok.RequiredArgsConstructor; import lombok.extern.slf4j.Slf4j; import org.apache.fineract.commands.domain.CommandSource; @@ -33,7 +32,6 @@ import org.apache.fineract.commands.exception.RollbackTransactionAsCommandIsNotA import org.apache.fineract.infrastructure.core.api.JsonCommand; import org.apache.fineract.infrastructure.core.data.CommandProcessingResult; import org.apache.fineract.infrastructure.core.serialization.FromJsonHelper; -import org.apache.fineract.infrastructure.core.service.DateUtils; import org.apache.fineract.infrastructure.core.service.ThreadLocalContextUtil; import org.apache.fineract.infrastructure.jobs.service.SchedulerJobRunnerReadService; import org.apache.fineract.infrastructure.security.service.PlatformSecurityContext; @@ -180,7 +178,7 @@ public class PortfolioCommandSourceWritePlatformServiceImpl implements Portfolio final CommandSource commandSourceInput = validateMakerCheckerTransaction(makerCheckerId); validateIsUpdateAllowed(); final AppUser maker = this.context.authenticatedUser(); - commandSourceInput.markAsRejected(maker, ZonedDateTime.now(DateUtils.getDateTimeZoneOfTenant())); + commandSourceInput.markAsRejected(maker); this.commandSourceRepository.save(commandSourceInput); return makerCheckerId; } diff --git a/fineract-provider/src/main/java/org/apache/fineract/commands/service/SynchronousCommandProcessingService.java b/fineract-provider/src/main/java/org/apache/fineract/commands/service/SynchronousCommandProcessingService.java index 016d7ac1f..90b911ac4 100644 --- a/fineract-provider/src/main/java/org/apache/fineract/commands/service/SynchronousCommandProcessingService.java +++ b/fineract-provider/src/main/java/org/apache/fineract/commands/service/SynchronousCommandProcessingService.java @@ -22,7 +22,6 @@ import com.google.gson.Gson; import com.google.gson.reflect.TypeToken; import java.lang.reflect.Type; import java.time.Instant; -import java.time.ZonedDateTime; import java.util.HashMap; import java.util.Map; import lombok.RequiredArgsConstructor; @@ -32,6 +31,7 @@ import org.apache.fineract.batch.exception.ErrorInfo; import org.apache.fineract.commands.domain.CommandSource; import org.apache.fineract.commands.domain.CommandSourceRepository; import org.apache.fineract.commands.domain.CommandWrapper; +import org.apache.fineract.commands.exception.CommandNotFoundException; import org.apache.fineract.commands.exception.RollbackTransactionAsCommandIsNotApprovedByCheckerException; import org.apache.fineract.commands.exception.UnsupportedCommandException; import org.apache.fineract.commands.handler.NewCommandSourceHandler; @@ -41,7 +41,6 @@ import org.apache.fineract.infrastructure.core.api.JsonCommand; import org.apache.fineract.infrastructure.core.data.CommandProcessingResult; import org.apache.fineract.infrastructure.core.data.CommandProcessingResultBuilder; import org.apache.fineract.infrastructure.core.serialization.ToApiJsonSerializer; -import org.apache.fineract.infrastructure.core.service.DateUtils; import org.apache.fineract.infrastructure.core.service.ThreadLocalContextUtil; import org.apache.fineract.infrastructure.hooks.event.HookEvent; import org.apache.fineract.infrastructure.hooks.event.HookEventSource; @@ -84,10 +83,11 @@ public class SynchronousCommandProcessingService implements CommandProcessingSer final AppUser maker = this.context.authenticatedUser(wrapper); - CommandSource commandSourceResult = null; + CommandSource commandSourceResult; if (command.commandId() != null) { - commandSourceResult = this.commandSourceRepository.findById(command.commandId()).orElse(null); - commandSourceResult.markAsChecked(maker, ZonedDateTime.now(DateUtils.getDateTimeZoneOfTenant())); + commandSourceResult = this.commandSourceRepository.findById(command.commandId()) + .orElseThrow(() -> new CommandNotFoundException(command.commandId())); + commandSourceResult.markAsChecked(maker); } else { commandSourceResult = CommandSource.fullEntryFrom(wrapper, command, maker); } @@ -95,7 +95,7 @@ public class SynchronousCommandProcessingService implements CommandProcessingSer commandSourceResult.updateForAudit(result.getOfficeId(), result.getGroupId(), result.getClientId(), result.getLoanId(), result.getSavingsId(), result.getProductId(), result.getTransactionId()); - String changesOnlyJson = null; + String changesOnlyJson; boolean rollBack = (rollbackTransaction || result.isRollbackTransaction()) && !isApprovedByChecker; if (result.hasChanges() && !rollBack) { changesOnlyJson = this.toApiJsonSerializer.serializeResult(result.getChanges()); @@ -142,7 +142,7 @@ public class SynchronousCommandProcessingService implements CommandProcessingSer } private NewCommandSourceHandler findCommandHandler(final CommandWrapper wrapper) { - NewCommandSourceHandler handler = null; + NewCommandSourceHandler handler; if (wrapper.isDatatableResource()) { if (wrapper.isCreateDatatable()) { @@ -209,8 +209,7 @@ public class SynchronousCommandProcessingService implements CommandProcessingSer private void publishErrorEvent(CommandWrapper wrapper, JsonCommand command, Throwable t) { ErrorInfo ex; - if (t instanceof RuntimeException) { - final RuntimeException e = (RuntimeException) t; + if (t instanceof final RuntimeException e) { ex = ErrorHandler.handler(e); } else { ex = new ErrorInfo(500, 9999, "{\"Exception\": " + t.toString() + "}"); @@ -249,8 +248,7 @@ public class SynchronousCommandProcessingService implements CommandProcessingSer reqmap.put("clientId", resultCopy.getClientId()); resultCopy.setOfficeId(null); reqmap.put("response", resultCopy); - } else if (result instanceof ErrorInfo) { - ErrorInfo ex = (ErrorInfo) result; + } else if (result instanceof ErrorInfo ex) { reqmap.put("status", "Exception"); Map errorMap = gson.fromJson(ex.getMessage(), type); diff --git a/fineract-provider/src/main/java/org/apache/fineract/infrastructure/core/domain/JdbcSupport.java b/fineract-provider/src/main/java/org/apache/fineract/infrastructure/core/domain/JdbcSupport.java index 97e1e9bf4..b37fc159f 100644 --- a/fineract-provider/src/main/java/org/apache/fineract/infrastructure/core/domain/JdbcSupport.java +++ b/fineract-provider/src/main/java/org/apache/fineract/infrastructure/core/domain/JdbcSupport.java @@ -42,7 +42,7 @@ public final class JdbcSupport { ZonedDateTime dateTime = null; final Timestamp dateValue = rs.getTimestamp(columnName); if (dateValue != null) { - dateTime = ZonedDateTime.ofInstant(dateValue.toInstant(), DateUtils.getDateTimeZoneOfTenant()); + dateTime = ZonedDateTime.of(dateValue.toLocalDateTime(), DateUtils.getDateTimeZoneOfTenant()); } return dateTime; } diff --git a/fineract-provider/src/main/resources/db/changelog/tenant/changelog-tenant.xml b/fineract-provider/src/main/resources/db/changelog/tenant/changelog-tenant.xml index 4d60f259d..65cf79c76 100644 --- a/fineract-provider/src/main/resources/db/changelog/tenant/changelog-tenant.xml +++ b/fineract-provider/src/main/resources/db/changelog/tenant/changelog-tenant.xml @@ -55,4 +55,5 @@ + diff --git a/fineract-provider/src/main/resources/db/changelog/tenant/parts/0036_add_audit_entries_and_rework_command_source_datetime_fields.xml b/fineract-provider/src/main/resources/db/changelog/tenant/parts/0036_add_audit_entries_and_rework_command_source_datetime_fields.xml new file mode 100644 index 000000000..f8eab3857 --- /dev/null +++ b/fineract-provider/src/main/resources/db/changelog/tenant/parts/0036_add_audit_entries_and_rework_command_source_datetime_fields.xml @@ -0,0 +1,52 @@ + + + + + + + + + + + + + + + + + + + + + select count(*) from m_portfolio_command_source + + + + + + select count(*) from m_portfolio_command_source + + + +