Files
sure/test/system/trades_test.rb
LPW c504ba9b99 Add security remapping for holdings with sync protection (#692)
* Add security remapping support to holdings

- Introduced `provider_security` tracking for holdings with schema updates.
- Implemented security remap/reset workflows in `Holding` model and UI.
- Updated routes, controllers, and tests to support new functionality.
- Enhanced client-side interaction with Stimulus controller for remapping.

# Conflicts:
#	app/components/UI/account/activity_feed.html.erb
#	db/schema.rb

* Refactor "New transaction" to "New activity" across UI and tests

- Updated localized strings, button labels, and ARIA attributes.
- Improved error handling in holdings' current price display.
- Scoped fallback queries in `provider_import_adapter` to prevent overwrites.
- Added safeguard for offline securities in price fetching logic.

* Update security remapping to merge holdings on collision by deleting duplicates

- Removed error handling for collisions in `remap_security!`.
- Added logic to merge holdings by deleting duplicates on conflicting dates.
- Modified associated test to validate merging behavior.

* Update security remapping to merge holdings on collision by combining qty and amount

- Modified `remap_security!` to merge holdings by summing `qty` and `amount` on conflicting dates.
- Adjusted logic to calculate `price` for merged holdings.
- Updated test to validate new merge behavior.

* Improve DOM handling in Turbo redirect action & enhance holdings merge logic

- Updated Turbo's custom `redirect` action to use the "replace" option for cleaner DOM updates without clearing the cache.
- Enhanced holdings merge logic to calculate weighted average cost basis during security remapping, ensuring more accurate cost_basis updates.

* Track provider_security_id during security updates to support reset workflows

* Fix provider tracking: guard nil ticker lookups and preserve merge attrs

- Guard fallback 1b lookup when security.ticker is blank to avoid matching NULL tickers
- Preserve external_id, provider_security_id, account_provider_id during collision merge

* Fix schema.rb version after merge (includes tax_treatment migration)

* fix: Rename migration to run after schema version

The migration 20260117000001 was skipped in CI because it had a timestamp
earlier than the schema version (2026_01_17_200000). CI loads schema.rb
directly and only runs migrations with versions after the schema version.

Renamed to 20260119000001 so it runs correctly.

* Update schema: remove Coinbase tables, add new fields and indexes

* Update schema: add back `tax_treatment` field with default value "taxable"

* Improve Turbo redirect action: use "replace" to avoid form submission in history

* Lock merged holdings to prevent provider overwrites and fix activity feed template indentation

* Refactor holdings transfer logic: enforce currency checks during collisions and enhance merge handling

---------

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>
2026-01-23 12:54:55 +01:00

76 lines
1.6 KiB
Ruby

require "application_system_test_case"
class TradesTest < ApplicationSystemTestCase
include ActiveJob::TestHelper
setup do
sign_in @user = users(:family_admin)
@user.update!(show_sidebar: false, show_ai_sidebar: false)
@account = accounts(:investment)
visit_account_portfolio
# Disable provider to focus on form testing
Security.stubs(:provider).returns(nil)
end
test "can create buy transaction" do
shares_qty = 25
open_new_trade_modal
fill_in "Ticker symbol", with: "AAPL"
fill_in "Date", with: Date.current
fill_in "Quantity", with: shares_qty
fill_in "model[price]", with: 214.23
click_button "Add transaction"
visit_trades
within_trades do
assert_text "Buy #{shares_qty}.0 shares of AAPL"
end
end
test "can create sell transaction" do
qty = 10
aapl = @account.holdings.find { |h| h.security.ticker == "AAPL" }
open_new_trade_modal
select "Sell", from: "Type"
fill_in "Ticker symbol", with: "AAPL"
fill_in "Date", with: Date.current
fill_in "Quantity", with: qty
fill_in "model[price]", with: 215.33
click_button "Add transaction"
visit_trades
within_trades do
assert_text "Sell #{qty}.0 shares of AAPL"
end
end
private
def open_new_trade_modal
click_on "New activity"
end
def within_trades(&block)
within "#" + dom_id(@account, "entries"), &block
end
def visit_trades
visit account_path(@account, tab: "activity")
end
def visit_account_portfolio
visit account_path(@account, tab: "holdings")
end
end