mirror of
https://github.com/maybe-finance/maybe.git
synced 2025-08-02 20:15:22 +02:00
parent
4bf72506d5
commit
53f4b32c33
19 changed files with 91 additions and 86 deletions
|
@ -11,7 +11,7 @@ class Account::BalanceCalculator
|
|||
holdings_value = converted_holdings.select { |h| h.date == balance.date }.sum(&:amount)
|
||||
balance.balance = balance.balance + holdings_value
|
||||
balance
|
||||
end
|
||||
end.compact
|
||||
end
|
||||
|
||||
private
|
||||
|
|
|
@ -76,29 +76,33 @@ class Account::Syncer
|
|||
exchange_rates = ExchangeRate.find_rates(
|
||||
from: from_currency,
|
||||
to: to_currency,
|
||||
start_date: balances.first.date
|
||||
start_date: balances.min_by(&:date).date
|
||||
)
|
||||
|
||||
converted_balances = balances.map do |balance|
|
||||
exchange_rate = exchange_rates.find { |er| er.date == balance.date }
|
||||
|
||||
next unless exchange_rate.present?
|
||||
|
||||
account.balances.build(
|
||||
date: balance.date,
|
||||
balance: exchange_rate.rate * balance.balance,
|
||||
currency: to_currency
|
||||
) if exchange_rate.present?
|
||||
end
|
||||
)
|
||||
end.compact
|
||||
|
||||
converted_holdings = holdings.map do |holding|
|
||||
exchange_rate = exchange_rates.find { |er| er.date == holding.date }
|
||||
|
||||
next unless exchange_rate.present?
|
||||
|
||||
account.holdings.build(
|
||||
security: holding.security,
|
||||
date: holding.date,
|
||||
amount: exchange_rate.rate * holding.amount,
|
||||
currency: to_currency
|
||||
) if exchange_rate.present?
|
||||
end
|
||||
)
|
||||
end.compact
|
||||
|
||||
Account.transaction do
|
||||
load_balances(converted_balances)
|
||||
|
|
|
@ -2,22 +2,25 @@ module Plaidable
|
|||
extend ActiveSupport::Concern
|
||||
|
||||
class_methods do
|
||||
def plaid_provider
|
||||
Provider::Plaid.new if Rails.application.config.plaid
|
||||
def plaid_us_provider
|
||||
Provider::Plaid.new(Rails.application.config.plaid, :us) if Rails.application.config.plaid
|
||||
end
|
||||
|
||||
def plaid_eu_provider
|
||||
Provider::Plaid.new if Rails.application.config.plaid_eu
|
||||
Provider::Plaid.new(Rails.application.config.plaid_eu, :eu) if Rails.application.config.plaid_eu
|
||||
end
|
||||
|
||||
def plaid_provider_for(plaid_item)
|
||||
return nil unless plaid_item
|
||||
plaid_item.eu? ? plaid_eu_provider : plaid_provider
|
||||
def plaid_provider_for_region(region)
|
||||
region.to_sym == :eu ? plaid_eu_provider : plaid_us_provider
|
||||
end
|
||||
end
|
||||
|
||||
private
|
||||
def plaid_provider_for(plaid_item)
|
||||
self.class.plaid_provider_for(plaid_item)
|
||||
def eu?
|
||||
raise "eu? is not implemented for #{self.class.name}"
|
||||
end
|
||||
|
||||
def plaid_provider
|
||||
eu? ? self.class.plaid_eu_provider : self.class.plaid_us_provider
|
||||
end
|
||||
end
|
||||
|
|
|
@ -1,4 +1,3 @@
|
|||
# rubocop:disable Layout/ElseAlignment, Layout/IndentationWidth
|
||||
class Family < ApplicationRecord
|
||||
include Plaidable, Syncable
|
||||
|
||||
|
@ -48,22 +47,22 @@ class Family < ApplicationRecord
|
|||
super || accounts.manual.any?(&:syncing?) || plaid_items.any?(&:syncing?)
|
||||
end
|
||||
|
||||
def get_link_token(webhooks_url:, redirect_url:, accountable_type: nil, region: :us)
|
||||
provider = case region
|
||||
when :eu
|
||||
self.class.plaid_eu_provider
|
||||
else
|
||||
self.class.plaid_provider
|
||||
end
|
||||
def eu?
|
||||
country != "US" && country != "CA"
|
||||
end
|
||||
|
||||
return nil unless provider
|
||||
def get_link_token(webhooks_url:, redirect_url:, accountable_type: nil, region: :us)
|
||||
provider = if region.to_sym == :eu
|
||||
self.class.plaid_eu_provider
|
||||
else
|
||||
self.class.plaid_us_provider
|
||||
end
|
||||
|
||||
provider.get_link_token(
|
||||
user_id: id,
|
||||
webhooks_url: webhooks_url,
|
||||
redirect_url: redirect_url,
|
||||
accountable_type: accountable_type,
|
||||
eu: region == :eu
|
||||
).link_token
|
||||
end
|
||||
|
||||
|
@ -238,4 +237,3 @@ class Family < ApplicationRecord
|
|||
)
|
||||
end
|
||||
end
|
||||
# rubocop:enable Layout/ElseAlignment, Layout/IndentationWidth
|
||||
|
|
|
@ -21,8 +21,8 @@ class PlaidItem < ApplicationRecord
|
|||
scope :ordered, -> { order(created_at: :desc) }
|
||||
|
||||
class << self
|
||||
def create_from_public_token(token, item_name:, region: "us")
|
||||
response = plaid_provider.exchange_public_token(token)
|
||||
def create_from_public_token(token, item_name:, region:)
|
||||
response = plaid_provider_for_region(region).exchange_public_token(token)
|
||||
|
||||
new_plaid_item = create!(
|
||||
name: item_name,
|
||||
|
@ -59,11 +59,10 @@ class PlaidItem < ApplicationRecord
|
|||
private
|
||||
def fetch_and_load_plaid_data
|
||||
data = {}
|
||||
provider = plaid_provider_for(self)
|
||||
item = provider.get_item(access_token).item
|
||||
item = plaid_provider.get_item(access_token).item
|
||||
update!(available_products: item.available_products, billed_products: item.billed_products)
|
||||
|
||||
fetched_accounts = provider.get_item_accounts(self).accounts
|
||||
fetched_accounts = plaid_provider.get_item_accounts(self).accounts
|
||||
data[:accounts] = fetched_accounts || []
|
||||
|
||||
internal_plaid_accounts = fetched_accounts.map do |account|
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
class Provider::Plaid
|
||||
attr_reader :client
|
||||
attr_reader :client, :region
|
||||
|
||||
MAYBE_SUPPORTED_PLAID_PRODUCTS = %w[transactions investments liabilities].freeze
|
||||
MAX_HISTORY_DAYS = Rails.env.development? ? 90 : 730
|
||||
|
@ -54,27 +54,22 @@ class Provider::Plaid
|
|||
actual_hash = Digest::SHA256.hexdigest(raw_body)
|
||||
raise JWT::VerificationError, "Invalid webhook body hash" unless ActiveSupport::SecurityUtils.secure_compare(expected_hash, actual_hash)
|
||||
end
|
||||
|
||||
def client
|
||||
api_client = Plaid::ApiClient.new(
|
||||
Rails.application.config.plaid
|
||||
)
|
||||
|
||||
Plaid::PlaidApi.new(api_client)
|
||||
end
|
||||
end
|
||||
|
||||
def initialize
|
||||
@client = self.class.client
|
||||
def initialize(config, region)
|
||||
@client = Plaid::PlaidApi.new(
|
||||
Plaid::ApiClient.new(config)
|
||||
)
|
||||
@region = region
|
||||
end
|
||||
|
||||
def get_link_token(user_id:, webhooks_url:, redirect_url:, accountable_type: nil, eu: false)
|
||||
def get_link_token(user_id:, webhooks_url:, redirect_url:, accountable_type: nil)
|
||||
request = Plaid::LinkTokenCreateRequest.new({
|
||||
user: { client_user_id: user_id },
|
||||
client_name: "Maybe Finance",
|
||||
products: [ get_primary_product(accountable_type) ],
|
||||
additional_consented_products: get_additional_consented_products(accountable_type),
|
||||
country_codes: get_country_codes(eu),
|
||||
country_codes: country_codes,
|
||||
language: "en",
|
||||
webhook: webhooks_url,
|
||||
redirect_uri: redirect_url,
|
||||
|
@ -199,8 +194,8 @@ class Provider::Plaid
|
|||
MAYBE_SUPPORTED_PLAID_PRODUCTS - [ get_primary_product(accountable_type) ]
|
||||
end
|
||||
|
||||
def get_country_codes(eu)
|
||||
if eu
|
||||
def country_codes
|
||||
if region.to_sym == :eu
|
||||
[ "ES", "NL", "FR", "IE", "DE", "IT", "PL", "DK", "NO", "SE", "EE", "LT", "LV", "PT", "BE" ] # EU supported countries
|
||||
else
|
||||
[ "US", "CA" ] # US + CA only
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue