intuit_ids_aggcat 0.0.5 → 0.0.7
Sign up to get free protection for your applications and to get access to all the features.
- data/README.markdown +19 -6
- data/lib/intuit_ids_aggcat/client/intuit_xml_mappings.rb +103 -8
- data/lib/intuit_ids_aggcat/client/saml.rb +0 -6
- data/lib/intuit_ids_aggcat/client/services.rb +117 -5
- data/lib/intuit_ids_aggcat/rails.rb +1 -1
- data/lib/intuit_ids_aggcat/version.rb +1 -1
- data/spec/saml_spec.rb +17 -0
- data/spec/services_spec.rb +8 -1
- metadata +125 -110
data/README.markdown
CHANGED
@@ -1,15 +1,23 @@
|
|
1
1
|
intuit_ids_aggcat - A wrapper for Intuit's Aggregation & Categorization Data Services
|
2
2
|
==================================================================
|
3
|
-
**Important Note: This gem is still under active development
|
3
|
+
**Important Note: This gem is still under active development. Some features provided by Intuit may be missing or imcomplete in this gem. It is released under the Apache 2.0 license "as-is" without warranty.**
|
4
|
+
|
5
|
+
Notice for Ruby 1.8.7 and Rails 2.x users: This gem has been tested with Ruby 1.9.2 and 1.9.3 and Rails 3.2.x. There are some known problems with the syntax used for hashes and with a lack of millisecond time formats that prevent the gem from working with Ruby 1.8.7 currently. Thanks to Vinh Pham for pointing this out.
|
4
6
|
|
5
7
|
Configuration
|
6
8
|
-----------------
|
7
|
-
While the first release of this gem is being developed,
|
9
|
+
While the first release of this gem is being developed, newer versions may be available on Github that have not yet been pushed to the RubyGems repository. Installation of the gem from RubyGems can be done by running:
|
10
|
+
`gem install intuit_ids_aggcat`
|
11
|
+
|
12
|
+
or the latest version can be cloned from Github and installing manually:
|
8
13
|
`git clone https://github.com/rewardsummit/intuit_ids_aggcat.git`
|
9
|
-
`gem build intuit_ids_aggcat.gemspec && gem install intuit_ids_aggcat-0.0.
|
14
|
+
`gem build intuit_ids_aggcat.gemspec && gem install intuit_ids_aggcat-0.0.x.gem`
|
10
15
|
|
11
16
|
... or in a Rails environment using bundler by adding this to your Gemfile:
|
12
|
-
`gem '
|
17
|
+
`gem 'intuit_ids_aggcat', :git => 'https://github.com/rewardsummit/intuit_ids_aggcat.git'`
|
18
|
+
for the latest development version in Github or:
|
19
|
+
`gem 'intuit_ids_aggcat'`
|
20
|
+
for the version in the RubyGems repository that should be production-ready.
|
13
21
|
|
14
22
|
Once installed, you can manually configure the gem at runtime (e.g. in a pure Ruby environment) by doing:
|
15
23
|
`require "intuit_ids_aggcat"`
|
@@ -64,7 +72,7 @@ The gem currently provides the following helper class methods from IntuitIdsAggc
|
|
64
72
|
|
65
73
|
- get_institutions(oauth_token_info, consumer_key, consumer_secret): all arguments optional, a "default" user context will be used for the request and consumer_key and consumer_secret will be pulled from the gem configuration if not specified. Returns an XML document with institution data.
|
66
74
|
- get_institution_detail(id, oauth_token_info, consumer_key, consumer_secret): id is required and is the institution ID for which the detail is retrieved, all other arguments optional, a "default" user context will be used for the request and consumer_key and consumer_secret will be pulled from the gem configuration if not specified. Returns institution detail XML document.
|
67
|
-
- discover_and_add_accounts_with_credentials institution_id, username, creds_hash, oauth_token_info, consumer_key, consumer_secret, timeout): Discovers and adds accounts from institution in the context of username or using the auth_tokens provided using the key/value pairs in creds_hash to populate the credentials/credential elements of the login request message. If no oauth_token_info is provided, new tokens will be provisioned using username. consumer_key, consumer_secret are optional and will be pulled from the gem configuration. timeout is optional, default is 30 seconds
|
75
|
+
- discover_and_add_accounts_with_credentials institution_id, username, creds_hash, oauth_token_info, consumer_key, consumer_secret, timeout): Discovers and adds accounts from institution in the context of username or using the auth_tokens provided using the key/value pairs in creds_hash to populate the credentials/credential elements of the login request message. If no oauth_token_info is provided, new tokens will be provisioned using username. consumer_key, consumer_secret are optional and will be pulled from the gem configuration. timeout is optional, default is 30 seconds
|
68
76
|
- delete_customer(username, oauth_token_info, consumer_key, consumer_secret): Deletes a customer from aggregation in the context of username or using the oauth_tokens provided.
|
69
77
|
|
70
78
|
Return values from all methods except get_institutions and get_institution_detail are a hash with a response_code key with the HTTP response code value and a response_xml key containing a REXML::Document object.
|
@@ -87,7 +95,7 @@ Return values from all methods except get_institutions and get_institution_detai
|
|
87
95
|
|
88
96
|
Testing
|
89
97
|
----------
|
90
|
-
In order to thoroughly test the Intuit integration, many of the RSpec tests included with this gem make live calls to the Intuit services and use Intuit's test financial institutions/customers/accounts. In order for this to work, real OAuth tokens and the corresponding private
|
98
|
+
In order to thoroughly test the Intuit integration, many of the RSpec tests included with this gem make live calls to the Intuit services and use Intuit's test financial institutions/customers/accounts. In order for this to work, real OAuth tokens and the corresponding private key and issuer ID need to be used. To configure these the tests assume there is a YAML configuration in spec/config/real_config.yml in the following format:
|
91
99
|
|
92
100
|
`certificate_path: key_file`
|
93
101
|
`issuer_id: issuer_id`
|
@@ -98,6 +106,11 @@ Note that the tests do create a test user to validate the integration and this w
|
|
98
106
|
|
99
107
|
The .gitignore file contains spec/config/real_config.yml and spec/config/real_cert.key to prevent sensitive information from being checked in. Note that if you change the names, or .gitignore is modified, this may not hold true. Exercise caution when commiting code to public repos.
|
100
108
|
|
109
|
+
Changelog
|
110
|
+
-----------------
|
111
|
+
0.0.7: Added support for updating institution login information with IntuitIdsAggcat::Client::Services.update_institution_login_with_credentials
|
112
|
+
|
113
|
+
|
101
114
|
Contributing
|
102
115
|
-----------------
|
103
116
|
Feel free to fork this repo, make changes and submit a pull request.
|
@@ -4,7 +4,7 @@ class DateTimeNode < XML::Mapping::SingleAttributeNode
|
|
4
4
|
path,*args = super(*args)
|
5
5
|
@path = XML::XXPath.new(path)
|
6
6
|
args
|
7
|
-
end
|
7
|
+
end #
|
8
8
|
|
9
9
|
def extract_attr_value(xml)
|
10
10
|
# without millisecs
|
@@ -39,6 +39,9 @@ module IntuitIdsAggcat
|
|
39
39
|
class Account; end
|
40
40
|
class BankingAccount < Account; end
|
41
41
|
class CreditAccount < Account; end
|
42
|
+
class InvestmentAccount < Account; end
|
43
|
+
class LoanAccount < Account; end
|
44
|
+
class OtherAccount < Account; end
|
42
45
|
class Choice; end
|
43
46
|
class Transaction; end
|
44
47
|
class BankingTransaction < Transaction; end
|
@@ -173,14 +176,14 @@ module IntuitIdsAggcat
|
|
173
176
|
include XML::Mapping
|
174
177
|
array_node :banking_accounts, "BankingAccount", :class => BankingAccount, :default_value => nil
|
175
178
|
array_node :credit_accounts, "CreditAccount", :class => CreditAccount, :default_value => nil
|
176
|
-
|
177
|
-
|
179
|
+
array_node :loan_accounts, "LoanAccount", :class => LoanAccount, :default_value => nil
|
180
|
+
array_node :investment_accounts, "InvestmentAccount", :class => InvestmentAccount, :default_value => nil
|
178
181
|
#array_node :rewards_accounts, "RewardsAccount", :default_value => nil
|
179
|
-
|
182
|
+
array_node :other_accounts, "OtherAccount", :class => OtherAccount, :default_value => nil
|
180
183
|
end
|
181
184
|
|
182
185
|
class Account
|
183
|
-
include XML::Mapping
|
186
|
+
include XML::Mapping
|
184
187
|
numeric_node :account_id, "accountId", :default_value => nil
|
185
188
|
text_node :status, "status", :default_value => nil
|
186
189
|
text_node :account_number, "accountNumber", :default_value => nil
|
@@ -198,7 +201,7 @@ module IntuitIdsAggcat
|
|
198
201
|
date_time_node :aggregation_attempt_date, "aggrAttemptDate", :default_value => nil
|
199
202
|
text_node :currency_code, "currencyCode", :default_value => nil
|
200
203
|
text_node :bank_id, "bankId", :default_value => nil
|
201
|
-
numeric_node :institution_login_id, "
|
204
|
+
numeric_node :institution_login_id, "institutionLoginId", :default_value => nil
|
202
205
|
end
|
203
206
|
|
204
207
|
class BankingAccount < Account
|
@@ -217,6 +220,95 @@ module IntuitIdsAggcat
|
|
217
220
|
numeric_node :maturity_amount, "maturityAmount", :default_value => nil
|
218
221
|
end
|
219
222
|
|
223
|
+
class OtherAccount < Account
|
224
|
+
include XML::Mapping
|
225
|
+
use_mapping :_default
|
226
|
+
end
|
227
|
+
|
228
|
+
class InvestmentAccount < Account
|
229
|
+
include XML::Mapping
|
230
|
+
|
231
|
+
text_node :investment_account_type, "investmentAccountType", :default_value => nil
|
232
|
+
numeric_node :interest_margin_balance, "interestMarginBalance", :default_value => nil
|
233
|
+
numeric_node :short_balance, "shortBalance", :default_value => nil
|
234
|
+
numeric_node :available_cash_balance, "availableCashBalance", :default_value => nil
|
235
|
+
numeric_node :current_balance, "currentBalance", :default_value => nil
|
236
|
+
numeric_node :maturity_value_amount, "maturityValueAmount", :default_value => nil
|
237
|
+
numeric_node :unvested_balance, "unvestedBalance", :default_value => nil
|
238
|
+
numeric_node :emp_match_defer_amount, "empMatchDeferAmount", :default_value => nil
|
239
|
+
numeric_node :emp_match_defer_amount_ytd, "empMatchDeferAmountYtd", :default_value => nil
|
240
|
+
numeric_node :emp_match_amount, "empMatchAmount", :default_value => nil
|
241
|
+
numeric_node :emp_match_amount_ytd, "empMatchAmountYtd", :default_value => nil
|
242
|
+
numeric_node :emp_pre_tax_contrib_amount, "empPretaxContribAmount", :default_value => nil
|
243
|
+
numeric_node :emp_pre_tax_contrib_amount_ytd, "empPretaxContribAmountYtd", :default_value => nil
|
244
|
+
numeric_node :rollover_itd, "rollover_itd", :default_value => nil
|
245
|
+
numeric_node :cash_balance_amount, "cashBalanceAmount", :default_value => nil
|
246
|
+
numeric_node :initial_loan_balance, "initialLoanBalance", :default_value => nil
|
247
|
+
date_time_node :loan_start_date, "loanStartDate", :default_value => nil
|
248
|
+
numeric_node :current_loan_balance, "currentLoanBalance", :default_value => nil
|
249
|
+
numeric_node :loan_rate, "loanRate", :default_value => nil
|
250
|
+
|
251
|
+
end
|
252
|
+
|
253
|
+
class LoanAccount < Account
|
254
|
+
include XML::Mapping
|
255
|
+
text_node :loan_type, "loanType", :default_value => nil
|
256
|
+
date_time_node :posted_date, "postedDate", :default_value => nil
|
257
|
+
text_node :term, "term", :default_value => nil
|
258
|
+
text_node :holder_name, "holderName", :default_value => nil
|
259
|
+
numeric_node :late_fee_amount, "lateFeeAmount", :default_value => nil
|
260
|
+
numeric_node :payoff_amount, "payoffAmount", :default_value => nil
|
261
|
+
date_time_node :payoff_amount_date, "payoffAmountDate", :default_value => nil
|
262
|
+
text_node :reference_number, "referenceNumber", :default_value => nil
|
263
|
+
date_time_node :original_maturity_date, "originalMaturityDate", :default_value => nil
|
264
|
+
text_node :tax_payee_name, "taxPayeeName", :default_value => nil
|
265
|
+
numeric_node :principal_balance, "principalBalance", :default_value => nil
|
266
|
+
numeric_node :escrow_balance, "escrowBalance", :default_value => nil
|
267
|
+
numeric_node :interest_rate, "interestRate", :default_value => nil
|
268
|
+
text_node :interest_period, "interestPeriod", :default_value => nil
|
269
|
+
numeric_node :initial_amount, "initialAmount", :default_value => nil
|
270
|
+
date_time_node :initial_date, "initialDate", :default_value => nil
|
271
|
+
numeric_node :next_payment_principal_amount, "nextPaymentPrincipalAmount", :default_value => nil
|
272
|
+
numeric_node :next_payment_interest_amount, "nextPaymentInterestAmount", :default_value => nil
|
273
|
+
numeric_node :next_payment, "nextPayment", :default_value => nil
|
274
|
+
date_time_node :next_payment_date, "nextPaymentDate", :default_value => nil
|
275
|
+
date_time_node :next_payment_due_date, "nextPaymentDueDate", :default_value => nil
|
276
|
+
date_time_node :next_payment_receive_date, "nextPaymentReceiveDate", :default_value => nil
|
277
|
+
numeric_node :last_payment_amount, "lastPaymentAmount", :default_value => nil
|
278
|
+
numeric_node :last_payment_principal_amount, "lastPaymentPrincipalAmount", :default_value => nil
|
279
|
+
numeric_node :last_payment_interest_amount, "lastPaymentInterestAmount", :default_value => nil
|
280
|
+
numeric_node :last_payment_escrow_amount, "lastPaymentEscrowAmount", :default_value => nil
|
281
|
+
numeric_node :last_payment_last_fee_amount, "lastPaymentLastFeeAmount", :default_value => nil
|
282
|
+
numeric_node :last_payment_late_charge, "lastPaymentLateCharge", :default_value => nil
|
283
|
+
numeric_node :principal_paid_ytd, "principalPaidYTD", :default_value => nil
|
284
|
+
numeric_node :interest_paid_ytd, "interestPaidYTD", :default_value => nil
|
285
|
+
numeric_node :insurance_paid_ytd, "insurancePaidYTD", :default_value => nil
|
286
|
+
numeric_node :tax_paid_ytd, "taxPaidYTD", :default_value => nil
|
287
|
+
boolean_node :auto_pay_enrolled, "autoPayEnrolled", :default_value => nil
|
288
|
+
text_node :collateral, "collateral", :default_value => nil
|
289
|
+
text_node :current_school, "currentSchool", :default_value => nil
|
290
|
+
date_time_node :first_payment_date, "firstPaymentDate", :default_value => nil
|
291
|
+
text_node :guarantor, "guarantor", :default_value => nil
|
292
|
+
boolean_node :first_mortgage, "firstMortgage", :default_value => nil
|
293
|
+
text_node :loan_payment_freq, "loanPaymentFreq", :default_value => nil
|
294
|
+
numeric_node :payment_min_amount, "paymentMinAmount", :default_value => nil
|
295
|
+
text_node :original_school, "originalSchool", :default_value => nil
|
296
|
+
numeric_node :recurring_payment_amount, "recurringPaymentAmount", :default_value => nil
|
297
|
+
text_node :lender, "lender", :default_value => nil
|
298
|
+
numeric_node :ending_balance_amount, "endingBalanceAmount", :default_value => nil
|
299
|
+
numeric_node :available_balance_amount, "availableBalanceAmount", :default_value => nil
|
300
|
+
text_node :loan_term_type, "loanTermType", :default_value => nil
|
301
|
+
numeric_node :no_of_payments, "noOfPayments", :default_value => nil
|
302
|
+
numeric_node :balloon_amount, "balloonAmount", :default_value => nil
|
303
|
+
numeric_node :projected_interest, "projectedInterest", :default_value => nil
|
304
|
+
numeric_node :interest_paid_ltd, "interestPaidLtd", :default_value => nil
|
305
|
+
text_node :interest_rate_type, "interestRateType", :default_value => nil
|
306
|
+
text_node :loan_payment_type, "loanPaymentType", :default_value => nil
|
307
|
+
numeric_node :remainingPayments, "remainingPayments", :default_value => nil
|
308
|
+
|
309
|
+
end
|
310
|
+
|
311
|
+
|
220
312
|
class CreditAccount < Account
|
221
313
|
include XML::Mapping
|
222
314
|
text_node :credit_account_type, "creditAccountType", :default_value => nil
|
@@ -244,12 +336,16 @@ module IntuitIdsAggcat
|
|
244
336
|
class Common
|
245
337
|
include XML::Mapping
|
246
338
|
text_node :normalized_payee_name, "normalizedPayeeName", :default_value => nil
|
339
|
+
text_node :merchant, "merchant", :default_value => nil
|
340
|
+
text_node :sic_code, "sic", :default_value => nil
|
247
341
|
end
|
248
342
|
|
249
343
|
class Context
|
250
344
|
include XML::Mapping
|
251
345
|
text_node :source, "source", :default_value => nil
|
252
346
|
text_node :category_name, "categoryName", :default_value => nil
|
347
|
+
text_node :context_type, "contextType", :default_value => nil
|
348
|
+
text_node :schedule_c_code, "scheduleC", :default_value => nil
|
253
349
|
end
|
254
350
|
|
255
351
|
class Categorization
|
@@ -285,7 +381,6 @@ module IntuitIdsAggcat
|
|
285
381
|
date_time_node :available_date, "availableDate", :default_value => nil
|
286
382
|
numeric_node :amount, "amount", :default_value => nil
|
287
383
|
numeric_node :running_balance_amount, "runningBalanceAmount", :default_value => nil
|
288
|
-
numeric_node :sic, "sic", :default_value => nil
|
289
384
|
boolean_node :pending, "pending", "true", "false", :default_value => nil
|
290
385
|
object_node :categorization, "categorization", :class => Categorization, :default_value => nil
|
291
386
|
end
|
@@ -393,4 +488,4 @@ module IntuitIdsAggcat
|
|
393
488
|
array_node :investment_transactions, "InvestmentTransaction", :class => InvestmentTransaction, :default_value => nil
|
394
489
|
array_node :rewards_transactions, "RewardsTransaction", :class => RewardsTransaction, :default_value => nil
|
395
490
|
end
|
396
|
-
end
|
491
|
+
end
|
@@ -111,13 +111,7 @@ EOF_XML
|
|
111
111
|
end
|
112
112
|
|
113
113
|
def get_tokens username, issuer_id = IntuitIdsAggcat.config.issuer_id, oauth_consumer_key = IntuitIdsAggcat.config.oauth_consumer_key, oauth_consumer_secret = IntuitIdsAggcat.config.oauth_consumer_secret, certificate_path = IntuitIdsAggcat.config.certificate_path, certificate_string = IntuitIdsAggcat.config.certificate_string, certificate_password = IntuitIdsAggcat.config.certificate_password
|
114
|
-
#if !IntuitIdsAggcat.config.oauth_token_info.nil? && !IntuitIdsAggcat.config.oauth_token_info[:oauth_token].nil? && IntuitIdsAggcat.config.oauth_token_info[:token_expiry] > (Time.now + 2)
|
115
|
-
# IntuitIdsAggcat.config.oauth_token_info
|
116
|
-
#else
|
117
114
|
oauth_token_info = get_oauth_info issuer_id, username, oauth_consumer_key, oauth_consumer_secret, certificate_path, certificate_string, certificate_password
|
118
|
-
# IntuitIdsAggcat.config(:oauth_token_info => oauth_token_info)
|
119
|
-
# oauth_token_info
|
120
|
-
#end
|
121
115
|
end
|
122
116
|
|
123
117
|
end
|
@@ -20,8 +20,12 @@ module IntuitIdsAggcat
|
|
20
20
|
# consumer_key and consumer_secret will be retrieved from the Configuration class if not provided
|
21
21
|
def get_institutions oauth_token_info = IntuitIdsAggcat::Client::Saml.get_tokens("default"), consumer_key = IntuitIdsAggcat.config.oauth_consumer_key, consumer_secret = IntuitIdsAggcat.config.oauth_consumer_secret
|
22
22
|
response = oauth_get_request "https://financialdatafeed.platform.intuit.com/rest-war/v1/institutions", oauth_token_info, consumer_key, consumer_secret
|
23
|
-
|
24
|
-
|
23
|
+
if response[:response_code] == "200"
|
24
|
+
institutions = Institutions.load_from_xml(response[:response_xml].root)
|
25
|
+
institutions.institutions
|
26
|
+
else
|
27
|
+
return nil
|
28
|
+
end
|
25
29
|
end
|
26
30
|
|
27
31
|
##
|
@@ -33,6 +37,15 @@ module IntuitIdsAggcat
|
|
33
37
|
institutions
|
34
38
|
end
|
35
39
|
|
40
|
+
##
|
41
|
+
# Get a specific account for a customer from aggregation at Intuit.
|
42
|
+
# username and account ID must be provided, if no oauth_token_info is provided, new tokens will be provisioned using username
|
43
|
+
def get_account username, account_id, oauth_token_info = IntuitIdsAggcat::Client::Saml.get_tokens(username), consumer_key = IntuitIdsAggcat.config.oauth_consumer_key, consumer_secret = IntuitIdsAggcat.config.oauth_consumer_secret
|
44
|
+
url = "https://financialdatafeed.platform.intuit.com/rest-war/v1/accounts/#{account_id}"
|
45
|
+
oauth_get_request url, oauth_token_info
|
46
|
+
end
|
47
|
+
|
48
|
+
|
36
49
|
##
|
37
50
|
# Deletes the customer's accounts from aggregation at Intuit.
|
38
51
|
# username must be provided, if no oauth_token_info is provided, new tokens will be provisioned using username
|
@@ -66,7 +79,9 @@ module IntuitIdsAggcat
|
|
66
79
|
# challenge_session_id: challenge session ID to pass to challenge_response if this is a challenge
|
67
80
|
# challenge_node_id : challenge node ID to pass to challenge_response if this is a challenge
|
68
81
|
# description : text description of the result of the discover request
|
82
|
+
|
69
83
|
def discover_and_add_accounts_with_credentials institution_id, username, creds_hash, oauth_token_info = IntuitIdsAggcat::Client::Saml.get_tokens(username), consumer_key = IntuitIdsAggcat.config.oauth_consumer_key, consumer_secret = IntuitIdsAggcat.config.oauth_consumer_secret, timeout = 30
|
84
|
+
|
70
85
|
url = "https://financialdatafeed.platform.intuit.com/rest-war/v1/institutions/#{institution_id}/logins"
|
71
86
|
credentials_array = []
|
72
87
|
creds_hash.each do |k,v|
|
@@ -102,11 +117,49 @@ module IntuitIdsAggcat
|
|
102
117
|
##
|
103
118
|
# Gets all accounts for a customer
|
104
119
|
def get_customer_accounts username, oauth_token_info = IntuitIdsAggcat::Client::Saml.get_tokens(username), consumer_key = IntuitIdsAggcat.config.oauth_consumer_key, consumer_secret = IntuitIdsAggcat.config.oauth_consumer_secret
|
105
|
-
url = "https://financialdatafeed.platform.intuit.com/
|
120
|
+
url = "https://financialdatafeed.platform.intuit.com/v1/accounts/"
|
121
|
+
response = oauth_get_request url, oauth_token_info
|
122
|
+
accounts = AccountList.load_from_xml(response[:response_xml].root)
|
123
|
+
end
|
124
|
+
|
125
|
+
##
|
126
|
+
# Gets accounts for a specific customer login_id
|
127
|
+
def get_login_accounts login_id, username, oauth_token_info = IntuitIdsAggcat::Client::Saml.get_tokens(username), consumer_key = IntuitIdsAggcat.config.oauth_consumer_key, consumer_secret = IntuitIdsAggcat.config.oauth_consumer_secret
|
128
|
+
url = "https://financialdatafeed.platform.intuit.com/v1/logins/#{login_id}/accounts"
|
106
129
|
response = oauth_get_request url, oauth_token_info
|
107
130
|
accounts = AccountList.load_from_xml(response[:response_xml].root)
|
108
131
|
end
|
109
132
|
|
133
|
+
##
|
134
|
+
# Updates an existing customer account with new credentials at an institution
|
135
|
+
# Response can include an MFA challenge; see the return values for discover_and_add_accounts_with_credentials for
|
136
|
+
# more information on possible responses
|
137
|
+
def update_institution_login_with_credentials login_id, username, creds_hash, oauth_token_info = IntuitIdsAggcat::Client::Saml.get_tokens(username), consumer_key = IntuitIdsAggcat.config.oauth_consumer_key, consumer_secret = IntuitIdsAggcat.config.oauth_consumer_secret
|
138
|
+
url = "https://financialdatafeed.platform.intuit.com/v1/logins/#{login_id}?refresh=true"
|
139
|
+
credentials_array = []
|
140
|
+
creds_hash.each do |k,v|
|
141
|
+
c = Credential.new
|
142
|
+
c.name = k
|
143
|
+
c.value = v
|
144
|
+
credentials_array.push c
|
145
|
+
end
|
146
|
+
creds = Credentials.new
|
147
|
+
creds.credential = credentials_array
|
148
|
+
il = InstitutionLogin.new
|
149
|
+
il.credentials = creds
|
150
|
+
response = oauth_put_request url, oauth_token_info, il.save_to_xml.to_s
|
151
|
+
update_credentials_data_to_hash response
|
152
|
+
end
|
153
|
+
|
154
|
+
##
|
155
|
+
# Explicitly refreshes the customer account with new credentials at an institution
|
156
|
+
def update_institution_login_explicit_refresh login_id, username, oauth_token_info = IntuitIdsAggcat::Client::Saml.get_tokens(username), consumer_key = IntuitIdsAggcat.config.oauth_consumer_key, consumer_secret = IntuitIdsAggcat.config.oauth_consumer_secret
|
157
|
+
url = "https://financialdatafeed.platform.intuit.com/v1/logins/#{login_id}?refresh=true"
|
158
|
+
body = InstitutionLogin.new.save_to_xml.to_s
|
159
|
+
response = oauth_put_request url, oauth_token_info, body
|
160
|
+
return response
|
161
|
+
end
|
162
|
+
|
110
163
|
##
|
111
164
|
# Get transactions for a specific account and timeframe
|
112
165
|
def get_account_transactions username, account_id, start_date, end_date = nil, oauth_token_info = IntuitIdsAggcat::Client::Saml.get_tokens(username), consumer_key = IntuitIdsAggcat.config.oauth_consumer_key, consumer_secret = IntuitIdsAggcat.config.oauth_consumer_secret
|
@@ -121,6 +174,39 @@ module IntuitIdsAggcat
|
|
121
174
|
tl = IntuitIdsAggcat::TransactionList.load_from_xml xml.root
|
122
175
|
end
|
123
176
|
|
177
|
+
##
|
178
|
+
# Helper method for parsing discover credential update response data
|
179
|
+
def update_credentials_data_to_hash daa
|
180
|
+
challenge_type = "none"
|
181
|
+
if daa[:response_code] == "200"
|
182
|
+
# return account list
|
183
|
+
accounts = AccountList.load_from_xml(daa[:response_xml].root)
|
184
|
+
{ update_response: daa, challenge_type: challenge_type, challenge: nil, description: "Account information updated." }
|
185
|
+
elsif daa[:response_code] == "401" && daa[:challenge_session_id]
|
186
|
+
# return challenge
|
187
|
+
challenge = Challenges.load_from_xml(daa[:response_xml].root)
|
188
|
+
challenge_type = "unknown"
|
189
|
+
if challenge.save_to_xml.to_s.include?("<choice>")
|
190
|
+
challenge_type = "choice"
|
191
|
+
elsif challenge.save_to_xml.to_s.include?("image")
|
192
|
+
challenge_type ="image"
|
193
|
+
else
|
194
|
+
challenge_type = "text"
|
195
|
+
end
|
196
|
+
{ update_response: daa, accounts: nil, challenge_type: challenge_type, challenge: challenge, challenge_session_id: daa[:challenge_session_id], challenge_node_id: daa[:challenge_node_id], description: "Multi-factor authentication required to update credentials." }
|
197
|
+
elsif daa[:response_code] == "404"
|
198
|
+
{ update_response: daa, accounts: nil, challenge_type: challenge_type, challenge: nil, description: "Login ID not found." }
|
199
|
+
elsif daa[:response_code] == "408"
|
200
|
+
{ update_response: daa, accounts: nil, challenge_type: challenge_type, challenge: nil, description: "Timed out." }
|
201
|
+
elsif daa[:response_code] == "500"
|
202
|
+
{ update_response: daa, accounts: nil, challenge_type: challenge_type, challenge: nil, description: "Internal server error." }
|
203
|
+
elsif daa[:response_code] == "503"
|
204
|
+
{ update_response: daa, accounts: nil, challenge_type: challenge_type, challenge: nil, description: "Problem at the finanical institution." }
|
205
|
+
else
|
206
|
+
{ update_response: daa, accounts: nil, challenge_type: challenge_type, challenge: nil, description: "Unknown error." }
|
207
|
+
end
|
208
|
+
end
|
209
|
+
|
124
210
|
##
|
125
211
|
# Helper method for parsing discover account response data
|
126
212
|
def discover_account_data_to_hash daa
|
@@ -187,8 +273,34 @@ module IntuitIdsAggcat
|
|
187
273
|
options = options.merge({ :proxy => IntuitIdsAggcat.config.proxy}) if !IntuitIdsAggcat.config.proxy.nil?
|
188
274
|
consumer = OAuth::Consumer.new(consumer_key, consumer_secret, options)
|
189
275
|
access_token = OAuth::AccessToken.new(consumer, oauth_token, oauth_token_secret)
|
190
|
-
|
191
|
-
|
276
|
+
begin
|
277
|
+
response = access_token.get(url, { "Content-Type"=>'application/xml', 'Host' => 'financialdatafeed.platform.intuit.com' })
|
278
|
+
response_xml = REXML::Document.new response.body
|
279
|
+
rescue REXML::ParseException => msg
|
280
|
+
#Rails.logger.error "REXML Parse Exception"
|
281
|
+
return nil
|
282
|
+
end
|
283
|
+
{ :response_code => response.code, :response_xml => response_xml }
|
284
|
+
end
|
285
|
+
|
286
|
+
##
|
287
|
+
# Helper method to issue put requests
|
288
|
+
def oauth_put_request url, oauth_token_info, body = nil, consumer_key = IntuitIdsAggcat.config.oauth_consumer_key, consumer_secret = IntuitIdsAggcat.config.oauth_consumer_secret, timeout = 120
|
289
|
+
oauth_token = oauth_token_info[:oauth_token]
|
290
|
+
oauth_token_secret = oauth_token_info[:oauth_token_secret]
|
291
|
+
|
292
|
+
options = { :request_token_path => 'https://financialdatafeed.platform.intuit.com', :timeout => timeout, :http_method => :put }
|
293
|
+
options = options.merge({ :proxy => IntuitIdsAggcat.config.proxy}) if !IntuitIdsAggcat.config.proxy.nil?
|
294
|
+
consumer = OAuth::Consumer.new(consumer_key, consumer_secret, options)
|
295
|
+
access_token = OAuth::AccessToken.new(consumer, oauth_token, oauth_token_secret)
|
296
|
+
begin
|
297
|
+
response = access_token.put(url, body, { "Content-Type"=>'application/xml', 'Host' => 'financialdatafeed.platform.intuit.com' })
|
298
|
+
response_xml = REXML::Document.new response.body
|
299
|
+
rescue REXML::ParseException => msg
|
300
|
+
#Rails.logger.error "REXML Parse Exception"
|
301
|
+
#Rails.logger.error msg
|
302
|
+
return nil
|
303
|
+
end
|
192
304
|
{ :response_code => response.code, :response_xml => response_xml }
|
193
305
|
end
|
194
306
|
|
data/spec/saml_spec.rb
CHANGED
@@ -21,5 +21,22 @@ describe IntuitIdsAggcat::Client::Saml do
|
|
21
21
|
tokens[:oauth_token].should_not be_nil
|
22
22
|
tokens[:token_expiry].should_not be_nil
|
23
23
|
end
|
24
|
+
|
25
|
+
it "should return different tokens for different usernames" do
|
26
|
+
path = Pathname.new("spec/config/real_config.yml")
|
27
|
+
config = YAML::load(ERB.new(File.read(path)).result)
|
28
|
+
IntuitIdsAggcat.config(config)
|
29
|
+
tokens = IntuitIdsAggcat::Client::Saml.get_tokens "test"
|
30
|
+
tokens[:oauth_token_secret].should_not be_nil
|
31
|
+
tokens[:oauth_token].should_not be_nil
|
32
|
+
tokens[:token_expiry].should_not be_nil
|
33
|
+
tokens2 = IntuitIdsAggcat::Client::Saml.get_tokens "test2"
|
34
|
+
tokens2[:oauth_token_secret].should_not be_nil
|
35
|
+
tokens2[:oauth_token].should_not be_nil
|
36
|
+
tokens2[:token_expiry].should_not be_nil
|
37
|
+
tokens[:oauth_token_secret].should_not eql(tokens2[:oauth_token_secret])
|
38
|
+
tokens[:oauth_token].should_not eql(tokens2[:oauth_token])
|
39
|
+
end
|
40
|
+
|
24
41
|
end
|
25
42
|
|
data/spec/services_spec.rb
CHANGED
@@ -63,13 +63,20 @@ describe IntuitIdsAggcat::Client::Services do
|
|
63
63
|
x.should_not be_nil
|
64
64
|
x.banking_accounts.count.should be > 2
|
65
65
|
|
66
|
+
# get the login ID to use later in the test
|
67
|
+
login_id = x.banking_accounts[0].institution_login_id
|
68
|
+
|
66
69
|
# get transactions from 90 days ago until current
|
67
70
|
start = Time.now - (90 * 24 * 60 * 60)
|
68
|
-
y = IntuitIdsAggcat::Client::Services.get_account_transactions
|
71
|
+
y = IntuitIdsAggcat::Client::Services.get_account_transactions "9cj2hbjfgh47cna72", x.banking_accounts[0].account_id, start
|
69
72
|
y.should_not be_nil
|
70
73
|
y.banking_transactions[0].id.should_not be_nil
|
71
74
|
y.banking_transactions[0].amount.should_not be_nil
|
72
75
|
|
76
|
+
# refresh credentials and confirm we get accounts back again
|
77
|
+
x = IntuitIdsAggcat::Client::Services.update_institution_login_with_credentials login_id, "9cj2hbjfgh47cna72", { "Banking Userid" => "direct", "Banking Password" => "anyvalue" }
|
78
|
+
x[:update_response][:response_code].should == "200"
|
79
|
+
|
73
80
|
# delete customer
|
74
81
|
x = IntuitIdsAggcat::Client::Services.delete_customer "9cj2hbjfgh47cna72"
|
75
82
|
x[:response_code].should == "200"
|
metadata
CHANGED
@@ -1,121 +1,135 @@
|
|
1
|
-
--- !ruby/object:Gem::Specification
|
1
|
+
--- !ruby/object:Gem::Specification
|
2
2
|
name: intuit_ids_aggcat
|
3
|
-
version: !ruby/object:Gem::Version
|
4
|
-
|
5
|
-
|
6
|
-
- 0
|
7
|
-
- 0
|
8
|
-
- 5
|
9
|
-
version: 0.0.5
|
3
|
+
version: !ruby/object:Gem::Version
|
4
|
+
version: 0.0.7
|
5
|
+
prerelease:
|
10
6
|
platform: ruby
|
11
|
-
authors:
|
7
|
+
authors:
|
12
8
|
- Chris Hart
|
13
9
|
autorequire:
|
14
10
|
bindir: bin
|
15
11
|
cert_chain: []
|
16
|
-
|
17
|
-
|
18
|
-
|
19
|
-
dependencies:
|
20
|
-
- !ruby/object:Gem::Dependency
|
12
|
+
date: 2013-07-03 00:00:00.000000000 Z
|
13
|
+
dependencies:
|
14
|
+
- !ruby/object:Gem::Dependency
|
21
15
|
name: rspec
|
22
|
-
|
23
|
-
|
24
|
-
requirements:
|
16
|
+
requirement: !ruby/object:Gem::Requirement
|
17
|
+
none: false
|
18
|
+
requirements:
|
25
19
|
- - ~>
|
26
|
-
- !ruby/object:Gem::Version
|
27
|
-
|
28
|
-
- 2
|
29
|
-
- 11
|
30
|
-
version: "2.11"
|
20
|
+
- !ruby/object:Gem::Version
|
21
|
+
version: '2.11'
|
31
22
|
type: :development
|
32
|
-
version_requirements: *id001
|
33
|
-
- !ruby/object:Gem::Dependency
|
34
|
-
name: vcr
|
35
23
|
prerelease: false
|
36
|
-
|
37
|
-
|
24
|
+
version_requirements: !ruby/object:Gem::Requirement
|
25
|
+
none: false
|
26
|
+
requirements:
|
38
27
|
- - ~>
|
39
|
-
- !ruby/object:Gem::Version
|
40
|
-
|
41
|
-
|
42
|
-
|
43
|
-
|
28
|
+
- !ruby/object:Gem::Version
|
29
|
+
version: '2.11'
|
30
|
+
- !ruby/object:Gem::Dependency
|
31
|
+
name: vcr
|
32
|
+
requirement: !ruby/object:Gem::Requirement
|
33
|
+
none: false
|
34
|
+
requirements:
|
35
|
+
- - ~>
|
36
|
+
- !ruby/object:Gem::Version
|
37
|
+
version: '2.2'
|
44
38
|
type: :development
|
45
|
-
version_requirements: *id002
|
46
|
-
- !ruby/object:Gem::Dependency
|
47
|
-
name: fakeweb
|
48
39
|
prerelease: false
|
49
|
-
|
50
|
-
|
40
|
+
version_requirements: !ruby/object:Gem::Requirement
|
41
|
+
none: false
|
42
|
+
requirements:
|
43
|
+
- - ~>
|
44
|
+
- !ruby/object:Gem::Version
|
45
|
+
version: '2.2'
|
46
|
+
- !ruby/object:Gem::Dependency
|
47
|
+
name: fakeweb
|
48
|
+
requirement: !ruby/object:Gem::Requirement
|
49
|
+
none: false
|
50
|
+
requirements:
|
51
51
|
- - ~>
|
52
|
-
- !ruby/object:Gem::Version
|
53
|
-
|
54
|
-
- 1
|
55
|
-
- 3
|
56
|
-
version: "1.3"
|
52
|
+
- !ruby/object:Gem::Version
|
53
|
+
version: '1.3'
|
57
54
|
type: :development
|
58
|
-
version_requirements: *id003
|
59
|
-
- !ruby/object:Gem::Dependency
|
60
|
-
name: oauth
|
61
55
|
prerelease: false
|
62
|
-
|
63
|
-
|
56
|
+
version_requirements: !ruby/object:Gem::Requirement
|
57
|
+
none: false
|
58
|
+
requirements:
|
59
|
+
- - ~>
|
60
|
+
- !ruby/object:Gem::Version
|
61
|
+
version: '1.3'
|
62
|
+
- !ruby/object:Gem::Dependency
|
63
|
+
name: oauth
|
64
|
+
requirement: !ruby/object:Gem::Requirement
|
65
|
+
none: false
|
66
|
+
requirements:
|
64
67
|
- - ~>
|
65
|
-
- !ruby/object:Gem::Version
|
66
|
-
|
67
|
-
- 0
|
68
|
-
- 4
|
69
|
-
version: "0.4"
|
68
|
+
- !ruby/object:Gem::Version
|
69
|
+
version: '0.4'
|
70
70
|
type: :runtime
|
71
|
-
version_requirements: *id004
|
72
|
-
- !ruby/object:Gem::Dependency
|
73
|
-
name: nokogiri
|
74
71
|
prerelease: false
|
75
|
-
|
76
|
-
|
72
|
+
version_requirements: !ruby/object:Gem::Requirement
|
73
|
+
none: false
|
74
|
+
requirements:
|
75
|
+
- - ~>
|
76
|
+
- !ruby/object:Gem::Version
|
77
|
+
version: '0.4'
|
78
|
+
- !ruby/object:Gem::Dependency
|
79
|
+
name: nokogiri
|
80
|
+
requirement: !ruby/object:Gem::Requirement
|
81
|
+
none: false
|
82
|
+
requirements:
|
77
83
|
- - ~>
|
78
|
-
- !ruby/object:Gem::Version
|
79
|
-
|
80
|
-
- 1
|
81
|
-
- 5
|
82
|
-
version: "1.5"
|
84
|
+
- !ruby/object:Gem::Version
|
85
|
+
version: '1.5'
|
83
86
|
type: :runtime
|
84
|
-
version_requirements: *id005
|
85
|
-
- !ruby/object:Gem::Dependency
|
86
|
-
name: xml-mapping
|
87
87
|
prerelease: false
|
88
|
-
|
89
|
-
|
90
|
-
|
91
|
-
|
92
|
-
|
93
|
-
|
94
|
-
|
88
|
+
version_requirements: !ruby/object:Gem::Requirement
|
89
|
+
none: false
|
90
|
+
requirements:
|
91
|
+
- - ~>
|
92
|
+
- !ruby/object:Gem::Version
|
93
|
+
version: '1.5'
|
94
|
+
- !ruby/object:Gem::Dependency
|
95
|
+
name: xml-mapping
|
96
|
+
requirement: !ruby/object:Gem::Requirement
|
97
|
+
none: false
|
98
|
+
requirements:
|
99
|
+
- - ! '>='
|
100
|
+
- !ruby/object:Gem::Version
|
101
|
+
version: '0'
|
95
102
|
type: :runtime
|
96
|
-
version_requirements: *id006
|
97
|
-
- !ruby/object:Gem::Dependency
|
98
|
-
name: activesupport
|
99
103
|
prerelease: false
|
100
|
-
|
101
|
-
|
102
|
-
|
103
|
-
|
104
|
-
|
105
|
-
|
106
|
-
|
104
|
+
version_requirements: !ruby/object:Gem::Requirement
|
105
|
+
none: false
|
106
|
+
requirements:
|
107
|
+
- - ! '>='
|
108
|
+
- !ruby/object:Gem::Version
|
109
|
+
version: '0'
|
110
|
+
- !ruby/object:Gem::Dependency
|
111
|
+
name: activesupport
|
112
|
+
requirement: !ruby/object:Gem::Requirement
|
113
|
+
none: false
|
114
|
+
requirements:
|
115
|
+
- - ! '>='
|
116
|
+
- !ruby/object:Gem::Version
|
117
|
+
version: '0'
|
107
118
|
type: :runtime
|
108
|
-
|
119
|
+
prerelease: false
|
120
|
+
version_requirements: !ruby/object:Gem::Requirement
|
121
|
+
none: false
|
122
|
+
requirements:
|
123
|
+
- - ! '>='
|
124
|
+
- !ruby/object:Gem::Version
|
125
|
+
version: '0'
|
109
126
|
description: Provides a wrapped for the IPP AggCat interfaces
|
110
|
-
email:
|
127
|
+
email:
|
111
128
|
- chris@rewardsummit.com
|
112
129
|
executables: []
|
113
|
-
|
114
130
|
extensions: []
|
115
|
-
|
116
131
|
extra_rdoc_files: []
|
117
|
-
|
118
|
-
files:
|
132
|
+
files:
|
119
133
|
- README.markdown
|
120
134
|
- LICENSE.txt
|
121
135
|
- lib/intuit_ids_aggcat/client/intuit_xml_mappings.rb
|
@@ -126,37 +140,38 @@ files:
|
|
126
140
|
- lib/intuit_ids_aggcat/rails.rb
|
127
141
|
- lib/intuit_ids_aggcat/version.rb
|
128
142
|
- lib/intuit_ids_aggcat.rb
|
129
|
-
|
130
|
-
|
143
|
+
- spec/config/intuit_ids_aggcat.yml
|
144
|
+
- spec/config/test.crt
|
145
|
+
- spec/configuration_spec.rb
|
146
|
+
- spec/rails_spec.rb
|
147
|
+
- spec/saml_spec.rb
|
148
|
+
- spec/services_spec.rb
|
149
|
+
- spec/spec_helper.rb
|
150
|
+
homepage: ''
|
131
151
|
licenses: []
|
132
|
-
|
133
152
|
post_install_message:
|
134
153
|
rdoc_options: []
|
135
|
-
|
136
|
-
require_paths:
|
154
|
+
require_paths:
|
137
155
|
- lib
|
138
|
-
required_ruby_version: !ruby/object:Gem::Requirement
|
139
|
-
|
140
|
-
|
141
|
-
|
142
|
-
|
143
|
-
|
144
|
-
|
145
|
-
|
146
|
-
requirements:
|
147
|
-
- -
|
148
|
-
- !ruby/object:Gem::Version
|
149
|
-
|
150
|
-
- 0
|
151
|
-
version: "0"
|
156
|
+
required_ruby_version: !ruby/object:Gem::Requirement
|
157
|
+
none: false
|
158
|
+
requirements:
|
159
|
+
- - ! '>='
|
160
|
+
- !ruby/object:Gem::Version
|
161
|
+
version: '0'
|
162
|
+
required_rubygems_version: !ruby/object:Gem::Requirement
|
163
|
+
none: false
|
164
|
+
requirements:
|
165
|
+
- - ! '>='
|
166
|
+
- !ruby/object:Gem::Version
|
167
|
+
version: '0'
|
152
168
|
requirements: []
|
153
|
-
|
154
169
|
rubyforge_project: intuit_ids_aggcat
|
155
|
-
rubygems_version: 1.
|
170
|
+
rubygems_version: 1.8.25
|
156
171
|
signing_key:
|
157
172
|
specification_version: 3
|
158
173
|
summary: Integration for Intuit's aggregation and categorization services
|
159
|
-
test_files:
|
174
|
+
test_files:
|
160
175
|
- spec/config/intuit_ids_aggcat.yml
|
161
176
|
- spec/config/test.crt
|
162
177
|
- spec/configuration_spec.rb
|