mirror of
https://github.com/we-promise/sure.git
synced 2026-08-05 16:42:18 +00:00
* Add support for trading212 integration in investments sync * Respect Trading 212 history rate limits * Replace hex colors with design tokens * Changed withdrawal to withdraw * Address PR review feedback for Trading 212 integration - Replace all Rails.logger calls with DebugLogEntry.capture across syncer, importer, processor, provider, controller, and unlinking - Fix destroy action to surface unlink errors via DebugLogEntry - Replace hardcoded 'GBP' currency fallback with Current.family.currency - Replace hardcoded English status strings in Syncer with i18n - Add config/initializers/trading212.rb with DEBUG_RAW ENV toggle - Add comprehensive test coverage: item, account, data_helpers, holdings_processor, activities_processor, importer, syncer, and controller tests - Rewrite syncer and controller tests to match actual interfaces * Fix tests and bugs found during local test execution - Fix standard_ticker: empty string caused nil.upcase via [].first - Fix parse_date: DateTime < Date, so when Date caught DateTime first - Fix ActivitiesProcessor/HoldingsProcessor: missing instruments_map in DataHelpers caused NameError when processing dividends - Fix test: security fixture ticker collision with test data - Fix test: sync_status_summary i18n matching in assertions - Fix test: trading212_provider ConfigurationError test path - Fix test: controller invalid params needs Turbo-Frame header - Fix test: syncer test uses stubs instead of strict expects 116 tests, 257 assertions, 0 failures, 0 errors * Keep raw provider response bodies out of exception messages. * Fix Secrets leak into page HTML, prevents the API key/secret from appearing in the HTML source while keeping the "leave blank to keep existing" UX. * Address review findings: env gate, sync test, uniqueness test, destroy flow - Gate TRADING212_DEBUG_RAW behind Rails.env.local? so staging/production cannot accidentally enable raw payload logging - Assert SyncJob enqueue in sync controller test, not just redirect - Fix cross-item uniqueness test to actually use two different items - Remove rescue in destroy so unlink failures stop the flow (matching Brex/Akahu pattern) instead of proceeding to destroy_later silently * Add Trading212 tables to db/schema.rb for CI test database CI runs db:test:prepare which loads db/schema.rb, not migrations. Without these table definitions, fixture loading fails with PG::UndefinedTable: relation "trading212_accounts" does not exist. * Removed lint complaint * Register Trading212 in ProviderConnectionStatus::PROVIDERS Fixes CI failure: test_provider_registry_covers_syncable_family_provider_item_associations * Fixed bad merge --------- Signed-off-by: jdcdp <47483528+jdcdp@users.noreply.github.com> Co-authored-by: jdcdp <jdcdp@cdm4.net>
69 lines
2.9 KiB
Ruby
69 lines
2.9 KiB
Ruby
class Trading212Item::Syncer
|
|
include SyncStats::Collector
|
|
|
|
attr_reader :trading212_item
|
|
|
|
def initialize(trading212_item)
|
|
@trading212_item = trading212_item
|
|
end
|
|
|
|
def perform_sync(sync)
|
|
sync.update!(status_text: I18n.t("trading212_items.sync.status.checking_credentials")) if sync.respond_to?(:status_text)
|
|
unless trading212_item.credentials_configured?
|
|
trading212_item.update!(status: :requires_update)
|
|
raise Provider::Trading212::ConfigurationError, "Trading 212 API key is missing."
|
|
end
|
|
|
|
sync.update!(status_text: I18n.t("trading212_items.sync.status.importing_account")) if sync.respond_to?(:status_text)
|
|
trading212_item.import_latest_data
|
|
|
|
sync.update!(status_text: I18n.t("trading212_items.sync.status.checking_configuration")) if sync.respond_to?(:status_text)
|
|
collect_setup_stats(sync, provider_accounts: trading212_item.trading212_accounts.to_a)
|
|
|
|
unlinked_accounts = trading212_item.trading212_accounts.left_joins(:account_provider).where(account_providers: { id: nil })
|
|
linked_accounts = trading212_item.trading212_accounts.joins(:account).merge(Account.visible)
|
|
|
|
if unlinked_accounts.any?
|
|
trading212_item.update!(pending_account_setup: true)
|
|
sync.update!(status_text: I18n.t("trading212_items.sync.status.accounts_need_setup", count: unlinked_accounts.count)) if sync.respond_to?(:status_text)
|
|
else
|
|
trading212_item.update!(pending_account_setup: false)
|
|
end
|
|
|
|
if linked_accounts.any?
|
|
sync.update!(status_text: I18n.t("trading212_items.sync.status.processing_activity")) if sync.respond_to?(:status_text)
|
|
trading212_item.process_accounts
|
|
|
|
sync.update!(status_text: I18n.t("trading212_items.sync.status.calculating_balances")) if sync.respond_to?(:status_text)
|
|
trading212_item.schedule_account_syncs(
|
|
parent_sync: sync,
|
|
window_start_date: sync.window_start_date,
|
|
window_end_date: sync.window_end_date
|
|
)
|
|
|
|
account_ids = linked_accounts.includes(:account).filter_map { |pa| pa.account&.id }
|
|
collect_transaction_stats(sync, account_ids: account_ids, source: "trading212") if account_ids.any?
|
|
collect_trades_stats(sync, account_ids: account_ids, source: "trading212") if account_ids.any?
|
|
collect_holdings_stats(sync, holdings_count: count_holdings, label: "processed")
|
|
end
|
|
|
|
collect_health_stats(sync, errors: nil)
|
|
rescue Provider::Trading212::AuthenticationError, Provider::Trading212::ConfigurationError => e
|
|
trading212_item.update!(status: :requires_update)
|
|
collect_health_stats(sync, errors: [ { message: e.message, category: "auth_error" } ])
|
|
raise
|
|
rescue => e
|
|
collect_health_stats(sync, errors: [ { message: e.message, category: "sync_error" } ])
|
|
raise
|
|
end
|
|
|
|
def perform_post_sync
|
|
end
|
|
|
|
private
|
|
|
|
def count_holdings
|
|
trading212_item.trading212_accounts.sum { |acct| Array(acct.raw_positions_payload).size }
|
|
end
|
|
end
|