1
0
Fork 0
mirror of https://github.com/maybe-finance/maybe.git synced 2025-08-09 07:25:19 +02:00

Sync broadcasters

This commit is contained in:
Zach Gollwitzer 2025-05-15 09:43:55 -04:00
parent 37d32e47a4
commit a4eae6a9c7
10 changed files with 121 additions and 53 deletions

View file

@ -0,0 +1,54 @@
class Account::SyncCompleteEvent
attr_reader :account
def initialize(account)
@account = account
end
def broadcast
# Refresh entire account page (only applies if currently viewing this account)
account.broadcast_refresh
# Replace account row in accounts list
account.broadcast_replace_to(
account.family,
target: "account_#{account.id}",
partial: "accounts/account",
locals: { account: account }
)
# Replace the groups this account belongs to in the sidebar
account_group_ids.each do |id|
account.broadcast_replace_to(
account.family,
target: id,
partial: "accounts/accountable_group",
locals: { account_group: account_group, open: true }
)
end
# If this is a manual, unlinked account (i.e. not part of a Plaid Item),
# trigger the family sync complete broadcast so net worth graph is updated
unless account.linked?
account.family.broadcast_sync_complete
end
end
private
# The sidebar will show the account in both its classification tab and the "all" tab,
# so we need to broadcast to both.
def account_group_ids
id = account_group.id
[ id, "#{account_group.classification}_#{id}" ]
end
def account_group
family_balance_sheet.account_groups.find do |group|
group.accounts.any? { |a| a.id == account.id }
end
end
def family_balance_sheet
account.family.balance_sheet
end
end

View file

@ -12,14 +12,6 @@ class Account::Syncer
def perform_post_sync def perform_post_sync
account.family.auto_match_transfers! account.family.auto_match_transfers!
account.broadcast_refresh
SyncCompleteEvent.new(account.family, accounts: [ account ]).broadcast
account.broadcast_replace_to(
account.family,
target: "account_#{account.id}",
partial: "accounts/account",
locals: { account: account }
)
end end
private private

View file

@ -22,6 +22,10 @@ module Syncable
syncer.perform_post_sync syncer.perform_post_sync
end end
def broadcast_sync_complete
sync_broadcaster.broadcast
end
def sync_error def sync_error
latest_sync&.error latest_sync&.error
end end
@ -42,4 +46,8 @@ module Syncable
def syncer def syncer
self.class::Syncer.new(self) self.class::Syncer.new(self)
end end
def sync_broadcaster
self.class::SyncCompleteEvent.new(self)
end
end end

View file

@ -0,0 +1,21 @@
class Family::SyncCompleteEvent
attr_reader :family
def initialize(family)
@family = family
end
def broadcast
family.broadcast_replace(
target: "balance-sheet",
partial: "pages/dashboard/balance_sheet",
locals: { balance_sheet: family.balance_sheet }
)
family.broadcast_replace(
target: "net-worth-chart",
partial: "pages/dashboard/net_worth_chart",
locals: { balance_sheet: family.balance_sheet, period: Period.last_30_days }
)
end
end

View file

@ -22,7 +22,6 @@ class Family::Syncer
def perform_post_sync def perform_post_sync
family.auto_match_transfers! family.auto_match_transfers!
family.broadcast_refresh
end end
private private

View file

@ -0,0 +1,22 @@
class PlaidItem::SyncCompleteEvent
attr_reader :plaid_item
def initialize(plaid_item)
@plaid_item = plaid_item
end
def broadcast
plaid_item.accounts.each do |account|
account.broadcast_sync_complete
end
plaid_item.broadcast_replace_to(
plaid_item.family,
target: "plaid_item_#{plaid_item.id}",
partial: "plaid_items/plaid_item",
locals: { plaid_item: plaid_item }
)
plaid_item.family.broadcast_sync_complete
end
end

View file

@ -24,13 +24,6 @@ class PlaidItem::Syncer
def perform_post_sync def perform_post_sync
plaid_item.auto_match_categories! plaid_item.auto_match_categories!
SyncCompleteEvent.new(plaid_item.family, accounts: plaid_item.accounts).broadcast
plaid_item.broadcast_replace_to(
plaid_item.family,
target: "plaid_item_#{plaid_item.id}",
partial: "plaid_items/plaid_item",
locals: { plaid_item: plaid_item }
)
end end
private private

