plaid 3.0.0 → 4.0.0

Sign up to get free protection for your applications and to get access to all the features.
@@ -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
@@ -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
@@ -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
@@ -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