mirror of
https://github.com/we-promise/sure.git
synced 2026-04-18 03:24:09 +00:00
Fix Broken Account Re-linking Feature (#469)
* Update SimpleFIN relinking flow and enhance duplicate account handling - Updated logic to allow relinking of SimpleFIN accounts while preserving legacy mappings. - Introduced clean-up logic to hide orphaned duplicate accounts after relinking. - Enhanced UI to display current mappings for linked accounts. - Improved test coverage for relinking scenarios and SimpleFIN account visibility. * Localize SimpleFIN account selection messages and remove hardcoded text - Added translations for user-facing messages in `select_existing_account` flow (`pt-BR` and `en` locales). - Replaced hardcoded strings in the view with localized keys. * Localize Enable Banking and SimpleFIN account linking messages; add support for investment accounts. - Added translations for Enable Banking and SimpleFIN account linking flows. - Updated views and controllers to replace hardcoded strings with localized keys. - Introduced support for investment accounts in `Provider::LunchflowAdapter`. - Enhanced relinking logic for SimpleFIN accounts and improved test coverage for related scenarios. --------- Co-authored-by: Josh Waldrep <joshua.waldrep5+github@gmail.com>
This commit is contained in:
@@ -323,12 +323,20 @@ class SimplefinItemsController < ApplicationController
|
||||
def select_existing_account
|
||||
@account = Current.family.accounts.find(params[:account_id])
|
||||
|
||||
# Filter out SimpleFIN accounts that are already linked to any account
|
||||
# (either via account_provider or legacy account association)
|
||||
# Allow explicit relinking by listing all available SimpleFIN accounts for the family.
|
||||
# The UI will surface the current mapping (if any), and the action will move the link.
|
||||
@available_simplefin_accounts = Current.family.simplefin_items
|
||||
.includes(:simplefin_accounts)
|
||||
.includes(simplefin_accounts: [ :account, { account_provider: :account } ])
|
||||
.flat_map(&:simplefin_accounts)
|
||||
.reject { |sfa| sfa.account_provider.present? || sfa.account.present? }
|
||||
# After provider setup, SFAs may already have an AccountProvider (linked to the freshly
|
||||
# created duplicate accounts). During relink, we need to show those SFAs until the legacy
|
||||
# link (`Account.simplefin_account_id`) has been cleared.
|
||||
#
|
||||
# Eligibility rule:
|
||||
# - Show SFAs that are still legacy-linked (`sfa.account.present?`) => candidates to move.
|
||||
# - Show SFAs that are fully unlinked (no legacy account and no account_provider) => candidates to link.
|
||||
# - Hide SFAs that are linked via AccountProvider but no longer legacy-linked => already relinked.
|
||||
.select { |sfa| sfa.account.present? || sfa.account_provider.nil? }
|
||||
.sort_by { |sfa| sfa.updated_at || sfa.created_at }
|
||||
.reverse
|
||||
|
||||
@@ -342,7 +350,7 @@ class SimplefinItemsController < ApplicationController
|
||||
|
||||
# Guard: only manual accounts can be linked (no existing provider links or legacy IDs)
|
||||
if @account.account_providers.any? || @account.plaid_account_id.present? || @account.simplefin_account_id.present?
|
||||
flash[:alert] = "Only manual accounts can be linked"
|
||||
flash[:alert] = t("simplefin_items.link_existing_account.errors.only_manual")
|
||||
if turbo_frame_request?
|
||||
return render turbo_stream: Array(flash_notification_stream_items)
|
||||
else
|
||||
@@ -352,7 +360,7 @@ class SimplefinItemsController < ApplicationController
|
||||
|
||||
# Verify the SimpleFIN account belongs to this family's SimpleFIN items
|
||||
unless Current.family.simplefin_items.include?(simplefin_account.simplefin_item)
|
||||
flash[:alert] = "Invalid SimpleFIN account selected"
|
||||
flash[:alert] = t("simplefin_items.link_existing_account.errors.invalid_simplefin_account")
|
||||
if turbo_frame_request?
|
||||
render turbo_stream: Array(flash_notification_stream_items)
|
||||
else
|
||||
@@ -364,9 +372,10 @@ class SimplefinItemsController < ApplicationController
|
||||
# Relink behavior: detach any legacy link and point provider link at the chosen account
|
||||
Account.transaction do
|
||||
simplefin_account.lock!
|
||||
# Clear legacy association if present
|
||||
if simplefin_account.account_id.present?
|
||||
simplefin_account.update!(account_id: nil)
|
||||
|
||||
# Clear legacy association if present (Account.simplefin_account_id)
|
||||
if (legacy_account = simplefin_account.account)
|
||||
legacy_account.update!(simplefin_account_id: nil)
|
||||
end
|
||||
|
||||
# Upsert the AccountProvider mapping deterministically
|
||||
@@ -382,9 +391,13 @@ class SimplefinItemsController < ApplicationController
|
||||
if previous_account && previous_account.id != @account.id && previous_account.family_id == @account.family_id
|
||||
begin
|
||||
previous_account.reload
|
||||
# Only disable if the previous account is truly orphaned (no other provider links)
|
||||
# Only hide if the previous account is truly orphaned (no other provider links)
|
||||
if previous_account.account_providers.none?
|
||||
previous_account.disable!
|
||||
# Disabled accounts still appear (greyed-out) in the manual list; for relink
|
||||
# consolidation we want the duplicate to disappear from the UI.
|
||||
# Use the app's standard deletion path (async) so the "pending_deletion" state
|
||||
# remains truthful in the UI.
|
||||
previous_account.destroy_later if previous_account.may_mark_for_deletion?
|
||||
else
|
||||
Rails.logger.info("Skipped disabling account ##{previous_account.id} after relink because it still has active provider links")
|
||||
end
|
||||
@@ -410,7 +423,7 @@ class SimplefinItemsController < ApplicationController
|
||||
@simplefin_items = Current.family.simplefin_items.ordered.includes(:syncs)
|
||||
build_simplefin_maps_for(@simplefin_items)
|
||||
|
||||
flash[:notice] = "Account successfully linked to SimpleFIN"
|
||||
flash[:notice] = t("simplefin_items.link_existing_account.success")
|
||||
@account.reload
|
||||
manual_accounts_stream = if @manual_accounts.any?
|
||||
turbo_stream.update(
|
||||
@@ -434,7 +447,7 @@ class SimplefinItemsController < ApplicationController
|
||||
turbo_stream.replace("modal", view_context.turbo_frame_tag("modal"))
|
||||
] + Array(flash_notification_stream_items)
|
||||
else
|
||||
redirect_to accounts_path(cache_bust: SecureRandom.hex(6)), notice: "Account successfully linked to SimpleFIN", status: :see_other
|
||||
redirect_to accounts_path(cache_bust: SecureRandom.hex(6)), notice: t("simplefin_items.link_existing_account.success"), status: :see_other
|
||||
end
|
||||
end
|
||||
|
||||
|
||||
Reference in New Issue
Block a user