dinero 0.0.6 → 0.0.7
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/Gemfile.lock +1 -1
- data/README.md +6 -4
- data/examples/scottrade.rb +32 -0
- data/lib/dinero.rb +1 -0
- data/lib/dinero/banks/scottrade.rb +119 -0
- data/lib/dinero/version.rb +1 -1
- data/spec/banks/scottrade_spec.rb +56 -0
- metadata +5 -1
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA1:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 10736ddeeabb779f6f1654971c33c8169633337a
|
4
|
+
data.tar.gz: 71d3256e43c8e91f52655efafe2ce6a397f8a81f
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 55469145a47545ba9829e3062ea1e4652d7e9b4911ed42f7217d23cb8b5c3d0c1b1a8a01d753f5ecfb78b66702d575890b32188c0fcd4ec5ce367b139da63f18
|
7
|
+
data.tar.gz: c149aeccd49f59004e5310777f4234e41082f86482dc6122adbc5e106ed26911f9fa2fe93ed55aa094cb7c6a98d38d39f245ed1dc39e0218796d32d0d393c3b3
|
data/Gemfile.lock
CHANGED
data/README.md
CHANGED
@@ -26,10 +26,12 @@ Much like ActiveRecord sought to standardize the API for accessing and modeling
|
|
26
26
|
|
27
27
|
The following banks are implemented:
|
28
28
|
|
29
|
-
* Capital One - https://capitalone.com (only U.S. credit card logins -- there's also banking, loans, investing, business, and Canada/UK credit cards)
|
30
|
-
* Capital One 360 - https://capitalone360.com (formerly Ing Direct).
|
31
|
-
* South State Bank - https://www.southstatebank.com/
|
32
|
-
* San Diego County Credit Union - https://www.sdccu.com/
|
29
|
+
* Capital One - https://capitalone.com (only U.S. credit card logins -- there's also banking, loans, investing, business, and Canada/UK credit cards)
|
30
|
+
* Capital One 360 - https://capitalone360.com (formerly Ing Direct).
|
31
|
+
* South State Bank - https://www.southstatebank.com/
|
32
|
+
* San Diego County Credit Union - https://www.sdccu.com/
|
33
|
+
* Georgia's Own Credit Union - https://www.georgiasown.org/
|
34
|
+
* Scottrade - https://www.scottrade.com/
|
33
35
|
|
34
36
|
Currently, only Accounts balances are implemented. The following properties are available on each Account:
|
35
37
|
|
@@ -0,0 +1,32 @@
|
|
1
|
+
require_relative '../lib/dinero'
|
2
|
+
require 'pry-byebug'
|
3
|
+
|
4
|
+
@config = YAML.load_file('spec/config/banks.yml').fetch("scottrade2", {})
|
5
|
+
|
6
|
+
@username = @config["username"]
|
7
|
+
@password = @config["password"]
|
8
|
+
|
9
|
+
def camelize term
|
10
|
+
string = term.to_s.sub(/^[a-z\d]*/) { $&.capitalize }
|
11
|
+
string.gsub!(/(?:_|(\/))([a-z\d]*)/i) { "#{$1}#{$2.capitalize}" }
|
12
|
+
string.gsub!(/\//, '::')
|
13
|
+
string
|
14
|
+
end
|
15
|
+
|
16
|
+
def show_balances bank
|
17
|
+
puts "Retrieving your bank account information..."
|
18
|
+
bank.accounts
|
19
|
+
|
20
|
+
puts "+" + "-" * 80 + "+"
|
21
|
+
puts "| %35s | %12s | %11s | %11s |" % %w(name number balance available)
|
22
|
+
puts "+" + "-" * 80 + "+"
|
23
|
+
bank.accounts.each do |acct|
|
24
|
+
puts "| %35s | %12s | $%10.2f | $%10.2f |" % [acct.name, acct.number, acct.balance, acct.available]
|
25
|
+
end
|
26
|
+
puts "+" + "-" * 80 + "+"
|
27
|
+
end
|
28
|
+
|
29
|
+
bank = Dinero::Bank::Scottrade.new(username: @username, password: @password)
|
30
|
+
|
31
|
+
bank.login!
|
32
|
+
show_balances bank
|
data/lib/dinero.rb
CHANGED
@@ -10,6 +10,7 @@ require_relative 'dinero/banks/capital_one_360'
|
|
10
10
|
require_relative 'dinero/banks/south_state_bank'
|
11
11
|
require_relative 'dinero/banks/sdccu'
|
12
12
|
require_relative 'dinero/banks/georgias_own'
|
13
|
+
require_relative 'dinero/banks/scottrade'
|
13
14
|
|
14
15
|
# Models
|
15
16
|
require_relative 'dinero/account'
|
@@ -0,0 +1,119 @@
|
|
1
|
+
module Dinero
|
2
|
+
module Bank
|
3
|
+
# San Diego County Credit Union
|
4
|
+
class Scottrade < Base
|
5
|
+
LOGIN_URL = "https://trading.scottrade.com/default.aspx"
|
6
|
+
CONNECTION_TIMEOUT = 20
|
7
|
+
|
8
|
+
def default_options
|
9
|
+
{ timeout: CONNECTION_TIMEOUT, login_url: LOGIN_URL }
|
10
|
+
end
|
11
|
+
|
12
|
+
def post_username!
|
13
|
+
screenshot_on_error do
|
14
|
+
wait.until { connection.find_element(id: "ctl00_body_txtAccountNumber") }
|
15
|
+
username_field = connection.find_element(id: "ctl00_body_txtAccountNumber")
|
16
|
+
username_field.send_keys username
|
17
|
+
end
|
18
|
+
end
|
19
|
+
|
20
|
+
def post_password!
|
21
|
+
screenshot_on_error do
|
22
|
+
password_field = connection.find_element(id: "ctl00_body_txtPassword")
|
23
|
+
password_field.send_keys password
|
24
|
+
|
25
|
+
login_btn = connection.find_element(id: "ctl00_body_btnLogin")
|
26
|
+
login_btn.click
|
27
|
+
end
|
28
|
+
end
|
29
|
+
|
30
|
+
def skip_confirmations_page
|
31
|
+
if connection.page_source =~ /has trade confirmations/
|
32
|
+
button = connection.find_element(id: "ctl00_body_btnViewLater")
|
33
|
+
button.click
|
34
|
+
end
|
35
|
+
end
|
36
|
+
|
37
|
+
# <button type="button" class="ui-button ui-widget ui-state-default ui-corner-all ui-button-text-only" role="button" aria-disabled="false"><span class="ui-button-text">Close</span></button>
|
38
|
+
def skip_monthly_statements_modal
|
39
|
+
if connection.page_source =~ /ui\-dialog\-title\-monthlyStatementsDiv/
|
40
|
+
button = connection.find_element(xpath: "button[@class='ui-button ui-widget ui-state-default ui-corner-all ui-button-text-only']")
|
41
|
+
button.click
|
42
|
+
end
|
43
|
+
end
|
44
|
+
|
45
|
+
def post_credentials!
|
46
|
+
post_username!
|
47
|
+
post_password!
|
48
|
+
skip_confirmations_page
|
49
|
+
skip_monthly_statements_modal
|
50
|
+
expand_bank_table
|
51
|
+
end
|
52
|
+
|
53
|
+
def after_successful_login
|
54
|
+
# the subdomain frequently changes, so capture the actual URL
|
55
|
+
# so we can return to the page if necessary.
|
56
|
+
@accounts_summary_url = connection.current_url
|
57
|
+
end
|
58
|
+
|
59
|
+
def on_accounts_summary_page?
|
60
|
+
connection.page_source =~ /Brokerage Balances/
|
61
|
+
end
|
62
|
+
|
63
|
+
def goto_accounts_summary_page
|
64
|
+
return if authenticated? && on_accounts_summary_page?
|
65
|
+
authenticated? ? connection.navigate.to(@accounts_summary_url) : login!
|
66
|
+
end
|
67
|
+
|
68
|
+
def expand_bank_table
|
69
|
+
return unless connection.page_source =~ /ctl00_PageContent_ctl02_w1_widgetContent1_lblDisplayBankBalanceLink/
|
70
|
+
expand_link = connection.find_element(id: "ctl00_PageContent_ctl02_w1_widgetContent1_lblDisplayBankBalanceLink")
|
71
|
+
expand_link.click
|
72
|
+
wait.until { connection.find_element(id: "bankBalance66") }
|
73
|
+
end
|
74
|
+
|
75
|
+
def brokerage_table
|
76
|
+
accounts_summary_document.css("#ctl00_PageContent_ctl02_w1_widgetContent1_tblBalanceElements66").first
|
77
|
+
end
|
78
|
+
|
79
|
+
def bank_table
|
80
|
+
table = accounts_summary_document.css("#bankBalance66")
|
81
|
+
end
|
82
|
+
|
83
|
+
def brokerage_data
|
84
|
+
rows = brokerage_table.xpath("tbody/tr").map{|tr| tr.xpath("td").map(&:text)}
|
85
|
+
available = rows.shift.last
|
86
|
+
rows.shift
|
87
|
+
rows.shift
|
88
|
+
balance = rows.shift.last
|
89
|
+
return { available: available, balance: balance }
|
90
|
+
end
|
91
|
+
|
92
|
+
def brokerage_account
|
93
|
+
data = brokerage_data
|
94
|
+
Account.new :brokerage, username, username, data[:balance], data[:available]
|
95
|
+
end
|
96
|
+
|
97
|
+
def bank_data
|
98
|
+
rows = bank_table.xpath("tbody/tr").map{|tr| tr.xpath("td").map(&:text)}
|
99
|
+
available = rows.shift.last
|
100
|
+
balance = rows.shift.last
|
101
|
+
return { available: available, balance: balance }
|
102
|
+
rescue
|
103
|
+
return nil
|
104
|
+
end
|
105
|
+
|
106
|
+
def bank_account
|
107
|
+
if data = bank_data
|
108
|
+
Account.new :bank, "Bank", "", data[:balance], data[:available]
|
109
|
+
end
|
110
|
+
end
|
111
|
+
|
112
|
+
# extract account data from the account summary page
|
113
|
+
def accounts
|
114
|
+
return @accounts if @accounts
|
115
|
+
@accounts = [ brokerage_account, bank_account ].compact
|
116
|
+
end
|
117
|
+
end
|
118
|
+
end
|
119
|
+
end
|
data/lib/dinero/version.rb
CHANGED
@@ -0,0 +1,56 @@
|
|
1
|
+
require 'spec_helper'
|
2
|
+
|
3
|
+
if bank_configured? :scottrade
|
4
|
+
|
5
|
+
RSpec.describe Dinero::Bank::Scottrade do
|
6
|
+
let(:bank_configuration) { bank_configurations[:scottrade] }
|
7
|
+
let(:account_types) { bank_configuration[:account_types] }
|
8
|
+
let(:accounts) { bank_configuration[:accounts] }
|
9
|
+
let(:acct_name) { bank_configuration[:acct_name] }
|
10
|
+
|
11
|
+
before(:all) do
|
12
|
+
VCR.use_cassette("accounts_scottrade", record: :new_episodes) do
|
13
|
+
@bank = Dinero::Bank::Scottrade.new(bank_configurations[:scottrade])
|
14
|
+
@bank.accounts
|
15
|
+
end
|
16
|
+
end
|
17
|
+
|
18
|
+
it "authenticates" do
|
19
|
+
@bank.login!
|
20
|
+
expect(@bank.authenticated?).to eq true
|
21
|
+
end
|
22
|
+
|
23
|
+
it "retrieves accounts_summary_document" do
|
24
|
+
expect(@bank.accounts_summary_document).to be_kind_of Nokogiri::HTML::Document
|
25
|
+
end
|
26
|
+
|
27
|
+
it "has brokerage_table" do
|
28
|
+
expect(@bank.brokerage_data.size).to eq 2
|
29
|
+
end
|
30
|
+
|
31
|
+
it "gets expected accounts" do
|
32
|
+
expect(@bank.accounts.size).to eq accounts
|
33
|
+
end
|
34
|
+
|
35
|
+
it "extracts account names" do
|
36
|
+
expect(@bank.accounts.map(&:name)).to_not be_empty
|
37
|
+
end
|
38
|
+
|
39
|
+
it "extracts account numbers" do
|
40
|
+
expect(@bank.accounts.map(&:number).first).to start_with "513"
|
41
|
+
end
|
42
|
+
|
43
|
+
it "expects balances to be greater than zero" do
|
44
|
+
expect(@bank.accounts.map(&:balance).any?(&:zero?)).to eq false
|
45
|
+
end
|
46
|
+
|
47
|
+
it "expects availables to be greater than zero for bank accts" do
|
48
|
+
expect(@bank.accounts.map(&:available).any?(&:zero?)).to eq false
|
49
|
+
end
|
50
|
+
|
51
|
+
it "sets account types" do
|
52
|
+
expect(@bank.accounts.map(&:account_type).uniq).to eq account_types
|
53
|
+
end
|
54
|
+
end
|
55
|
+
|
56
|
+
end
|
metadata
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: dinero
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.0.
|
4
|
+
version: 0.0.7
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Michael Lang
|
@@ -169,6 +169,7 @@ files:
|
|
169
169
|
- Rakefile
|
170
170
|
- dinero.gemspec
|
171
171
|
- examples/get_balances.rb
|
172
|
+
- examples/scottrade.rb
|
172
173
|
- examples/sdccu.rb
|
173
174
|
- lib/dinero.rb
|
174
175
|
- lib/dinero/account.rb
|
@@ -176,6 +177,7 @@ files:
|
|
176
177
|
- lib/dinero/banks/capital_one.rb
|
177
178
|
- lib/dinero/banks/capital_one_360.rb
|
178
179
|
- lib/dinero/banks/georgias_own.rb
|
180
|
+
- lib/dinero/banks/scottrade.rb
|
179
181
|
- lib/dinero/banks/sdccu.rb
|
180
182
|
- lib/dinero/banks/south_state_bank.rb
|
181
183
|
- lib/dinero/version.rb
|
@@ -183,6 +185,7 @@ files:
|
|
183
185
|
- spec/banks/capital_one_360_spec.rb
|
184
186
|
- spec/banks/capital_one_spec.rb
|
185
187
|
- spec/banks/georgias_own_spec.rb
|
188
|
+
- spec/banks/scottrade_spec.rb
|
186
189
|
- spec/banks/sdccu_spec.rb
|
187
190
|
- spec/banks/south_state_bank_spec.rb
|
188
191
|
- spec/fixtures/vcr_cassettes/.keep
|
@@ -217,6 +220,7 @@ test_files:
|
|
217
220
|
- spec/banks/capital_one_360_spec.rb
|
218
221
|
- spec/banks/capital_one_spec.rb
|
219
222
|
- spec/banks/georgias_own_spec.rb
|
223
|
+
- spec/banks/scottrade_spec.rb
|
220
224
|
- spec/banks/sdccu_spec.rb
|
221
225
|
- spec/banks/south_state_bank_spec.rb
|
222
226
|
- spec/fixtures/vcr_cassettes/.keep
|