Add SnapTrade brokerage integration with full trade history support (#737)

* Introduce SnapTrade integration with models, migrations, views, and activity processing logic.

* Refactor SnapTrade activities processing: improve activity fetching flow, handle pending states, and update UI elements for enhanced user feedback.

* Update Brakeman ignore file to include intentional redirect for SnapTrade OAuth portal.

* Refactor SnapTrade models, views, and processing logic: add currency extraction helper, improve pending state handling, optimize migration checks, and enhance user feedback in UI.

* Remove encryption for SnapTrade `snaptrade_user_id`, as it is an identifier, not a secret.

* Introduce `SnaptradeConnectionCleanupJob` to asynchronously handle SnapTrade connection cleanup and improve i18n for SnapTrade item status messages.

* Update SnapTrade encryption: make `snaptrade_user_secret` non-deterministic to enhance security.

---------

Signed-off-by: Juan José Mata <juanjo.mata@gmail.com>
Co-authored-by: luckyPipewrench <luckypipewrench@proton.me>
Co-authored-by: Juan José Mata <juanjo.mata@gmail.com>
This commit is contained in:
LPW
2026-01-22 14:52:49 -05:00
committed by GitHub
parent 179552657c
commit a83f70425f
52 changed files with 4417 additions and 25 deletions

View File

@@ -19,15 +19,21 @@
# ) %>
#
class ProviderSyncSummary < ViewComponent::Base
attr_reader :stats, :provider_item, :institutions_count
attr_reader :stats, :provider_item, :institutions_count, :activities_pending
# @param stats [Hash] The sync statistics hash from sync.sync_stats
# @param provider_item [Object] The provider item (must respond to last_synced_at)
# @param institutions_count [Integer, nil] Optional count of connected institutions
def initialize(stats:, provider_item:, institutions_count: nil)
# @param activities_pending [Boolean] Whether activities are still being fetched in background
def initialize(stats:, provider_item:, institutions_count: nil, activities_pending: false)
@stats = stats || {}
@provider_item = provider_item
@institutions_count = institutions_count
@activities_pending = activities_pending
end
def activities_pending?
@activities_pending
end
def render?
@@ -102,6 +108,19 @@ class ProviderSyncSummary < ViewComponent::Base
stats.key?("holdings_processed") ? holdings_processed : holdings_found
end
# Trades statistics (investment activities like buy/sell)
def trades_imported
stats["trades_imported"].to_i
end
def trades_skipped
stats["trades_skipped"].to_i
end
def has_trades_stats?
stats.key?("trades_imported") || stats.key?("trades_skipped")
end
# Returns the CSS color class for a data quality detail severity
# @param severity [String] The severity level ("warning", "error", or other)
# @return [String] The Tailwind CSS class for the color