FINERACT-2701: support OffsetTime for savings transactions - #6187
FINERACT-2701: support OffsetTime for savings transactions#6187AnvayKharb wants to merge 2 commits into
Conversation
c62facb to
7215a56
Compare
adamsaghy
left a comment
There was a problem hiding this comment.
It looks weird at first...
Let me review a little deeper...
We should really not use LocalDateTime and mess with modifiers (Midnight...)
| <databaseChangeLog xmlns="http://www.liquibase.org/xml/ns/dbchangelog" | ||
| xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" | ||
| xsi:schemaLocation="http://www.liquibase.org/xml/ns/dbchangelog http://www.liquibase.org/xml/ns/dbchangelog/dbchangelog-4.3.xsd"> | ||
| <changeSet author="fineract" id="1"> |
There was a problem hiding this comment.
Please dont use TIMESTAMP... use TIMESTAMP WITH TZ for postgres and DATETIME(6) for mysql
| <addColumn tableName="m_savings_account_transaction"> | ||
| <column name="transaction_datetime" type="TIMESTAMP"/> | ||
| </addColumn> | ||
| <addColumn tableName="m_account_transfer_transaction"> |
There was a problem hiding this comment.
We already have transaction date for transfer and for savings transactions.
If the plan is to store a user provided TIME part as well, lets do it with timezone infomation and as a standalone field for the TIME only. transaction date + transaction time together can represent a more precise point in time... TZ informations are important to ensure correctness across timezones.
We are storing all date time and time in UTC.
adamsaghy
left a comment
There was a problem hiding this comment.
-
I’m not keen on introducing a brand new field called
TIMESTAMP(on the database side) andLocalDateTime(on the Java side). Instead, let’s useOffsetTimeto ensure accurate timezone handling. -
The
transaction datefield already exists in thesavings transactionandsavings transferentities, and it’s of typeDATE. Do we really need a user-provided time part? Will this be different from the created date time (OffsetDateTime)?
If we do need a user-provided time part, let’s add a new field that stores as OffsetTime and is optional for backward compatibility.
-
I suggest that we request the transaction date and transaction time as two separate fields. This way, we avoid supporting a single field with different data types.
-
Let’s avoid using
LocalDateTimeand parsing to that data type in all places. Instead, the user should provide the time part with an offset TZ. Is this a viable option?
@AnvayKharb @IOhacker what do you think?
|
Hi @adamsaghy Thanks for the detailed review. I understand your concerns. Using a separate optional transactionTime with timezone information while keeping the existing transactionDate sounds like a cleaner and more backward-compatible approach than introducing a LocalDateTime field. I'll wait for @IOhacker 's thoughts as well, and if we're aligned on this direction, I'll update the implementation accordingly. |
587fa6b to
287c73f
Compare
|
Thanks for the guidance @adamsaghy @IOhacker . I updated the PR to follow the separate optional transaction time approach instead of the earlier combined date-time design. Current implementation:
I also rechecked the diff for newly introduced LocalDateTime, transaction_datetime, transactionDateTime, .atStartOfDay(), midnight conversions, and generic TIMESTAMP usage; none remain in this PR diff. Local validation passed for OpenAPI compatibility, formatting/checkstyle, focused transaction-time tests, Liquibase DDL safety, and Liquibase-only runs against both PostgreSQL and MariaDB with actual column type verification. |
287c73f to
cb7bd37
Compare
| return localTime; | ||
| } | ||
|
|
||
| public static OffsetTime getOffsetTime(final ResultSet rs, final String columnName) throws SQLException { |
There was a problem hiding this comment.
I dont think we need this many options... the field is stored as OffsetTime and fetched as OffsetTime. No need for anything else but reading as OffsetTime...
| import org.apache.fineract.infrastructure.core.service.DateUtils; | ||
|
|
||
| @Converter | ||
| public class UtcOffsetTimeAttributeConverter implements AttributeConverter<OffsetTime, LocalTime> { |
There was a problem hiding this comment.
We dont need this. We dont want to work with LocalTime...
| return OffsetDateTime.now(ZoneOffset.UTC); | ||
| } | ||
|
|
||
| public static OffsetTime toUtcOffsetTime(final OffsetTime time) { |
| private final CurrencyData currency; | ||
| private final BigDecimal transferAmount; | ||
| private final LocalDate transferDate; | ||
| @Schema(type = "string", example = "09:00:00Z", nullable = true) |
There was a problem hiding this comment.
I dont think we need swagger annotations here.
| private final String accountNo; | ||
| private final ExternalId externalId; | ||
| private final LocalDate date; | ||
| @Schema(type = "string", example = "09:00:00Z", nullable = true) |
There was a problem hiding this comment.
I dont think we need swagger annotations here.
| false); | ||
| } | ||
|
|
||
| public static SavingsAccountTransactionData create(final Long id, final SavingsAccountTransactionEnumData transactionType, |
There was a problem hiding this comment.
Instead of creating the N+1 constructor, would you be open to rewrite these using builder pattern instead?
| private LocalDate date; | ||
|
|
||
| @Column(name = "transaction_time") | ||
| @Convert(converter = UtcOffsetTimeAttributeConverter.class) |
There was a problem hiding this comment.
We dont need converter...
| validate(command, false); | ||
| } | ||
|
|
||
| public void validate(final JsonCommand command, final boolean transactionTimeSupported) { |
There was a problem hiding this comment.
I dont think we need final boolean transactionTimeSupported arg... since this field is added, it can be freely provided, no?
|
@AnvayKharb @IOhacker Can you help me understand this new field a little better? Is this provided new field will be different then the "created date time"? |
|
Hi @adamsaghy Yes, they're different. createdDateTime is the system timestamp when Fineract persisted the transaction, while transactionTime is the optional business time provided by the user for the transaction. I'll simplify the implementation as suggested by removing the converter/helper and persisting OffsetTime directly. |
cb7bd37 to
59ab286
Compare
16f06b0 to
cff0e0d
Compare
Description
This PR adds support for an optional
transactionTimefield for savings transactions usingOffsetTimewhile maintaining full backward compatibility with the existing API.The existing
transactionDatefield remains unchanged. Clients can optionally providetransactionTimein ISO-8601 offset time format (for example,14:30:00+05:30). The provided time is normalized to UTC before persistence.The implementation also propagates the optional transaction time through account transfer flows to ensure consistent transaction handling across savings operations.
Changes
transactionTimesupport usingOffsetTime.Related Issue
FINERACT-2701