diff --git a/app/controllers/accounts_controller.rb b/app/controllers/accounts_controller.rb index 20d31811c..a50f60137 100644 --- a/app/controllers/accounts_controller.rb +++ b/app/controllers/accounts_controller.rb @@ -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 diff --git a/app/controllers/wise_items_controller.rb b/app/controllers/wise_items_controller.rb index d3373aa69..3fb7f5035 100644 --- a/app/controllers/wise_items_controller.rb +++ b/app/controllers/wise_items_controller.rb @@ -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) diff --git a/app/models/wise_activity/processor.rb b/app/models/wise_activity/processor.rb index eddc191a1..e58d5c9df 100644 --- a/app/models/wise_activity/processor.rb +++ b/app/models/wise_activity/processor.rb @@ -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 diff --git a/app/models/wise_entry/processor.rb b/app/models/wise_entry/processor.rb index 5e5648bea..8bd42a92e 100644 --- a/app/models/wise_entry/processor.rb +++ b/app/models/wise_entry/processor.rb @@ -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, diff --git a/app/models/wise_item/unlinking.rb b/app/models/wise_item/unlinking.rb index 41132f7df..1634b74c9 100644 --- a/app/models/wise_item/unlinking.rb +++ b/app/models/wise_item/unlinking.rb @@ -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 diff --git a/app/views/accounts/index.html.erb b/app/views/accounts/index.html.erb index fb3fe4395..4d7f161b8 100644 --- a/app/views/accounts/index.html.erb +++ b/app/views/accounts/index.html.erb @@ -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 %>
WI
+WI