mirror of
https://github.com/we-promise/sure.git
synced 2026-07-16 23:05:22 +00:00
fix(wise): address PR #2433 review feedback
- Wire @wise_items into AccountsController#index so linked accounts appear on /accounts - Fix find_wise_account_for_linking to preserve .active scope via .merge instead of .then - Fix cross-currency incoming transfer amount to use targetValue instead of sourceValue - Add missing select_profiles.session_expired locale key - Add missing account_name interpolation to link_existing_account success notice - Use i18n for profile type labels in profile_display_name - Trigger wise_item.sync_later after account linking in all three linking actions - Isolate fee transaction failure so it no longer aborts the main transfer import - Use bare raise in WiseActivity/WiseEntry processors to preserve original backtrace - Re-raise in WiseItem::Unlinking to prevent silently orphaned Holdings - Fix avatar badge to use design system tokens (bg-container-inset, text-primary)
This commit is contained in:
@@ -28,6 +28,7 @@ class AccountsController < ApplicationController
|
||||
@sophtron_items = visible_provider_items(family.sophtron_items.ordered.includes(:syncs, :sophtron_accounts))
|
||||
@binance_items = visible_provider_items(family.binance_items.ordered.includes(:binance_accounts, :accounts, :syncs))
|
||||
@questrade_items = visible_provider_items(family.questrade_items.ordered.includes(:syncs, questrade_accounts: :account_provider))
|
||||
@wise_items = visible_provider_items(family.wise_items.ordered.includes(:syncs, :wise_accounts))
|
||||
|
||||
# Build sync stats maps for all providers
|
||||
build_sync_stats_maps
|
||||
@@ -451,5 +452,12 @@ class AccountsController < ApplicationController
|
||||
linked: linked, unlinked: accounts.size - linked, total: accounts.size
|
||||
}
|
||||
end
|
||||
|
||||
# Wise sync stats
|
||||
@wise_sync_stats_map = {}
|
||||
@wise_items.each do |item|
|
||||
latest_sync = item.syncs.ordered.first
|
||||
@wise_sync_stats_map[item.id] = latest_sync&.sync_stats || {}
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
@@ -145,6 +145,8 @@ class WiseItemsController < ApplicationController
|
||||
provider: wise_account
|
||||
)
|
||||
|
||||
@wise_item.sync_later unless @wise_item.syncing?
|
||||
|
||||
redirect_to accounts_path, notice: t(".success")
|
||||
rescue => e
|
||||
Rails.logger.error "WiseItemsController#complete_account_setup - #{e.class}: #{e.message}"
|
||||
@@ -176,6 +178,7 @@ class WiseItemsController < ApplicationController
|
||||
|
||||
account = Account.create_from_wise_account(wise_account)
|
||||
AccountProvider.create!(account: account, provider: wise_account)
|
||||
wise_account.wise_item.sync_later unless wise_account.wise_item.syncing?
|
||||
|
||||
redirect_to safe_return_to_path || accounts_path, notice: t("wise_items.link_accounts.success")
|
||||
rescue => e
|
||||
@@ -206,8 +209,9 @@ class WiseItemsController < ApplicationController
|
||||
end
|
||||
|
||||
AccountProvider.create!(account: account, provider: wise_account)
|
||||
wise_account.wise_item.sync_later unless wise_account.wise_item.syncing?
|
||||
|
||||
redirect_to safe_return_to_path || accounts_path, notice: t("wise_items.link_existing_account.success")
|
||||
redirect_to safe_return_to_path || accounts_path, notice: t("wise_items.link_existing_account.success", account_name: account.name)
|
||||
rescue => e
|
||||
Rails.logger.error "WiseItemsController#link_existing_account - #{e.class}: #{e.message}"
|
||||
redirect_to accounts_path, alert: t("wise_items.link_existing_account.failed")
|
||||
@@ -243,19 +247,19 @@ class WiseItemsController < ApplicationController
|
||||
def find_wise_account_for_linking(wise_account_id)
|
||||
return nil if wise_account_id.blank?
|
||||
|
||||
Current.family.wise_items.active
|
||||
.joins(:wise_accounts)
|
||||
.then { |_| WiseAccount.joins(:wise_item).where(wise_items: { family_id: Current.family.id }, id: wise_account_id) }
|
||||
.first
|
||||
WiseAccount.joins(:wise_item)
|
||||
.merge(Current.family.wise_items.active)
|
||||
.find_by(id: wise_account_id)
|
||||
end
|
||||
|
||||
def profile_display_name(profile)
|
||||
type = profile["type"] == "business" ? "Business" : "Personal"
|
||||
type_key = profile["type"] == "business" ? :business : :personal
|
||||
type_label = I18n.t("wise_items.profile_types.#{type_key}")
|
||||
details = profile["details"] || {}
|
||||
name = details["name"].presence ||
|
||||
[ details["firstName"], details["lastName"] ].compact.join(" ").presence
|
||||
|
||||
name.present? ? "#{name} (#{type})" : "Wise #{type}"
|
||||
name.present? ? "#{name} (#{type_label})" : "Wise #{type_label}"
|
||||
end
|
||||
|
||||
def render_provider_panel_success(message)
|
||||
|
||||
@@ -28,7 +28,7 @@ class WiseActivity::Processor
|
||||
raise
|
||||
rescue => e
|
||||
Rails.logger.error "WiseActivity::Processor - Error for activity #{safe_id}: #{e.class} - #{e.message}"
|
||||
raise StandardError, e.message
|
||||
raise
|
||||
end
|
||||
|
||||
private
|
||||
|
||||
@@ -25,17 +25,22 @@ class WiseEntry::Processor
|
||||
end
|
||||
|
||||
result = import_main_transaction
|
||||
import_fee_transaction if fee > 0
|
||||
|
||||
if fee > 0
|
||||
begin
|
||||
import_fee_transaction
|
||||
rescue StandardError => e
|
||||
Rails.logger.warn "WiseEntry::Processor - Fee transaction failed for transfer #{safe_id}: #{e.message}"
|
||||
end
|
||||
end
|
||||
|
||||
result
|
||||
rescue ArgumentError => e
|
||||
Rails.logger.error "WiseEntry::Processor - Validation error for transfer #{safe_id}: #{e.message}"
|
||||
raise
|
||||
rescue ActiveRecord::RecordInvalid, ActiveRecord::RecordNotSaved => e
|
||||
Rails.logger.error "WiseEntry::Processor - Failed to save transfer #{safe_id}: #{e.message}"
|
||||
raise StandardError, "Failed to import transaction: #{e.message}"
|
||||
rescue => e
|
||||
Rails.logger.error "WiseEntry::Processor - Unexpected error for transfer #{safe_id}: #{e.class} - #{e.message}"
|
||||
raise StandardError, "Unexpected error: #{e.message}"
|
||||
raise
|
||||
end
|
||||
|
||||
private
|
||||
@@ -93,9 +98,13 @@ class WiseEntry::Processor
|
||||
|
||||
# Expenses (outgoing) → positive amount in Sure convention.
|
||||
# Incomes (incoming) → negative amount in Sure convention.
|
||||
# Incoming cross-currency transfers use targetValue (what actually arrived) not sourceValue.
|
||||
def main_amount
|
||||
value = data[:sourceValue].to_d.abs
|
||||
outgoing? ? value : -value
|
||||
if outgoing?
|
||||
data[:sourceValue].to_d.abs
|
||||
else
|
||||
-(data[:targetValue].to_d.abs)
|
||||
end
|
||||
end
|
||||
|
||||
# Fee is the difference between what was debited and what the recipient received,
|
||||
|
||||
@@ -31,6 +31,7 @@ module WiseItem::Unlinking
|
||||
"WiseItem Unlinker: failed to fully unlink provider account ##{provider_account.id} (links=#{link_ids.inspect}): #{e.class} - #{e.message}"
|
||||
)
|
||||
result[:error] = e.message
|
||||
raise
|
||||
end
|
||||
end
|
||||
|
||||
|
||||
@@ -17,7 +17,7 @@
|
||||
) %>
|
||||
<% end %>
|
||||
|
||||
<% if @manual_accounts.empty? && @plaid_items.empty? && @simplefin_items.empty? && @lunchflow_items.empty? && @akahu_items.empty? && @up_items.empty? && @enable_banking_items.empty? && @coinstats_items.empty? && @coinbase_items.empty? && @mercury_items.empty? && @brex_items.empty? && @ibkr_items.empty? && @snaptrade_items.empty? && @indexa_capital_items.empty? && @sophtron_items.empty? && @binance_items.empty? && @questrade_items.empty? %>
|
||||
<% if @manual_accounts.empty? && @plaid_items.empty? && @simplefin_items.empty? && @lunchflow_items.empty? && @akahu_items.empty? && @up_items.empty? && @enable_banking_items.empty? && @coinstats_items.empty? && @coinbase_items.empty? && @mercury_items.empty? && @brex_items.empty? && @ibkr_items.empty? && @snaptrade_items.empty? && @indexa_capital_items.empty? && @sophtron_items.empty? && @binance_items.empty? && @questrade_items.empty? && @wise_items.empty? %>
|
||||
<%= render "empty" %>
|
||||
<% else %>
|
||||
<div class="space-y-2">
|
||||
@@ -69,6 +69,10 @@
|
||||
<%= render @binance_items.sort_by(&:created_at) %>
|
||||
<% end %>
|
||||
|
||||
<% if @wise_items.any? %>
|
||||
<%= render @wise_items.sort_by(&:created_at) %>
|
||||
<% end %>
|
||||
|
||||
<% if @snaptrade_items.any? %>
|
||||
<%= render @snaptrade_items.sort_by(&:created_at) %>
|
||||
<% end %>
|
||||
|
||||
@@ -7,8 +7,8 @@
|
||||
<div class="flex items-center gap-2">
|
||||
<%= icon "chevron-right", class: "group-open:rotate-90 motion-safe:transition-transform motion-safe:duration-150" %>
|
||||
|
||||
<div class="flex items-center justify-center h-8 w-8 bg-green-500 rounded-full">
|
||||
<p class="text-white text-xs font-bold">WI</p>
|
||||
<div class="flex items-center justify-center h-8 w-8 bg-container-inset rounded-full">
|
||||
<p class="text-primary text-xs font-bold">WI</p>
|
||||
</div>
|
||||
|
||||
<div class="pl-1 text-sm">
|
||||
|
||||
@@ -93,6 +93,7 @@ en:
|
||||
one: "Successfully connected %{count} Wise profile"
|
||||
other: "Successfully connected %{count} Wise profiles"
|
||||
select_profiles:
|
||||
session_expired: Session expired. Please try connecting again.
|
||||
title: Select Wise Profiles
|
||||
subtitle: Choose which profiles to connect
|
||||
description: Your Wise account has multiple profiles. Select the ones you want to sync with Sure.
|
||||
|
||||
Reference in New Issue
Block a user