Skip to content
This repository was archived by the owner on Jul 27, 2025. It is now read-only.

Commit fa02480

Browse files
authored
Show UI warning to user when they need provider data but have not setup Synth yet (#1926)
* Simplify provider concerns * Update tests * Add UI warning for missing Synth key if family requires external data
1 parent 624faa1 commit fa02480

File tree

22 files changed

+182
-134
lines changed

22 files changed

+182
-134
lines changed

app/controllers/securities_controller.rb

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,7 @@ def index
33
query = params[:q]
44
return render json: [] if query.blank? || query.length < 2 || query.length > 100
55

6-
@securities = Security.search({
6+
@securities = Security.search_provider({
77
search: query,
88
country: params[:country_code] == "US" ? "US" : nil
99
})

app/jobs/fetch_security_info_job.rb

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,7 @@ class FetchSecurityInfoJob < ApplicationJob
22
queue_as :latency_low
33

44
def perform(security_id)
5-
return unless Security.security_info_provider.present?
5+
return unless Security.provider.present?
66

77
security = Security.find(security_id)
88

@@ -12,7 +12,7 @@ def perform(security_id)
1212
params[:mic_code] = security.exchange_mic if security.exchange_mic.present?
1313
params[:operating_mic] = security.exchange_operating_mic if security.exchange_operating_mic.present?
1414

15-
security_info_response = Security.security_info_provider.fetch_security_info(**params)
15+
security_info_response = Security.provider.fetch_security_info(**params)
1616

1717
security.update(
1818
name: security_info_response.info.dig("name")

app/models/account/data_enricher.rb

Lines changed: 1 addition & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,4 @@
11
class Account::DataEnricher
2-
include Providable
3-
42
attr_reader :account
53

64
def initialize(account)
@@ -37,7 +35,7 @@ def enrich_transaction_batch(batch_size = 50, offset = 0)
3735

3836
candidates.each do |entry|
3937
begin
40-
info = self.class.synth_provider.enrich_transaction(entry.name).info
38+
info = entry.fetch_enrichment_info
4139

4240
next unless info.present?
4341

app/models/account/entry.rb

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
class Account::Entry < ApplicationRecord
2-
include Monetizable
2+
include Monetizable, Provided
33

44
monetize :amount
55

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,11 @@
1+
module Account::Entry::Provided
2+
extend ActiveSupport::Concern
3+
4+
include Synthable
5+
6+
def fetch_enrichment_info
7+
return nil unless synth_client.present?
8+
9+
synth_client.enrich_transaction(name).info
10+
end
11+
end

app/models/concerns/providable.rb

Lines changed: 0 additions & 35 deletions
This file was deleted.

app/models/concerns/synthable.rb

Lines changed: 37 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,37 @@
1+
module Synthable
2+
extend ActiveSupport::Concern
3+
4+
class_methods do
5+
def synth_usage
6+
synth_client&.usage
7+
end
8+
9+
def synth_overage?
10+
synth_usage&.usage&.utilization.to_i >= 100
11+
end
12+
13+
def synth_healthy?
14+
synth_client&.healthy?
15+
end
16+
17+
def synth_client
18+
api_key = ENV.fetch("SYNTH_API_KEY", Setting.synth_api_key)
19+
20+
return nil unless api_key.present?
21+
22+
Provider::Synth.new(api_key)
23+
end
24+
end
25+
26+
def synth_client
27+
self.class.synth_client
28+
end
29+
30+
def synth_usage
31+
self.class.synth_usage
32+
end
33+
34+
def synth_overage?
35+
self.class.synth_overage?
36+
end
37+
end

app/models/exchange_rate/provided.rb

Lines changed: 7 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -1,19 +1,18 @@
11
module ExchangeRate::Provided
22
extend ActiveSupport::Concern
33

4-
include Providable
4+
include Synthable
55

66
class_methods do
7-
def provider_healthy?
8-
exchange_rates_provider.present? && exchange_rates_provider.healthy?
7+
def provider
8+
synth_client
99
end
1010

1111
private
12-
1312
def fetch_rates_from_provider(from:, to:, start_date:, end_date: Date.current, cache: false)
14-
return [] unless exchange_rates_provider.present?
13+
return [] unless provider.present?
1514

16-
response = exchange_rates_provider.fetch_exchange_rates \
15+
response = provider.fetch_exchange_rates \
1716
from: from,
1817
to: to,
1918
start_date: start_date,
@@ -38,9 +37,9 @@ def fetch_rates_from_provider(from:, to:, start_date:, end_date: Date.current, c
3837
end
3938

4039
def fetch_rate_from_provider(from:, to:, date:, cache: false)
41-
return nil unless exchange_rates_provider.present?
40+
return nil unless provider.present?
4241

43-
response = exchange_rates_provider.fetch_exchange_rate \
42+
response = provider.fetch_exchange_rate \
4443
from: from,
4544
to: to,
4645
date: date

app/models/family.rb

Lines changed: 14 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
class Family < ApplicationRecord
2-
include Providable, Plaidable, Syncable, AutoTransferMatchable
2+
include Synthable, Plaidable, Syncable, AutoTransferMatchable
33

44
DATE_FORMATS = [
55
[ "MM-DD-YYYY", "%m-%d-%Y" ],
@@ -92,20 +92,23 @@ def get_link_token(webhooks_url:, redirect_url:, accountable_type: nil, region:
9292
).link_token
9393
end
9494

95-
def synth_usage
96-
self.class.synth_provider&.usage
95+
def subscribed?
96+
stripe_subscription_status == "active"
9797
end
9898

99-
def synth_overage?
100-
self.class.synth_provider&.usage&.utilization.to_i >= 100
101-
end
99+
def requires_data_provider?
100+
# If family has any trades, they need a provider for historical prices
101+
return true if trades.any?
102102

103-
def synth_valid?
104-
self.class.synth_provider&.healthy?
105-
end
103+
# If family has any accounts not denominated in the family's currency, they need a provider for historical exchange rates
104+
return true if accounts.where.not(currency: self.currency).any?
106105

107-
def subscribed?
108-
stripe_subscription_status == "active"
106+
# If family has any entries in different currencies, they need a provider for historical exchange rates
107+
uniq_currencies = entries.pluck(:currency).uniq
108+
return true if uniq_currencies.count > 1
109+
return true if uniq_currencies.first != self.currency
110+
111+
false
109112
end
110113

111114
def primary_user

app/models/security.rb

Lines changed: 1 addition & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
class Security < ApplicationRecord
2-
include Providable
2+
include Provided
33

44
before_save :upcase_ticker
55

@@ -9,21 +9,6 @@ class Security < ApplicationRecord
99
validates :ticker, presence: true
1010
validates :ticker, uniqueness: { scope: :exchange_operating_mic, case_sensitive: false }
1111

12-
class << self
13-
def provider
14-
security_prices_provider
15-
end
16-
17-
def search(query)
18-
security_prices_provider.search_securities(
19-
query: query[:search],
20-
dataset: "limited",
21-
country_code: query[:country],
22-
exchange_operating_mic: query[:exchange_operating_mic]
23-
).securities.map { |attrs| new(**attrs) }
24-
end
25-
end
26-
2712
def current_price
2813
@current_price ||= Security::Price.find_price(security: self, date: Date.current)
2914
return nil if @current_price.nil?

0 commit comments

Comments
 (0)