plaid 3.0.0 → 4.0.0
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/CONTRIBUTING.md +7 -1
- data/Gemfile +0 -1
- data/LICENSE.txt +21 -0
- data/README.md +233 -206
- data/Rakefile +1 -2
- data/bin/console +8 -7
- data/circle.yml +3 -0
- data/lib/plaid.rb +15 -60
- data/lib/plaid/client.rb +120 -52
- data/lib/plaid/connect.rb +75 -0
- data/lib/plaid/errors.rb +60 -24
- data/lib/plaid/products/accounts.rb +60 -0
- data/lib/plaid/products/auth.rb +29 -0
- data/lib/plaid/products/categories.rb +18 -0
- data/lib/plaid/products/credit_details.rb +21 -0
- data/lib/plaid/products/identity.rb +20 -0
- data/lib/plaid/products/income.rb +20 -0
- data/lib/plaid/products/institutions.rb +51 -0
- data/lib/plaid/products/item.rb +230 -0
- data/lib/plaid/products/processor.rb +48 -0
- data/lib/plaid/products/sandbox.rb +32 -0
- data/lib/plaid/products/transactions.rb +74 -0
- data/lib/plaid/version.rb +1 -1
- data/plaid.gemspec +13 -8
- metadata +21 -61
- data/CHANGELOG.md +0 -34
- data/LICENSE +0 -20
- data/UPGRADING.md +0 -60
- data/lib/plaid/account.rb +0 -144
- data/lib/plaid/category.rb +0 -62
- data/lib/plaid/connector.rb +0 -172
- data/lib/plaid/income.rb +0 -106
- data/lib/plaid/info.rb +0 -65
- data/lib/plaid/institution.rb +0 -253
- data/lib/plaid/risk.rb +0 -34
- data/lib/plaid/transaction.rb +0 -128
- data/lib/plaid/user.rb +0 -507
- data/lib/plaid/webhook.rb +0 -153
data/lib/plaid/account.rb
DELETED
@@ -1,144 +0,0 @@
|
|
1
|
-
require 'plaid/risk'
|
2
|
-
|
3
|
-
module Plaid
|
4
|
-
# Public: Representation of user account data.
|
5
|
-
class Account
|
6
|
-
# Public: The String unique ID of the account. E.g.
|
7
|
-
# "QPO8Jo8vdDHMepg41PBwckXm4KdK1yUdmXOwK".
|
8
|
-
attr_reader :id
|
9
|
-
|
10
|
-
# Public: The String account ID unique to the accounts of a particular
|
11
|
-
# access token. E.g. "KdDjmojBERUKx3JkDd9RuxA5EvejA4SENO4AA".
|
12
|
-
attr_reader :item_id
|
13
|
-
|
14
|
-
# Public: The Float value of the current balance for the account.
|
15
|
-
attr_reader :current_balance
|
16
|
-
|
17
|
-
# Public: The Float value of the available balance for the account.
|
18
|
-
#
|
19
|
-
# The Available Balance is the Current Balance less any outstanding holds
|
20
|
-
# or debits that have not yet posted to the account. Note that not all
|
21
|
-
# institutions calculate the Available Balance. In the case that Available
|
22
|
-
# Balance is unavailable from the institution, Plaid will either return an
|
23
|
-
# Available Balance value of null or only return a Current Balance.
|
24
|
-
attr_reader :available_balance
|
25
|
-
|
26
|
-
# Public: The Symbol institution type, e.g. :wells.
|
27
|
-
attr_reader :institution
|
28
|
-
|
29
|
-
# Public: The Hash with additional information pertaining to the account
|
30
|
-
# such as the limit, name, or last few digits of the account number. E.g.
|
31
|
-
# {"name": "Plaid Savings", "number": "9606" }.
|
32
|
-
attr_reader :meta
|
33
|
-
|
34
|
-
# Public: The Symbol account type. One of :depository, :credit, :loan,
|
35
|
-
# :mortgage, :brokerage, and :other.
|
36
|
-
attr_reader :type
|
37
|
-
|
38
|
-
# Public: The String account subtype. E.g. "savings".
|
39
|
-
#
|
40
|
-
# Read more about subtypes in the Plaid API docs.
|
41
|
-
attr_reader :subtype
|
42
|
-
|
43
|
-
# Public: The Hash with account and routing numbers for the account.
|
44
|
-
#
|
45
|
-
# This attribute would be nil unless you used Auth product for the user.
|
46
|
-
#
|
47
|
-
# The Hash contains Symbol keys and String values. E.g.
|
48
|
-
# {routing: "021000021", account: "9900009606", wireRouting: "021000021"}.
|
49
|
-
attr_reader :numbers
|
50
|
-
|
51
|
-
# Public: The Risk information associated with the account.
|
52
|
-
#
|
53
|
-
# This attribute would be nil unless you used Risk product for the user.
|
54
|
-
attr_reader :risk
|
55
|
-
|
56
|
-
def initialize(hash)
|
57
|
-
@id = hash['_id']
|
58
|
-
@item_id = hash['_item']
|
59
|
-
@meta = hash['meta']
|
60
|
-
@type = hash['type'].to_sym
|
61
|
-
@subtype = hash['subtype']
|
62
|
-
@institution = hash['institution_type'].to_sym
|
63
|
-
|
64
|
-
unless (bal = hash['balance']).nil?
|
65
|
-
@available_balance = bal['available']
|
66
|
-
@current_balance = bal['current']
|
67
|
-
end
|
68
|
-
|
69
|
-
if (risk = hash['risk'])
|
70
|
-
@risk = Plaid::Risk.new(risk)
|
71
|
-
end
|
72
|
-
|
73
|
-
@numbers = Plaid.symbolize_hash(hash['numbers'])
|
74
|
-
end
|
75
|
-
|
76
|
-
# Public: Get a String representation of the account.
|
77
|
-
#
|
78
|
-
# Returns a String.
|
79
|
-
def inspect
|
80
|
-
"#<Plaid::Account id=#{id.inspect}, type=#{type.inspect}, " \
|
81
|
-
"name=#{name.inspect}, institution=#{institution.inspect}>"
|
82
|
-
end
|
83
|
-
|
84
|
-
# Public: Get a String representation of the account.
|
85
|
-
#
|
86
|
-
# Returns a String.
|
87
|
-
alias to_s inspect
|
88
|
-
|
89
|
-
# Public: Get the account name.
|
90
|
-
#
|
91
|
-
# The name is obtained from #meta Hash.
|
92
|
-
#
|
93
|
-
# Returns the String name.
|
94
|
-
def name
|
95
|
-
meta && meta['name']
|
96
|
-
end
|
97
|
-
|
98
|
-
# Internal: Merge account information.
|
99
|
-
#
|
100
|
-
# accounts - The Array of Account instances.
|
101
|
-
# new_accounts - The Array of Account instances.
|
102
|
-
#
|
103
|
-
# Returns accounts.
|
104
|
-
def self.merge(accounts, new_accounts)
|
105
|
-
# Index accounts by their ID.
|
106
|
-
#
|
107
|
-
# Same as index = accounts.index_by(&:id) in ActiveSupport.
|
108
|
-
index = Hash[accounts.map { |a| [a.id, a] }]
|
109
|
-
|
110
|
-
new_accounts.each do |acc|
|
111
|
-
if (old_acc = index[acc.id])
|
112
|
-
old_acc.update_from(acc)
|
113
|
-
else
|
114
|
-
accounts << acc
|
115
|
-
end
|
116
|
-
end
|
117
|
-
|
118
|
-
accounts
|
119
|
-
end
|
120
|
-
|
121
|
-
# Internal: Update account information.
|
122
|
-
#
|
123
|
-
# All fields which are not nil in another are copied to self.
|
124
|
-
#
|
125
|
-
# another - The Account instance with new information.
|
126
|
-
#
|
127
|
-
# Returns self.
|
128
|
-
def update_from(another)
|
129
|
-
# A sanity check. Nobody would want to update information from totally
|
130
|
-
# different account!
|
131
|
-
if id != another.id
|
132
|
-
raise ArgumentError, 'Plaid::Account#update_from: id != another.id!'
|
133
|
-
end
|
134
|
-
|
135
|
-
%i(item_id meta name type subtype institution available_balance
|
136
|
-
current_balance numbers risk).each do |field|
|
137
|
-
value = another.send(field)
|
138
|
-
instance_variable_set("@#{field}", value) unless value.nil?
|
139
|
-
end
|
140
|
-
|
141
|
-
self
|
142
|
-
end
|
143
|
-
end
|
144
|
-
end
|
data/lib/plaid/category.rb
DELETED
@@ -1,62 +0,0 @@
|
|
1
|
-
module Plaid
|
2
|
-
# Public: A class which encapsulates information about a Plaid category.
|
3
|
-
class Category
|
4
|
-
# Public: The String category ID, e.g. "21010006".
|
5
|
-
attr_reader :id
|
6
|
-
|
7
|
-
# Public: The Symbol category type. One of :special, :place, :digital.
|
8
|
-
attr_reader :type
|
9
|
-
|
10
|
-
# Public: The Array of String hierarchy. E.g.
|
11
|
-
# ["Food and Drink", "Nightlife"].
|
12
|
-
attr_reader :hierarchy
|
13
|
-
|
14
|
-
# Internal: Initialize a Category with given fields.
|
15
|
-
def initialize(fields)
|
16
|
-
@type = fields['type'].to_sym
|
17
|
-
@hierarchy = fields['hierarchy']
|
18
|
-
@id = fields['id']
|
19
|
-
end
|
20
|
-
|
21
|
-
# Public: Get a String representation of Category.
|
22
|
-
#
|
23
|
-
# Returns a String.
|
24
|
-
def inspect
|
25
|
-
"#<Plaid::Category id=#{id.inspect}, type=#{type.inspect}, " \
|
26
|
-
"hierarchy=#{hierarchy.inspect}>"
|
27
|
-
end
|
28
|
-
|
29
|
-
# Public: Get a String representation of Category.
|
30
|
-
#
|
31
|
-
# Returns a String.
|
32
|
-
alias to_s inspect
|
33
|
-
|
34
|
-
# Public: Get information about all available categories.
|
35
|
-
#
|
36
|
-
# Does a GET /categories call.
|
37
|
-
#
|
38
|
-
# client - The Plaid::Client instance used to connect
|
39
|
-
# (default: Plaid.client).
|
40
|
-
#
|
41
|
-
# Returns an Array of Category instances.
|
42
|
-
def self.all(client: nil)
|
43
|
-
Connector.new(:categories, client: client).get.map do |category_data|
|
44
|
-
new(category_data)
|
45
|
-
end
|
46
|
-
end
|
47
|
-
|
48
|
-
# Public: Get information about a given category.
|
49
|
-
#
|
50
|
-
# Does a GET /categories/:id call.
|
51
|
-
#
|
52
|
-
# id - the String category ID (e.g. "17001013").
|
53
|
-
# client - The Plaid::Client instance used to connect
|
54
|
-
# (default: Plaid.client).
|
55
|
-
#
|
56
|
-
# Returns a Category instance or raises Plaid::NotFoundError if category
|
57
|
-
# with given id is not found.
|
58
|
-
def self.get(id, client: nil)
|
59
|
-
new Connector.new(:categories, id, client: client).get
|
60
|
-
end
|
61
|
-
end
|
62
|
-
end
|
data/lib/plaid/connector.rb
DELETED
@@ -1,172 +0,0 @@
|
|
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
|
-
if @response.body.nil? || @response.body.empty?
|
99
|
-
raise Plaid::ServerError.new(0, 'Server error', 'Try to connect later')
|
100
|
-
end
|
101
|
-
|
102
|
-
# All responses are expected to have a JSON body, so we always parse,
|
103
|
-
# not looking at the status code.
|
104
|
-
@body = MultiJson.load(@response.body)
|
105
|
-
|
106
|
-
case @response
|
107
|
-
when Net::HTTPSuccess, Net::HTTPCreated
|
108
|
-
@body
|
109
|
-
else
|
110
|
-
raise_error
|
111
|
-
end
|
112
|
-
end
|
113
|
-
|
114
|
-
# Internal: Run POST-like request.
|
115
|
-
#
|
116
|
-
# payload - The Hash with posted data.
|
117
|
-
# request - The Net::HTTPGenericRequest descendant instance.
|
118
|
-
def post_like(payload, request)
|
119
|
-
request.set_form_data(with_credentials(payload))
|
120
|
-
|
121
|
-
run request
|
122
|
-
end
|
123
|
-
|
124
|
-
# Internal: Raise an error with the class depending on @response.
|
125
|
-
#
|
126
|
-
# Returns an Array with arguments.
|
127
|
-
def raise_error
|
128
|
-
klass = case @response
|
129
|
-
when Net::HTTPBadRequest then Plaid::BadRequestError
|
130
|
-
when Net::HTTPUnauthorized then Plaid::UnauthorizedError
|
131
|
-
when Net::HTTPPaymentRequired then Plaid::RequestFailedError
|
132
|
-
when Net::HTTPNotFound then Plaid::NotFoundError
|
133
|
-
else
|
134
|
-
Plaid::ServerError
|
135
|
-
end
|
136
|
-
|
137
|
-
raise klass.new(body['code'], body['message'], body['resolve'])
|
138
|
-
end
|
139
|
-
|
140
|
-
# Internal: Verify that Plaid environment is properly configured.
|
141
|
-
#
|
142
|
-
# Raises NotConfiguredError if anything is wrong.
|
143
|
-
def verify_configuration
|
144
|
-
raise_not_configured(:env, auth: false) unless @client.env
|
145
|
-
return unless @auth
|
146
|
-
|
147
|
-
!@client.client_id_configured? && raise_not_configured(:client_id)
|
148
|
-
!@client.secret_configured? && raise_not_configured(:secret)
|
149
|
-
end
|
150
|
-
|
151
|
-
# Internal: Raise a NotConfiguredError exception with proper message.
|
152
|
-
def raise_not_configured(field, auth: true)
|
153
|
-
message = "You must set Plaid::Client.#{field} before using any methods"
|
154
|
-
message << ' which require authentication' if auth
|
155
|
-
message << "! It's current value is #{@client.send(field).inspect}. " \
|
156
|
-
'E.g. add a Plaid.config do .. end block somewhere in the ' \
|
157
|
-
'initialization code of your program.'
|
158
|
-
|
159
|
-
raise NotConfiguredError, message
|
160
|
-
end
|
161
|
-
|
162
|
-
# Internal: Merge credentials to the payload if needed.
|
163
|
-
def with_credentials(payload)
|
164
|
-
if @auth
|
165
|
-
payload.merge(client_id: @client.client_id,
|
166
|
-
secret: @client.secret)
|
167
|
-
else
|
168
|
-
payload
|
169
|
-
end
|
170
|
-
end
|
171
|
-
end
|
172
|
-
end
|
data/lib/plaid/income.rb
DELETED
@@ -1,106 +0,0 @@
|
|
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
|