plaid 1.7.1 → 2.0.0.alpha
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +4 -4
- data/CHANGELOG.md +3 -0
- data/CONTRIBUTING.md +15 -0
- data/LICENSE +20 -0
- data/README.md +215 -63
- data/Rakefile +50 -4
- data/UPGRADING.md +45 -0
- data/bin/console +13 -0
- data/bin/setup +8 -0
- data/lib/plaid.rb +51 -88
- data/lib/plaid/account.rb +144 -0
- data/lib/plaid/category.rb +62 -0
- data/lib/plaid/client.rb +67 -0
- data/lib/plaid/connector.rb +168 -0
- data/lib/plaid/errors.rb +24 -14
- data/lib/plaid/income.rb +106 -0
- data/lib/plaid/info.rb +65 -0
- data/lib/plaid/institution.rb +240 -0
- data/lib/plaid/risk.rb +34 -0
- data/lib/plaid/transaction.rb +123 -0
- data/lib/plaid/user.rb +430 -0
- data/lib/plaid/version.rb +1 -1
- data/plaid.gemspec +20 -12
- metadata +58 -62
- data/.gitignore +0 -15
- data/.rspec +0 -2
- data/.travis.yml +0 -5
- data/LICENSE.txt +0 -22
- data/PUBLISHING.md +0 -21
- data/lib/plaid/config.rb +0 -19
- data/lib/plaid/connection.rb +0 -109
- data/lib/plaid/models/account.rb +0 -24
- data/lib/plaid/models/category.rb +0 -17
- data/lib/plaid/models/exchange_token_response.rb +0 -11
- data/lib/plaid/models/info.rb +0 -12
- data/lib/plaid/models/institution.rb +0 -22
- data/lib/plaid/models/transaction.rb +0 -24
- data/lib/plaid/models/user.rb +0 -189
- data/spec/plaid/config_spec.rb +0 -67
- data/spec/plaid/connection_spec.rb +0 -191
- data/spec/plaid/error_spec.rb +0 -10
- data/spec/plaid/models/account_spec.rb +0 -37
- data/spec/plaid/models/category_spec.rb +0 -16
- data/spec/plaid/models/institution_spec.rb +0 -19
- data/spec/plaid/models/transaction_spec.rb +0 -28
- data/spec/plaid/models/user_spec.rb +0 -172
- data/spec/plaid_spec.rb +0 -263
- data/spec/spec_helper.rb +0 -14
@@ -0,0 +1,168 @@
|
|
1
|
+
require 'net/http'
|
2
|
+
require 'uri'
|
3
|
+
require 'multi_json'
|
4
|
+
|
5
|
+
module Plaid
|
6
|
+
# Internal: A class encapsulating HTTP requests to the Plaid API servers
|
7
|
+
class Connector
|
8
|
+
attr_reader :uri, :http, :request, :response, :body
|
9
|
+
|
10
|
+
# Internal: Default read timeout for HTTP calls.
|
11
|
+
DEFAULT_TIMEOUT = 120
|
12
|
+
|
13
|
+
# Internal: Prepare to run request.
|
14
|
+
#
|
15
|
+
# path - The String path without leading slash. E.g. 'connect'
|
16
|
+
# subpath - The String subpath. E.g. 'get'
|
17
|
+
# auth - The Boolean flag indicating that client_id and secret should be
|
18
|
+
# included into the request payload.
|
19
|
+
# client - The Plaid::Client instance used to connect
|
20
|
+
# (default: Plaid.client).
|
21
|
+
def initialize(path, subpath = nil, auth: false, client: nil)
|
22
|
+
@auth = auth
|
23
|
+
@client = client || Plaid.client
|
24
|
+
verify_configuration
|
25
|
+
|
26
|
+
path = File.join(@client.env, path.to_s)
|
27
|
+
path = File.join(path, subpath.to_s) if subpath
|
28
|
+
|
29
|
+
@uri = URI.parse(path)
|
30
|
+
|
31
|
+
@http = Net::HTTP.new(@uri.host, @uri.port)
|
32
|
+
@http.use_ssl = true
|
33
|
+
|
34
|
+
@http.read_timeout = Plaid.read_timeout || DEFAULT_TIMEOUT
|
35
|
+
end
|
36
|
+
|
37
|
+
# Internal: Run GET request.
|
38
|
+
#
|
39
|
+
# Returns the parsed JSON response body.
|
40
|
+
def get(payload = {})
|
41
|
+
payload = with_credentials(payload)
|
42
|
+
|
43
|
+
@uri.query = URI.encode_www_form(payload) unless payload.empty?
|
44
|
+
|
45
|
+
run Net::HTTP::Get.new(@uri)
|
46
|
+
end
|
47
|
+
|
48
|
+
# Internal: Run POST request.
|
49
|
+
#
|
50
|
+
# Adds client_id and secret to the payload if @auth is true.
|
51
|
+
#
|
52
|
+
# payload - The Hash with data.
|
53
|
+
#
|
54
|
+
# Returns the parsed JSON response body.
|
55
|
+
def post(payload)
|
56
|
+
post_like payload, Net::HTTP::Post.new(@uri.path)
|
57
|
+
end
|
58
|
+
|
59
|
+
# Internal: Run PATCH request.
|
60
|
+
#
|
61
|
+
# Adds client_id and secret to the payload if @auth is true.
|
62
|
+
#
|
63
|
+
# payload - The Hash with data.
|
64
|
+
#
|
65
|
+
# Returns the parsed JSON response body.
|
66
|
+
def patch(payload)
|
67
|
+
post_like payload, Net::HTTP::Patch.new(@uri.path)
|
68
|
+
end
|
69
|
+
|
70
|
+
# Internal: Run DELETE request.
|
71
|
+
#
|
72
|
+
# Adds client_id and secret to the payload if @auth is true.
|
73
|
+
#
|
74
|
+
# payload - The Hash with data.
|
75
|
+
#
|
76
|
+
# Returns the parsed JSON response body.
|
77
|
+
def delete(payload)
|
78
|
+
post_like payload, Net::HTTP::Delete.new(@uri.path)
|
79
|
+
end
|
80
|
+
|
81
|
+
# Internal: Check if MFA response received.
|
82
|
+
#
|
83
|
+
# Returns true if response has code 201.
|
84
|
+
def mfa?
|
85
|
+
@response.is_a?(Net::HTTPCreated)
|
86
|
+
end
|
87
|
+
|
88
|
+
private
|
89
|
+
|
90
|
+
# Internal: Run the request and process the response.
|
91
|
+
#
|
92
|
+
# Returns the parsed JSON body or raises an appropriate exception (a
|
93
|
+
# descendant of Plaid::PlaidError).
|
94
|
+
def run(request)
|
95
|
+
@request = request
|
96
|
+
@response = http.request(@request)
|
97
|
+
|
98
|
+
# All responses are expected to have a JSON body, so we always parse,
|
99
|
+
# not looking at the status code.
|
100
|
+
@body = MultiJson.load(@response.body)
|
101
|
+
|
102
|
+
case @response
|
103
|
+
when Net::HTTPSuccess, Net::HTTPCreated
|
104
|
+
@body
|
105
|
+
else
|
106
|
+
raise_error
|
107
|
+
end
|
108
|
+
end
|
109
|
+
|
110
|
+
# Internal: Run POST-like request.
|
111
|
+
#
|
112
|
+
# payload - The Hash with posted data.
|
113
|
+
# request - The Net::HTTPGenericRequest descendant instance.
|
114
|
+
def post_like(payload, request)
|
115
|
+
request.set_form_data(with_credentials(payload))
|
116
|
+
|
117
|
+
run request
|
118
|
+
end
|
119
|
+
|
120
|
+
# Internal: Raise an error with the class depending on @response.
|
121
|
+
#
|
122
|
+
# Returns an Array with arguments.
|
123
|
+
def raise_error
|
124
|
+
klass = case @response
|
125
|
+
when Net::HTTPBadRequest then Plaid::BadRequestError
|
126
|
+
when Net::HTTPUnauthorized then Plaid::UnauthorizedError
|
127
|
+
when Net::HTTPPaymentRequired then Plaid::RequestFailedError
|
128
|
+
when Net::HTTPNotFound then Plaid::NotFoundError
|
129
|
+
else
|
130
|
+
Plaid::ServerError
|
131
|
+
end
|
132
|
+
|
133
|
+
raise klass.new(body['code'], body['message'], body['resolve'])
|
134
|
+
end
|
135
|
+
|
136
|
+
# Internal: Verify that Plaid environment is properly configured.
|
137
|
+
#
|
138
|
+
# Raises NotConfiguredError if anything is wrong.
|
139
|
+
def verify_configuration
|
140
|
+
raise_not_configured(:env, auth: false) unless @client.env
|
141
|
+
return unless @auth
|
142
|
+
|
143
|
+
!@client.client_id_configured? && raise_not_configured(:client_id)
|
144
|
+
!@client.secret_configured? && raise_not_configured(:secret)
|
145
|
+
end
|
146
|
+
|
147
|
+
# Internal: Raise a NotConfiguredError exception with proper message.
|
148
|
+
def raise_not_configured(field, auth: true)
|
149
|
+
message = "You must set Plaid::Client.#{field} before using any methods"
|
150
|
+
message << ' which require authentication' if auth
|
151
|
+
message << "! It's current value is #{@client.send(field).inspect}. " \
|
152
|
+
'E.g. add a Plaid.config do .. end block somewhere in the ' \
|
153
|
+
'initialization code of your program.'
|
154
|
+
|
155
|
+
raise NotConfiguredError, message
|
156
|
+
end
|
157
|
+
|
158
|
+
# Internal: Merge credentials to the payload if needed.
|
159
|
+
def with_credentials(payload)
|
160
|
+
if @auth
|
161
|
+
payload.merge(client_id: @client.client_id,
|
162
|
+
secret: @client.secret)
|
163
|
+
else
|
164
|
+
payload
|
165
|
+
end
|
166
|
+
end
|
167
|
+
end
|
168
|
+
end
|
data/lib/plaid/errors.rb
CHANGED
@@ -1,27 +1,37 @@
|
|
1
1
|
module Plaid
|
2
|
+
# Public: Exception to throw when there are configuration problems
|
3
|
+
class NotConfiguredError < StandardError; end
|
4
|
+
|
5
|
+
# Internal: Base class for Plaid errors
|
2
6
|
class PlaidError < StandardError
|
3
|
-
attr_reader :code
|
4
|
-
|
5
|
-
|
7
|
+
attr_reader :code, :resolve
|
8
|
+
|
9
|
+
# Internal: Initialize a error with proper attributes.
|
10
|
+
#
|
11
|
+
# code - The Integer code (e.g. 1501).
|
12
|
+
# message - The String message, describing the error.
|
13
|
+
# resolve - The String description how to fix the error.
|
6
14
|
def initialize(code, message, resolve)
|
7
|
-
super(message)
|
8
15
|
@code = code
|
9
16
|
@resolve = resolve
|
17
|
+
|
18
|
+
super "Code #{@code}: #{message}. #{resolve}"
|
10
19
|
end
|
11
20
|
end
|
12
21
|
|
13
|
-
|
14
|
-
end
|
22
|
+
# Public: Exception which is thrown when Plaid API returns a 400 response.
|
23
|
+
class BadRequestError < PlaidError; end
|
15
24
|
|
16
|
-
|
17
|
-
end
|
25
|
+
# Public: Exception which is thrown when Plaid API returns a 401 response.
|
26
|
+
class UnauthorizedError < PlaidError; end
|
18
27
|
|
19
|
-
|
20
|
-
end
|
28
|
+
# Public: Exception which is thrown when Plaid API returns a 402 response.
|
29
|
+
class RequestFailedError < PlaidError; end
|
21
30
|
|
22
|
-
|
23
|
-
end
|
31
|
+
# Public: Exception which is thrown when Plaid API returns a 404 response.
|
32
|
+
class NotFoundError < PlaidError; end
|
24
33
|
|
25
|
-
|
26
|
-
|
34
|
+
# Public: Exception which is thrown when Plaid API returns a response which
|
35
|
+
# is neither 2xx, nor 4xx. Presumably 5xx.
|
36
|
+
class ServerError < PlaidError; end
|
27
37
|
end
|
data/lib/plaid/income.rb
ADDED
@@ -0,0 +1,106 @@
|
|
1
|
+
module Plaid
|
2
|
+
# Public: Representation of Income data.
|
3
|
+
class Income
|
4
|
+
# Public: The class encapsulating an income stream.
|
5
|
+
class Stream
|
6
|
+
# Public: The Float monthly income associated with the income stream.
|
7
|
+
# E.g. 5700.
|
8
|
+
attr_reader :monthly_income
|
9
|
+
|
10
|
+
# Public: The Float representation of Plaid's confidence in the income
|
11
|
+
# data associated with this particular income stream, with 0 being
|
12
|
+
# the lowest confidence and 1 being the highest. E.g. 0.9.
|
13
|
+
attr_reader :confidence
|
14
|
+
|
15
|
+
# Public: The Integer extent of data found for this income stream.
|
16
|
+
# E.g. 314.
|
17
|
+
attr_reader :days
|
18
|
+
|
19
|
+
# Public: The String name of the entity associated with this income
|
20
|
+
# stream. E.g. "APPLE INC".
|
21
|
+
attr_reader :name
|
22
|
+
|
23
|
+
# Internal: Initialize a Stream.
|
24
|
+
#
|
25
|
+
# fields - The Hash with fields (keys are Strings).
|
26
|
+
def initialize(fields)
|
27
|
+
@monthly_income = fields['monthly_income']
|
28
|
+
@confidence = fields['confidence']
|
29
|
+
@days = fields['days']
|
30
|
+
@name = fields['name']
|
31
|
+
end
|
32
|
+
|
33
|
+
# Public: Get a String representation of the Stream.
|
34
|
+
#
|
35
|
+
# Returns a String.
|
36
|
+
def inspect
|
37
|
+
"#<Plaid::Income::Stream name=#{name.inspect}, " \
|
38
|
+
"monthly_income=#{monthly_income.inspect}, " \
|
39
|
+
"confidence=#{confidence.inspect}, " \
|
40
|
+
"days=#{days.inspect}>"
|
41
|
+
end
|
42
|
+
|
43
|
+
# Public: Get a String representation of the Stream.
|
44
|
+
#
|
45
|
+
# Returns a String.
|
46
|
+
alias to_s inspect
|
47
|
+
end
|
48
|
+
|
49
|
+
# Public: The Array of Stream.
|
50
|
+
attr_reader :income_streams
|
51
|
+
|
52
|
+
# Public: The Numeric sum of user's income over the past 365 days. If Plaid
|
53
|
+
# has less than 365 days of data this will be less than a full year income.
|
54
|
+
# E.g. 67000.
|
55
|
+
attr_reader :last_year_income
|
56
|
+
|
57
|
+
# Public: The last_year_income interpolated to value before taxes. This is
|
58
|
+
# the minimum pre-tax salary that assumes a filing status of single with
|
59
|
+
# zero dependents. E.g. 73700.
|
60
|
+
attr_reader :last_year_income_before_tax
|
61
|
+
|
62
|
+
# Public: The Numeric user's income extrapolated over a year based on
|
63
|
+
# current, active income streams. Income streams become inactive if they
|
64
|
+
# have not recurred for more than two cycles. For example, if a weekly
|
65
|
+
# paycheck hasn't been seen for the past two weeks, it is no longer active.
|
66
|
+
# E.g. 69800.
|
67
|
+
attr_reader :projected_yearly_income
|
68
|
+
|
69
|
+
# Public: The projected_yearly_income interpolated to value before taxes.
|
70
|
+
# This is the minimum pre-tax salary that assumes a filing status of single
|
71
|
+
# with zero dependents. E.g. 75600.
|
72
|
+
attr_reader :projected_yearly_income_before_tax
|
73
|
+
|
74
|
+
# Public: The Integer max number of income streams present at the same time
|
75
|
+
# over the past 365 days. E.g. 314.
|
76
|
+
attr_reader :max_number_of_overlapping_income_streams
|
77
|
+
|
78
|
+
# Public: The Integer total number of distinct income streams received over
|
79
|
+
# the past 365 days. E.g. 2.
|
80
|
+
attr_reader :number_of_income_streams
|
81
|
+
|
82
|
+
def initialize(fields)
|
83
|
+
@income_streams = fields['income_streams'].map { |is| Stream.new(is) }
|
84
|
+
|
85
|
+
%w(last_year_income last_year_income_before_tax projected_yearly_income
|
86
|
+
projected_yearly_income_before_tax number_of_income_streams
|
87
|
+
max_number_of_overlapping_income_streams).each do |field|
|
88
|
+
instance_variable_set "@#{field}", fields[field]
|
89
|
+
end
|
90
|
+
end
|
91
|
+
|
92
|
+
# Public: Get a String representation of Income.
|
93
|
+
#
|
94
|
+
# Returns a String.
|
95
|
+
def inspect
|
96
|
+
"#<Plaid::Income last_year_income=#{last_year_income.inspect}, " \
|
97
|
+
"projected_yearly_income=#{projected_yearly_income.inspect}, " \
|
98
|
+
"number_of_income_streams=#{number_of_income_streams.inspect}, ...>"
|
99
|
+
end
|
100
|
+
|
101
|
+
# Public: Get a String representation of Income.
|
102
|
+
#
|
103
|
+
# Returns a String.
|
104
|
+
alias to_s inspect
|
105
|
+
end
|
106
|
+
end
|
data/lib/plaid/info.rb
ADDED
@@ -0,0 +1,65 @@
|
|
1
|
+
module Plaid
|
2
|
+
# Public: Representation of user information.
|
3
|
+
class Info
|
4
|
+
# Public: The Array of String user names.
|
5
|
+
#
|
6
|
+
# E.g. ["Frodo Baggins", "Samwise Gamgee"].
|
7
|
+
attr_reader :names
|
8
|
+
|
9
|
+
# Public: The Array of Hash user emails information.
|
10
|
+
#
|
11
|
+
# E.g. [{data: "frodo.baggins@plaid.com", type: :primary}, ...]
|
12
|
+
attr_reader :emails
|
13
|
+
|
14
|
+
# Public: The Array of Hash user phone number information.
|
15
|
+
#
|
16
|
+
# E.g. [{data: "111-222-3456", type: :work, primary: false},
|
17
|
+
# {data: "123-456-7891", type: :mobile, primary: true}]
|
18
|
+
attr_reader :phone_numbers
|
19
|
+
|
20
|
+
# Public: The Array of Hash user address information.
|
21
|
+
#
|
22
|
+
# E.g. [{ primary: true, data: {
|
23
|
+
# "street" => "1 Hobbit Way",
|
24
|
+
# "city" => "The Shire",
|
25
|
+
# "state" => "CA",
|
26
|
+
# "zip" => "94108"}}]
|
27
|
+
attr_reader :addresses
|
28
|
+
|
29
|
+
# Internal: Construct the Info object.
|
30
|
+
def initialize(fields)
|
31
|
+
@names = fields['names']
|
32
|
+
@emails = fields['emails'].map do |h|
|
33
|
+
symbolize_values Plaid.symbolize_hash(h), :type
|
34
|
+
end
|
35
|
+
|
36
|
+
@phone_numbers = fields['phone_numbers'].map do |h|
|
37
|
+
symbolize_values Plaid.symbolize_hash(h), :type
|
38
|
+
end
|
39
|
+
|
40
|
+
@addresses = fields['addresses'].map do |h|
|
41
|
+
Plaid.symbolize_hash(h)
|
42
|
+
end
|
43
|
+
end
|
44
|
+
|
45
|
+
# Public: Get a String representation of Info object.
|
46
|
+
#
|
47
|
+
# Returns a String.
|
48
|
+
def inspect
|
49
|
+
"#<Plaid::Info names=#{names.inspect}, ...>"
|
50
|
+
end
|
51
|
+
|
52
|
+
# Public: Get a String representation of Info object.
|
53
|
+
#
|
54
|
+
# Returns a String.
|
55
|
+
alias to_s inspect
|
56
|
+
|
57
|
+
private
|
58
|
+
|
59
|
+
def symbolize_values(hash, *keys)
|
60
|
+
hash.each do |k, v|
|
61
|
+
hash[k] = v.to_sym if keys.include?(k)
|
62
|
+
end
|
63
|
+
end
|
64
|
+
end
|
65
|
+
end
|
@@ -0,0 +1,240 @@
|
|
1
|
+
module Plaid
|
2
|
+
# Public: A class encapsulating information about a Financial Institution
|
3
|
+
# supported by Plaid.
|
4
|
+
class Institution
|
5
|
+
# Public: The String institution ID. E.g. "5301a93ac140de84910000e0".
|
6
|
+
attr_reader :id
|
7
|
+
|
8
|
+
# Public: The String institution name. E.g. "Bank of America".
|
9
|
+
attr_reader :name
|
10
|
+
|
11
|
+
# Public: The String institution shortname, or "type" per Plaid API docs.
|
12
|
+
# E.g. "bofa".
|
13
|
+
attr_reader :type
|
14
|
+
|
15
|
+
# Public: The Boolean flag telling if the institution requires MFA.
|
16
|
+
attr_reader :has_mfa
|
17
|
+
|
18
|
+
# Public: Returns true if the institution requires MFA.
|
19
|
+
alias has_mfa? has_mfa
|
20
|
+
|
21
|
+
# Public: The Hash with MFA options available. E.g. ["code", "list",
|
22
|
+
# "questions(3)"]. This means that you are allowed to request a list of
|
23
|
+
# possible MFA options, use code-based MFA and questions MFA (there are 3
|
24
|
+
# questions).
|
25
|
+
attr_reader :mfa
|
26
|
+
|
27
|
+
# Public: The Hash with credential labels, how they are exactly named by
|
28
|
+
# the institution. E.g. {"username": "Online ID", "password": "Password"}.
|
29
|
+
attr_reader :credentials
|
30
|
+
|
31
|
+
# Public: An Array with Symbol product names supported by the institution.
|
32
|
+
# E.g. [:connect, :auth, :balance, :info, :income, :risk]. See
|
33
|
+
# Plaid::PRODUCTS.
|
34
|
+
attr_reader :products
|
35
|
+
|
36
|
+
# Internal: Initialize an Institution with given fields.
|
37
|
+
def initialize(fields)
|
38
|
+
@id = fields['id']
|
39
|
+
@name = fields['name']
|
40
|
+
@type = fields['type']
|
41
|
+
@has_mfa = fields['has_mfa']
|
42
|
+
@mfa = fields['mfa']
|
43
|
+
@credentials = fields['credentials']
|
44
|
+
@products = fields['products'].map(&:to_sym)
|
45
|
+
end
|
46
|
+
|
47
|
+
# Public: Get a String representation of the institution.
|
48
|
+
#
|
49
|
+
# Returns a String.
|
50
|
+
def inspect
|
51
|
+
"#<Plaid::Institution id=#{id.inspect}, type=#{type.inspect}, " \
|
52
|
+
"name=#{name.inspect}>"
|
53
|
+
end
|
54
|
+
|
55
|
+
# Public: Get a String representation of the institution.
|
56
|
+
#
|
57
|
+
# Returns a String.
|
58
|
+
alias to_s inspect
|
59
|
+
|
60
|
+
# Public: Get information about the Financial Institutions currently
|
61
|
+
# supported by Plaid.
|
62
|
+
#
|
63
|
+
# Does a GET /institutions call.
|
64
|
+
#
|
65
|
+
# client - The Plaid::Client instance used to connect
|
66
|
+
# (default: Plaid.client).
|
67
|
+
#
|
68
|
+
# Returns an Array of Institution instances.
|
69
|
+
def self.all(client: nil)
|
70
|
+
Connector.new(:institutions, client: client).get.map do |idata|
|
71
|
+
new(idata)
|
72
|
+
end
|
73
|
+
end
|
74
|
+
|
75
|
+
# Public: Get information about a given Financial Institution.
|
76
|
+
#
|
77
|
+
# Does a GET /institutions/:id call.
|
78
|
+
#
|
79
|
+
# id - the String institution ID (e.g. "5301a93ac140de84910000e0").
|
80
|
+
# client - The Plaid::Client instance used to connect
|
81
|
+
# (default: Plaid.client).
|
82
|
+
#
|
83
|
+
# Returns an Institution instance or raises Plaid::NotFoundError if
|
84
|
+
# institution with given id is not found.
|
85
|
+
def self.get(id, client: nil)
|
86
|
+
new Connector.new(:institutions, id, client: client).get
|
87
|
+
end
|
88
|
+
end
|
89
|
+
|
90
|
+
##############################################################################
|
91
|
+
|
92
|
+
# Public: A class encapsulating information about a "long tail" Financial
|
93
|
+
# Institution supported by Plaid.
|
94
|
+
class LongTailInstitution
|
95
|
+
# Public: The String ID of the institution. Same as type. E.g. "bofa".
|
96
|
+
attr_reader :id
|
97
|
+
|
98
|
+
# Public: The String short name ("type") of the institution. E.g. "bofa".
|
99
|
+
attr_reader :type
|
100
|
+
|
101
|
+
# Public: The String institution name. E.g. "Bank of America".
|
102
|
+
attr_reader :name
|
103
|
+
|
104
|
+
# Public: The Hash with supported products as keys and booleans as values.
|
105
|
+
#
|
106
|
+
# E.g. { auth: true, balance: true, connect: true, info: true }.
|
107
|
+
attr_reader :products
|
108
|
+
|
109
|
+
# Public: The String "forgotten password" URL.
|
110
|
+
attr_reader :forgotten_password_url
|
111
|
+
|
112
|
+
# Public: The String "account locked" URL.
|
113
|
+
attr_reader :account_locked_url
|
114
|
+
|
115
|
+
# Public: The String "account setup" URL.
|
116
|
+
attr_reader :account_setup_url
|
117
|
+
|
118
|
+
# Public: The String video (???).
|
119
|
+
attr_reader :video
|
120
|
+
|
121
|
+
# Public: The Array of Hashes with login fields information.
|
122
|
+
#
|
123
|
+
# E.g. [{ name: 'username', label: 'Online ID', type: 'text' },
|
124
|
+
# { name: 'password', label: 'Password', type: 'password' }].
|
125
|
+
attr_reader :fields
|
126
|
+
|
127
|
+
# Public: The Hash with color information for the institution.
|
128
|
+
#
|
129
|
+
# E.g. { primary: 'rgba(220,20,48,1)',
|
130
|
+
# darker: 'rgba(180,11,35,1)',
|
131
|
+
# gradient: ['rgba(250,20,51,1)', 'rgba(227,24,55,1)'] }.
|
132
|
+
attr_reader :colors
|
133
|
+
|
134
|
+
# Public: The String with base64 encoded logo.
|
135
|
+
attr_reader :logo
|
136
|
+
|
137
|
+
# Public: ???.
|
138
|
+
attr_reader :name_break
|
139
|
+
|
140
|
+
# Internal: Initialize the LongTailInstitution instance.
|
141
|
+
def initialize(hash)
|
142
|
+
%w(id type name video logo).each do |f|
|
143
|
+
instance_variable_set "@#{f}", hash[f]
|
144
|
+
end
|
145
|
+
|
146
|
+
@products = Plaid.symbolize_hash(hash['products'])
|
147
|
+
@forgotten_password_url = hash['forgottenPassword']
|
148
|
+
@account_locked_url = hash['accountLocked']
|
149
|
+
@account_setup_url = hash['accountSetup']
|
150
|
+
@fields = hash['fields'].map { |fld| Plaid.symbolize_hash(fld) }
|
151
|
+
@colors = Plaid.symbolize_hash(hash['colors'])
|
152
|
+
@name_break = hash['nameBreak']
|
153
|
+
end
|
154
|
+
|
155
|
+
# Public: Get a String representation of the institution.
|
156
|
+
#
|
157
|
+
# Returns a String.
|
158
|
+
def inspect
|
159
|
+
"#<Plaid::LongTailInstitution id=#{id.inspect}, name=#{name.inspect}, " \
|
160
|
+
'...>'
|
161
|
+
end
|
162
|
+
|
163
|
+
# Public: Get a String representation of the institution.
|
164
|
+
#
|
165
|
+
# Returns a String.
|
166
|
+
alias to_s inspect
|
167
|
+
|
168
|
+
# Public: Lookup a "long tail" Financial Institution by ID.
|
169
|
+
#
|
170
|
+
# Does a GET /institutions/search call with id param.
|
171
|
+
#
|
172
|
+
# id - the String institution ID (e.g. 'bofa').
|
173
|
+
# client - The Plaid::Client instance used to connect
|
174
|
+
# (default: Plaid.client).
|
175
|
+
#
|
176
|
+
# Returns an Institution instance or nil if institution with given id is not
|
177
|
+
# found.
|
178
|
+
def self.get(id, client: nil)
|
179
|
+
client ||= Plaid.client
|
180
|
+
|
181
|
+
# If client_id is set, use it, no authentication otherwise
|
182
|
+
auth = client && !client.client_id.nil?
|
183
|
+
conn = Connector.new(:institutions, :search, auth: auth, client: client)
|
184
|
+
resp = conn.get(id: id)
|
185
|
+
|
186
|
+
case resp
|
187
|
+
when Hash
|
188
|
+
new resp
|
189
|
+
when Array
|
190
|
+
raise 'Non-empty array returned by /institutions/search with id' \
|
191
|
+
unless resp.empty?
|
192
|
+
|
193
|
+
nil
|
194
|
+
else
|
195
|
+
raise 'Unexpected result returned by /institutions/search with id: ' \
|
196
|
+
"#{resp.inspect}"
|
197
|
+
end
|
198
|
+
end
|
199
|
+
|
200
|
+
# Public: Get information about the "long tail" institutions supported
|
201
|
+
# by Plaid via partnerships.
|
202
|
+
#
|
203
|
+
# Does a POST /institutions/longtail call.
|
204
|
+
#
|
205
|
+
# count - The Integer number of results to retrieve (default: 50).
|
206
|
+
# offset - The Integer number of results to skip forward from the
|
207
|
+
# beginning of the list (default: 0).
|
208
|
+
# client - The Plaid::Client instance used to connect
|
209
|
+
# (default: Plaid.client).
|
210
|
+
#
|
211
|
+
# Returns an Array of LongTailInstitution instances.
|
212
|
+
def self.all(count: 50, offset: 0, client: nil)
|
213
|
+
conn = Connector.new(:institutions, :longtail, auth: true, client: client)
|
214
|
+
resp = conn.post(count: count, offset: offset)
|
215
|
+
resp.map { |lti_data| new(lti_data) }
|
216
|
+
end
|
217
|
+
|
218
|
+
# Public: Search "long tail" institutions.
|
219
|
+
#
|
220
|
+
# query - The String search query to match against the full list of
|
221
|
+
# institutions. Partial matches are returned making this useful
|
222
|
+
# for autocompletion purposes.
|
223
|
+
# product - The Symbol product name to filter by, one of Plaid::PRODUCTS
|
224
|
+
# (e.g. :info, :connect, etc.). Only valid when query is
|
225
|
+
# specified. If nil, results are not filtered by product
|
226
|
+
# (default: nil).
|
227
|
+
# client - The Plaid::Client instance used to connect
|
228
|
+
# (default: Plaid.client).
|
229
|
+
def self.search(query: nil, product: nil, client: nil)
|
230
|
+
raise ArgumentError, 'query must be specified' \
|
231
|
+
unless query.is_a?(String) && !query.empty?
|
232
|
+
|
233
|
+
payload = { q: query }
|
234
|
+
payload[:p] = product.to_s if product
|
235
|
+
|
236
|
+
resp = Connector.new(:institutions, :search, client: client).get(payload)
|
237
|
+
resp.map { |lti_data| new(lti_data) }
|
238
|
+
end
|
239
|
+
end
|
240
|
+
end
|