commerce-bank-client 1.0.0 → 1.1.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.
data.tar.gz.sig CHANGED
Binary file
data/Manifest CHANGED
@@ -1,6 +1,7 @@
1
1
  Manifest
2
2
  README.markdown
3
3
  Rakefile
4
+ lib/commerce-bank-client.rb
4
5
  lib/commercebank.rb
5
6
  lib/commercebank/monkey.rb
6
7
  test/commerce_bank_client_test.rb
data/Rakefile CHANGED
@@ -2,7 +2,7 @@ require 'rubygems'
2
2
  require 'rake'
3
3
  require 'echoe'
4
4
 
5
- Echoe.new("commerce-bank-client", "1.0.0") do |p|
5
+ Echoe.new("commerce-bank-client", "1.1.0") do |p|
6
6
 
7
7
  p.description = "An interface to the Commerce Bank website (https://banking.commercebank.com)."
8
8
  p.url = "http://github.com/alexmchale/commerce-bank-client"
@@ -2,7 +2,7 @@
2
2
 
3
3
  Gem::Specification.new do |s|
4
4
  s.name = %q{commerce-bank-client}
5
- s.version = "1.0.0"
5
+ s.version = "1.1.0"
6
6
 
7
7
  s.required_rubygems_version = Gem::Requirement.new(">= 1.2") if s.respond_to? :required_rubygems_version=
8
8
  s.authors = ["Alex McHale"]
@@ -10,8 +10,8 @@ Gem::Specification.new do |s|
10
10
  s.date = %q{2010-09-02}
