diff --git a/app/models/plaid_account.rb b/app/models/plaid_account.rb index 165ed1551..bb5237586 100644 --- a/app/models/plaid_account.rb +++ b/app/models/plaid_account.rb @@ -5,7 +5,8 @@ class PlaidAccount < ApplicationRecord if encryption_ready? encrypts :raw_payload encrypts :raw_transactions_payload - encrypts :raw_investments_payload + # Support reading data encrypted under the old column name after rename + encrypts :raw_holdings_payload, previous: { attribute: :raw_investments_payload } encrypts :raw_liabilities_payload end @@ -48,9 +49,9 @@ class PlaidAccount < ApplicationRecord save! end - def upsert_plaid_investments_snapshot!(investments_snapshot) + def upsert_plaid_holdings_snapshot!(holdings_snapshot) assign_attributes( - raw_investments_payload: investments_snapshot + raw_holdings_payload: holdings_snapshot ) save! diff --git a/app/models/plaid_account/importer.rb b/app/models/plaid_account/importer.rb index 10ae10840..f12c10bdd 100644 --- a/app/models/plaid_account/importer.rb +++ b/app/models/plaid_account/importer.rb @@ -23,7 +23,7 @@ class PlaidAccount::Importer end def import_investments - plaid_account.upsert_plaid_investments_snapshot!(account_snapshot.investments_data) + plaid_account.upsert_plaid_holdings_snapshot!(account_snapshot.investments_data) end def import_liabilities diff --git a/app/models/plaid_account/investments/balance_calculator.rb b/app/models/plaid_account/investments/balance_calculator.rb index eade15ee4..852f29a0d 100644 --- a/app/models/plaid_account/investments/balance_calculator.rb +++ b/app/models/plaid_account/investments/balance_calculator.rb @@ -44,7 +44,7 @@ class PlaidAccount::Investments::BalanceCalculator attr_reader :plaid_account, :security_resolver def holdings - plaid_account.raw_investments_payload["holdings"] || [] + plaid_account.raw_holdings_payload&.dig("holdings") || [] end def calculate_investment_brokerage_cash diff --git a/app/models/plaid_account/investments/holdings_processor.rb b/app/models/plaid_account/investments/holdings_processor.rb index 493b8a9d1..44b967ea2 100644 --- a/app/models/plaid_account/investments/holdings_processor.rb +++ b/app/models/plaid_account/investments/holdings_processor.rb @@ -51,7 +51,7 @@ class PlaidAccount::Investments::HoldingsProcessor end def holdings - plaid_account.raw_investments_payload&.[]("holdings") || [] + plaid_account.raw_holdings_payload&.[]("holdings") || [] end def parse_decimal(value) diff --git a/app/models/plaid_account/investments/security_resolver.rb b/app/models/plaid_account/investments/security_resolver.rb index a8f15b0ea..5d4fa1d98 100644 --- a/app/models/plaid_account/investments/security_resolver.rb +++ b/app/models/plaid_account/investments/security_resolver.rb @@ -43,7 +43,7 @@ class PlaidAccount::Investments::SecurityResolver Response = Struct.new(:security, :cash_equivalent?, :brokerage_cash?, keyword_init: true) def securities - plaid_account.raw_investments_payload["securities"] || [] + plaid_account.raw_holdings_payload&.dig("securities") || [] end # Tries to find security, or returns the "proxy security" (common with options contracts that have underlying securities) diff --git a/app/models/plaid_account/investments/transactions_processor.rb b/app/models/plaid_account/investments/transactions_processor.rb index 5cabccb2c..efce85118 100644 --- a/app/models/plaid_account/investments/transactions_processor.rb +++ b/app/models/plaid_account/investments/transactions_processor.rb @@ -98,7 +98,7 @@ class PlaidAccount::Investments::TransactionsProcessor end def transactions - plaid_account.raw_investments_payload["transactions"] || [] + plaid_account.raw_holdings_payload&.dig("transactions") || [] end # Plaid unfortunately returns incorrect signage on some `quantity` values. They claim all "sell" transactions diff --git a/app/models/plaid_item/syncer.rb b/app/models/plaid_item/syncer.rb index 58c2baccd..74d66a58b 100644 --- a/app/models/plaid_item/syncer.rb +++ b/app/models/plaid_item/syncer.rb @@ -61,7 +61,7 @@ class PlaidItem::Syncer def count_holdings(plaid_accounts) plaid_accounts.sum do |pa| - Array(pa.raw_investments_payload).size + pa.raw_holdings_payload&.dig("holdings")&.size || 0 end end end diff --git a/db/migrate/20260123214127_rename_raw_investments_payload_to_raw_holdings_payload.rb b/db/migrate/20260123214127_rename_raw_investments_payload_to_raw_holdings_payload.rb new file mode 100644 index 000000000..80d64e953 --- /dev/null +++ b/db/migrate/20260123214127_rename_raw_investments_payload_to_raw_holdings_payload.rb @@ -0,0 +1,5 @@ +class RenameRawInvestmentsPayloadToRawHoldingsPayload < ActiveRecord::Migration[7.2] + def change + rename_column :plaid_accounts, :raw_investments_payload, :raw_holdings_payload + end +end diff --git a/db/schema.rb b/db/schema.rb index ff964879f..84bf07e6f 100644 --- a/db/schema.rb +++ b/db/schema.rb @@ -10,7 +10,7 @@ # # It's strongly recommended that you check this file into your version control system. -ActiveRecord::Schema[7.2].define(version: 2026_01_23_000000) do +ActiveRecord::Schema[7.2].define(version: 2026_01_23_214127) do # These are extensions that must be enabled in order to support this database enable_extension "pgcrypto" enable_extension "plpgsql" @@ -943,7 +943,7 @@ ActiveRecord::Schema[7.2].define(version: 2026_01_23_000000) do t.datetime "updated_at", null: false t.jsonb "raw_payload", default: {} t.jsonb "raw_transactions_payload", default: {} - t.jsonb "raw_investments_payload", default: {} + t.jsonb "raw_holdings_payload", default: {} t.jsonb "raw_liabilities_payload", default: {} t.index ["plaid_id"], name: "index_plaid_accounts_on_plaid_id", unique: true t.index ["plaid_item_id"], name: "index_plaid_accounts_on_plaid_item_id" diff --git a/lib/tasks/security_backfill.rake b/lib/tasks/security_backfill.rake index 49dd08c6b..3b79ecc8f 100644 --- a/lib/tasks/security_backfill.rake +++ b/lib/tasks/security_backfill.rake @@ -52,7 +52,7 @@ namespace :security do results[:enable_banking_items] = backfill_model(EnableBankingItem, %i[client_certificate session_id raw_payload raw_institution_payload], batch_size, dry_run) # Provider accounts - results[:plaid_accounts] = backfill_model(PlaidAccount, %i[raw_payload raw_transactions_payload raw_investments_payload raw_liabilities_payload], batch_size, dry_run) + results[:plaid_accounts] = backfill_model(PlaidAccount, %i[raw_payload raw_transactions_payload raw_holdings_payload raw_liabilities_payload], batch_size, dry_run) results[:simplefin_accounts] = backfill_model(SimplefinAccount, %i[raw_payload raw_transactions_payload raw_holdings_payload], batch_size, dry_run) results[:lunchflow_accounts] = backfill_model(LunchflowAccount, %i[raw_payload raw_transactions_payload], batch_size, dry_run) results[:enable_banking_accounts] = backfill_model(EnableBankingAccount, %i[raw_payload raw_transactions_payload], batch_size, dry_run) diff --git a/test/models/plaid_account/importer_test.rb b/test/models/plaid_account/importer_test.rb index b1084cdb0..69fcf489d 100644 --- a/test/models/plaid_account/importer_test.rb +++ b/test/models/plaid_account/importer_test.rb @@ -38,7 +38,7 @@ class PlaidAccount::ImporterTest < ActiveSupport::TestCase @plaid_account.expects(:upsert_plaid_snapshot!).with(account_data) @plaid_account.expects(:upsert_plaid_transactions_snapshot!).with(transactions_data) - @plaid_account.expects(:upsert_plaid_investments_snapshot!).with(investments_data) + @plaid_account.expects(:upsert_plaid_holdings_snapshot!).with(investments_data) @plaid_account.expects(:upsert_plaid_liabilities_snapshot!).with(liabilities_data) PlaidAccount::Importer.new(@plaid_account, account_snapshot: @mock_account_snapshot).import diff --git a/test/models/plaid_account/investments/balance_calculator_test.rb b/test/models/plaid_account/investments/balance_calculator_test.rb index c4cd5d10c..0755f22c1 100644 --- a/test/models/plaid_account/investments/balance_calculator_test.rb +++ b/test/models/plaid_account/investments/balance_calculator_test.rb @@ -67,7 +67,7 @@ class PlaidAccount::Investments::BalanceCalculatorTest < ActiveSupport::TestCase ] } - @plaid_account.update!(raw_investments_payload: test_investments) + @plaid_account.update!(raw_holdings_payload: test_investments) security_resolver = PlaidAccount::Investments::SecurityResolver.new(@plaid_account) balance_calculator = PlaidAccount::Investments::BalanceCalculator.new(@plaid_account, security_resolver: security_resolver) diff --git a/test/models/plaid_account/investments/holdings_processor_test.rb b/test/models/plaid_account/investments/holdings_processor_test.rb index 169784ae9..01194cccf 100644 --- a/test/models/plaid_account/investments/holdings_processor_test.rb +++ b/test/models/plaid_account/investments/holdings_processor_test.rb @@ -27,7 +27,7 @@ class PlaidAccount::Investments::HoldingsProcessorTest < ActiveSupport::TestCase transactions: [] # not relevant for test } - @plaid_account.update!(raw_investments_payload: test_investments_payload) + @plaid_account.update!(raw_holdings_payload: test_investments_payload) @security_resolver.expects(:resolve) .with(plaid_security_id: "123") @@ -125,7 +125,7 @@ class PlaidAccount::Investments::HoldingsProcessorTest < ActiveSupport::TestCase transactions: [] } - @plaid_account.update!(raw_investments_payload: test_investments_payload) + @plaid_account.update!(raw_holdings_payload: test_investments_payload) # Mock security resolver for all three securities @security_resolver.expects(:resolve) @@ -175,7 +175,7 @@ class PlaidAccount::Investments::HoldingsProcessorTest < ActiveSupport::TestCase transactions: [] } - @plaid_account.update!(raw_investments_payload: test_investments_payload) + @plaid_account.update!(raw_holdings_payload: test_investments_payload) # First security fails to resolve @security_resolver.expects(:resolve) @@ -213,7 +213,7 @@ class PlaidAccount::Investments::HoldingsProcessorTest < ActiveSupport::TestCase transactions: [] } - @plaid_account.update!(raw_investments_payload: test_investments_payload) + @plaid_account.update!(raw_holdings_payload: test_investments_payload) @security_resolver.expects(:resolve) .with(plaid_security_id: "string_values") @@ -264,7 +264,7 @@ class PlaidAccount::Investments::HoldingsProcessorTest < ActiveSupport::TestCase transactions: [] } - @plaid_account.update!(raw_investments_payload: test_investments_payload) + @plaid_account.update!(raw_holdings_payload: test_investments_payload) @security_resolver.expects(:resolve) .with(plaid_security_id: "missing_quantity") @@ -310,7 +310,7 @@ class PlaidAccount::Investments::HoldingsProcessorTest < ActiveSupport::TestCase transactions: [] } - @plaid_account.update!(raw_investments_payload: test_investments_payload) + @plaid_account.update!(raw_holdings_payload: test_investments_payload) @security_resolver.expects(:resolve) .with(plaid_security_id: "no_currency") diff --git a/test/models/plaid_account/investments/security_resolver_test.rb b/test/models/plaid_account/investments/security_resolver_test.rb index a32430c6f..cde26bd3b 100644 --- a/test/models/plaid_account/investments/security_resolver_test.rb +++ b/test/models/plaid_account/investments/security_resolver_test.rb @@ -11,7 +11,7 @@ class PlaidAccount::Investments::SecurityResolverTest < ActiveSupport::TestCase missing_id = "missing_security_id" # Ensure there are *no* securities that reference the missing ID - @plaid_account.update!(raw_investments_payload: { + @plaid_account.update!(raw_holdings_payload: { securities: [ { "security_id" => "some_other_id", @@ -35,7 +35,7 @@ class PlaidAccount::Investments::SecurityResolverTest < ActiveSupport::TestCase test "identifies brokerage cash plaid securities" do brokerage_cash_id = "brokerage_cash_security_id" - @plaid_account.update!(raw_investments_payload: { + @plaid_account.update!(raw_holdings_payload: { securities: [ { "security_id" => brokerage_cash_id, @@ -58,7 +58,7 @@ class PlaidAccount::Investments::SecurityResolverTest < ActiveSupport::TestCase test "identifies cash equivalent plaid securities" do mmf_security_id = "money_market_security_id" - @plaid_account.update!(raw_investments_payload: { + @plaid_account.update!(raw_holdings_payload: { securities: [ { "security_id" => mmf_security_id, @@ -87,7 +87,7 @@ class PlaidAccount::Investments::SecurityResolverTest < ActiveSupport::TestCase test "resolves normal plaid securities" do security_id = "regular_security_id" - @plaid_account.update!(raw_investments_payload: { + @plaid_account.update!(raw_holdings_payload: { securities: [ { "security_id" => security_id, diff --git a/test/models/plaid_account/investments/transactions_processor_test.rb b/test/models/plaid_account/investments/transactions_processor_test.rb index be589c513..648d22cf4 100644 --- a/test/models/plaid_account/investments/transactions_processor_test.rb +++ b/test/models/plaid_account/investments/transactions_processor_test.rb @@ -23,7 +23,7 @@ class PlaidAccount::Investments::TransactionsProcessorTest < ActiveSupport::Test ] } - @plaid_account.update!(raw_investments_payload: test_investments_payload) + @plaid_account.update!(raw_holdings_payload: test_investments_payload) @security_resolver.stubs(:resolve).returns(OpenStruct.new( security: securities(:aapl) @@ -58,7 +58,7 @@ class PlaidAccount::Investments::TransactionsProcessorTest < ActiveSupport::Test ] } - @plaid_account.update!(raw_investments_payload: test_investments_payload) + @plaid_account.update!(raw_holdings_payload: test_investments_payload) @security_resolver.expects(:resolve).never # Cash transactions don't have a security @@ -91,7 +91,7 @@ class PlaidAccount::Investments::TransactionsProcessorTest < ActiveSupport::Test ] } - @plaid_account.update!(raw_investments_payload: test_investments_payload) + @plaid_account.update!(raw_holdings_payload: test_investments_payload) @security_resolver.expects(:resolve).never # Cash transactions don't have a security @@ -127,7 +127,7 @@ class PlaidAccount::Investments::TransactionsProcessorTest < ActiveSupport::Test ] } - @plaid_account.update!(raw_investments_payload: test_investments_payload) + @plaid_account.update!(raw_holdings_payload: test_investments_payload) @security_resolver.expects(:resolve).returns(OpenStruct.new( security: securities(:aapl) @@ -163,7 +163,7 @@ class PlaidAccount::Investments::TransactionsProcessorTest < ActiveSupport::Test ] } - @plaid_account.update!(raw_investments_payload: test_investments_payload) + @plaid_account.update!(raw_holdings_payload: test_investments_payload) @security_resolver.expects(:resolve).never