View file

@ -39,6 +39,8 @@ class Sync < ApplicationRecord
Rails.logger.tagged("Sync", id, syncable_type, syncable_id) do Rails.logger.tagged("Sync", id, syncable_type, syncable_id) do
start! start!
sleep 10
begin begin
syncable.perform_sync(self) syncable.perform_sync(self)
rescue => e rescue => e
@ -89,8 +91,11 @@ class Sync < ApplicationRecord
end end
def perform_post_sync def perform_post_sync
Rails.logger.info("Performing post-sync for #{syncable_type} (#{syncable.id})")
syncable.perform_post_sync syncable.perform_post_sync
syncable.broadcast_sync_complete
rescue => e rescue => e
Rails.logger.error("Error performing post-sync for #{syncable_type} (#{syncable.id}): #{e.message}")
report_error(e) report_error(e)
end end

View file

@ -1,37 +0,0 @@
class SyncCompleteEvent
attr_reader :family, :accounts
def initialize(family, accounts: [])
@family = family
@accounts = accounts
end
def broadcast
account_groups = family.balance_sheet.account_groups.select do |group|
group.accounts.any? { |a| accounts.include?(a) }
end
account_groups.each do |account_group|
[ nil, "asset", "liability" ].each do |classification|
id = classification ? "#{classification}_#{account_group.id}" : account_group.id
family.broadcast_replace(
target: id,
partial: "accounts/accountable_group",
locals: { account_group: account_group, open: true }
)
end
end
family.broadcast_replace(
target: "balance-sheet",
partial: "pages/dashboard/balance_sheet",
locals: { balance_sheet: family.balance_sheet }
)
family.broadcast_replace(
target: "net-worth-chart",
partial: "pages/dashboard/net_worth_chart",
locals: { balance_sheet: family.balance_sheet, period: Period.last_30_days }
)
end
end

View file

@ -63,8 +63,11 @@ class SyncTest < ActiveSupport::TestCase
# Since these are accessed through `parent`, they won't necessarily be the same # Since these are accessed through `parent`, they won't necessarily be the same
# instance we configured above # instance we configured above
Account.any_instance.expects(:perform_post_sync).once Account.any_instance.expects(:perform_post_sync).once
Account.any_instance.expects(:broadcast_sync_complete).once
PlaidItem.any_instance.expects(:perform_post_sync).once PlaidItem.any_instance.expects(:perform_post_sync).once
PlaidItem.any_instance.expects(:broadcast_sync_complete).once
Family.any_instance.expects(:perform_post_sync).once Family.any_instance.expects(:perform_post_sync).once
Family.any_instance.expects(:broadcast_sync_complete).once
account_sync.perform account_sync.perform
@ -108,6 +111,10 @@ class SyncTest < ActiveSupport::TestCase
PlaidItem.any_instance.expects(:perform_post_sync).once PlaidItem.any_instance.expects(:perform_post_sync).once
Family.any_instance.expects(:perform_post_sync).once Family.any_instance.expects(:perform_post_sync).once
Account.any_instance.expects(:broadcast_sync_complete).once
PlaidItem.any_instance.expects(:broadcast_sync_complete).once
Family.any_instance.expects(:broadcast_sync_complete).once
account_sync.perform account_sync.perform
assert_equal "failed", plaid_item_sync.reload.status assert_equal "failed", plaid_item_sync.reload.status
@ -150,6 +157,10 @@ class SyncTest < ActiveSupport::TestCase
PlaidItem.any_instance.expects(:perform_post_sync).once PlaidItem.any_instance.expects(:perform_post_sync).once
Family.any_instance.expects(:perform_post_sync).once Family.any_instance.expects(:perform_post_sync).once
Account.any_instance.expects(:broadcast_sync_complete).once
PlaidItem.any_instance.expects(:broadcast_sync_complete).once
Family.any_instance.expects(:broadcast_sync_complete).once
account_sync.perform account_sync.perform
assert_equal "failed", plaid_item_sync.reload.status assert_equal "failed", plaid_item_sync.reload.status