11
11
  s.description = %q{An interface to the Commerce Bank website (https://banking.commercebank.com).}
12
12
  s.email = %q{alexmchale@gmail.com}
13
- s.extra_rdoc_files = ["README.markdown", "lib/commercebank.rb", "lib/commercebank/monkey.rb"]
14
- s.files = ["Manifest", "README.markdown", "Rakefile", "lib/commercebank.rb", "lib/commercebank/monkey.rb", "test/commerce_bank_client_test.rb", "test/monkeypatch_test.rb", "test/test_helper.rb", "commerce-bank-client.gemspec"]
13
+ s.extra_rdoc_files = ["README.markdown", "lib/commerce-bank-client.rb", "lib/commercebank.rb", "lib/commercebank/monkey.rb"]
14
+ s.files = ["Manifest", "README.markdown", "Rakefile", "lib/commerce-bank-client.rb", "lib/commercebank.rb", "lib/commercebank/monkey.rb", "test/commerce_bank_client_test.rb", "test/monkeypatch_test.rb", "test/test_helper.rb", "commerce-bank-client.gemspec"]
15
15
  s.homepage = %q{http://github.com/alexmchale/commerce-bank-client}
16
16
  s.rdoc_options = ["--line-numbers", "--inline-source", "--title", "Commerce-bank-client", "--main", "README.markdown"]
17
17
  s.require_paths = ["lib"]
@@ -0,0 +1,232 @@
1
+ require 'rubygems'
2
+ require 'net/http'
3
+ require 'net/https'
4
+ require 'hpricot'
5
+ require 'andand'
6
+ require 'cgi'
7
+ require 'yaml'
8
+ require 'time'
9
+ require 'date'
10
+ require 'json'
11
+ require 'htmlentities'
12
+ require 'gmail'
13
+ require 'appconfig'
14
+ require 'commercebank/monkey.rb'
15
+
16
+ class Fixnum
17
+ def days; 24 * hours; end
18
+ def hours; 60 * minutes; end
19
+ def minutes; 60 * seconds; end
20
+ def seconds; self; end
21
+ end
22
+
23
+ class WebClient
24
+ attr_reader :fields, :cookies
25
+
26
+ def initialize
27
+ @cookies = Hash.new
28
+ @http = Net::HTTP.new('banking.commercebank.com', 443)
29
+ @http.use_ssl = true
30
+ @http.verify_mode = OpenSSL::SSL::VERIFY_NONE
31
+ end
32
+
33
+ def get(path, form = nil)
34
+ response = @http.get(path, header)
35
+ add_cookies(response)
36
+ @fields = (form && get_form(response.body, form)) || Hash.new
37
+ response
38
+ end
39
+
40
+ def post(path, form = nil)
41
+ response = @http.post(path, @fields.to_url, header)
42
+ add_cookies(response)
43
+ @fields = (form && get_form(response.body, form)) || Hash.new
44
+ response
45
+ end
46
+
47
+ private
48
+
49
+ def header
50
+ { 'Cookie' => @cookies.to_cookie }
51
+ end
52
+
53
+ def get_form(body, name)
54
+ Hpricot.buffer_size = 262144
55
+ doc = Hpricot.parse(body)
56
+ form = (doc/"##{name}").first
57
+ raise "could not find form #{name}" unless form
58
+ fields = Hash[*((form/"input").map {|e| [ e.attributes['name'], e.attributes['value'] ]}.flatten)]
59
+ fields['TestJavaScript'] = 'OK'
60
+ fields
61
+ end
62
+
63
+ def add_cookies(response)
64
+ CGI::Cookie.parse(response.header['set-cookie']).each do |key, value|
65
+ @cookies[key] = value.first
66
+ end
67
+
68
+ @cookies.delete 'path'
69
+ @cookies.delete 'expires'
70
+
71
+ self
72
+ end
73
+ end
74
+
75
+ class CommerceBank
76
+ attr_reader :pending, :register, :current, :available
77
+
78
+ def initialize
79
+ @config = AppConfig.new('~/.commerce.yaml')
80
+
81
+ client = WebClient.new
82
+
83
+ client.get('/')
84
+
85
+ client.get('/CBI/login.aspx', 'MAINFORM')
86
+
87
+ client.fields['txtUserID'] = @config.get('username')
88
+ response = client.post('/CBI/login.aspx', 'MAINFORM')
89
+
90
+ # If a question was asked, answer it then get the password page.
91
+ question = response.body.scan(/Your security question:&nbsp;&nbsp;(.*?)<\/td>/i).first.andand.first
92
+ if question
93
+ client.fields['txtChallengeAnswer'] = @config.get(question)
94
+ client.fields['saveComputer'] = 'rdoBindDeviceNo'
95
+ response = client.post('/CBI/login.aspx', 'MAINFORM')
96
+ end
97
+
98
+ raise "could not reach the password page" unless client.fields['__EVENTTARGET'] == 'btnLogin'
99
+
100
+ client.fields['txtPassword'] = @config.get('password')
101
+ response = client.post('/CBI/login.aspx')
102
+
103
+ response = client.get('/CBI/Accounts/CBI/Activity.aspx', 'MAINFORM')
104
+ (@current, @available) = parse_balance(response.body)
105
+ @pending = parse_pending(response.body)
106
+
107
+ client.fields['Anthem_UpdatePage'] = 'true'
108
+ client.fields['txtFilterFromDate:textBox'] = (Time.now - 30.days).strftime('%m/%d/%Y')
109
+ client.fields['txtFilterToDate:textBox'] = Time.now.strftime('%m/%d/%Y')
110
+ response = client.post('/CBI/Accounts/CBI/Activity.aspx?Anthem_CallBack=true')
111
+
112
+ raw_data = JSON.parse(response.body)
113
+ @register = parse_register(raw_data['controls']['pnlPosted'])
114
+
115
+ @register.each do |entry|
116
+ entry[:images].map! do |image_url|
117
+ url = "https://banking.commercebank.com/CBI/Accounts/CBI/#{image_url[:url]}"
118
+ client.get(url).andand.body
119
+ end
120
+ entry[:images].compact!
121
+ end
122
+ end
123
+
124
+ def daily_summary
125
+ today, yesterday, this_week, last_week = [], [], [], []
126
+
127
+ register.each do |entry|
128
+ if entry[:date] == Date.today then today << entry
129
+ elsif entry[:date] == (Date.today - 1) then yesterday << entry
130
+ elsif entry[:date] >= Date.today.last_sunday then this_week << entry
131
+ elsif entry[:date] >= (Date.today.last_sunday - 1).last_sunday then last_week << entry
132
+ end
133
+ end
134
+
135
+ yield 'Pending', @pending
136
+ yield 'Today', today
137
+ yield 'Yesterday', yesterday
138
+ yield 'This Week', this_week
139
+ yield 'Last Week', last_week
140
+ end
141
+
142
+ def monthly_summary(day_in_month = (Date.today - Date.today.day))
143
+ first_of_month = day_in_month - day_in_month.day + 1
144
+ last_of_month = first_of_month + day_in_month.days_in_month - 1
145
+
146
+ entries = register.find_all {|entry| entry[:date] >= first_of_month && entry[:date] <= last_of_month}
147
+
148
+ yield day_in_month.strftime('%B'), entries
149
+ end
150
+
151
+ private
152
+
153
+ def parse_balance(body)
154
+ Hpricot.buffer_size = 262144
155
+ doc = Hpricot.parse(body)
156
+ summaryRows = doc/"table.summaryTable"/"tr"
157
+ current = (summaryRows[3]/"td")[1].inner_html.to_cents
158
+ available = (summaryRows[4]/"td")[1].inner_html.to_cents
159
+ [current, available]
160
+ end
161
+
162
+ def parse_pending(body)
163
+ Hpricot.buffer_size = 262144
164
+ doc = Hpricot.parse(body)
165
+ coder = HTMLEntities.new
166
+
167
+ (doc/"#grdMemoPosted"/"tr").map do |e|
168
+ next nil unless (e['class'] == 'item' || e['class'] == 'alternatingItem')
169
+
170
+ values = (e/"td").map {|e1| coder.decode(e1.inner_html.strip)}
171
+
172
+ debit = values[2].to_cents
173
+ credit = values[3].to_cents
174
+ delta = credit - debit
175
+
176
+ { :date => parse_date(values[0]),
177
+ :destination => values[1],
178
+ :delta => delta,
179
+ :debit => debit,
180
+ :credit => credit }
181
+ end.compact
182
+ end
183
+
184
+ def parse_register(body)
185
+ Hpricot.buffer_size = 262144
186
+ doc = Hpricot.parse(body)
187
+ coder = HTMLEntities.new
188
+ (doc/"#grdHistory"/"tr").map do |e|
189
+ next nil unless [ 'item', 'alternatingitem' ].include? e['class'].to_s.downcase
190
+
191
+ anchor = e.at("a")
192
+ values = (e/"td").map {|e1| e1.inner_html}
193
+ date = parse_date(values[0])
194
+ check = values[1].strip
195
+ debit = values[3].to_cents
196
+ credit = values[4].to_cents
197
+ delta = credit - debit
198
+ total = values[5].scan(/\$[\d,]+\.\d\d/).first.to_cents
199
+
200
+ images = (e/"a").find_all do |e1|
201
+ e1['target'].to_s.downcase == 'checkimage'
202
+ end.map do |e1|
203
+ { :url => e1['href'], :title => e1.inner_html.strip }
204
+ end
205
+
206
+ {
207
+ :destination => coder.decode(anchor.inner_html.strip),
208
+ :url => anchor['href'],
209
+ :date => date,
210
+ :check => check,
211
+ :images => images,
212
+ :delta => delta,
213
+ :debit => debit,
214
+ :credit => credit,
215
+ :total => total
216
+ }
217
+ end.compact
218
+ end
219
+
220
+ def parse_date(date_string)
221
+ (month, day, year) = date_string.scan(/(\d+)\/(\d+)\/(\d+)/).first
222
+ return nil unless month && day && year
223
+
224
+ month = month.to_i
225
+ day = day.to_i
226
+ year = year.to_i
227
+ year += 2000 if year < 100
228
+
229
+ Date.parse("%04d-%02d-%02d" % [ year, month, day ])
230
+ end
231
+ end
232
+
metadata CHANGED
@@ -1,13 +1,13 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: commerce-bank-client
3
3
  version: !ruby/object:Gem::Version
4
- hash: 23
4
+ hash: 19
5
5
  prerelease: false
6
6
  segments:
7
7
  - 1
8
+ - 1
8
9
  - 0
9
- - 0
10
- version: 1.0.0
10
+ version: 1.1.0
11
11
  platform: ruby
12
12
  authors:
13
13
  - Alex McHale
@@ -48,12 +48,14 @@ extensions: []
48
48
 
49
49
  extra_rdoc_files:
50
50
  - README.markdown
51
+ - lib/commerce-bank-client.rb
51
52
  - lib/commercebank.rb
52
53
  - lib/commercebank/monkey.rb
53
54
  files:
54
55
  - Manifest
55
56
  - README.markdown
56
57
  - Rakefile
58
+ - lib/commerce-bank-client.rb
57
59
  - lib/commercebank.rb
58
60
  - lib/commercebank/monkey.rb
59
61
  - test/commerce_bank_client_test.rb
metadata.gz.sig CHANGED
Binary file