Smile Bank to Ledger

Check-in [6a191c53d1]
Login

Many hyperlinks are disabled.
Use anonymous login to enable hyperlinks.

Overview
Comment:Merge in the cascaded_methods approach. I've decided I prefer that
Downloads: Tarball | ZIP archive | SQL archive
Timelines: family | ancestors | descendants | both | trunk
Files: files | file ages | folders
SHA1: 6a191c53d125da195cb11ac2df490782ad995083
User & Date: atomicules 2015-07-10 10:42:55
Context
2015-07-10
11:12
Remove redundant comments after merge check-in: 16a050f0ef user: atomicules tags: trunk
10:42
Merge in the cascaded_methods approach. I've decided I prefer that check-in: 6a191c53d1 user: atomicules tags: trunk
2015-07-07
22:19
Report out balance as a comment at end of the file check-in: 565270916f user: atomicules tags: trunk
2015-07-06
20:57
Alternative approach to code, cascading methods

Since methods make no sense on their own, make each method call the method
before it so requirements cascade all the way back. Since each method now
returns `page` there is no need for `page` to be an instance variable. So
perhaps this is a bit cleaner? Leaf check-in: 1905cd0eb7 user: atomicules tags: cascade_methods

Changes
Hide Diffs Unified Diffs Ignore Whitespace Patch

Changes to smile.rb.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29

30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53


54
55
56
57
58
59
60
61
62
63
64


65
66
67
68
69
70
71
72
73
74
75
76


77
78
79
80
81
82
83


84
85


86
87
88
89
90
91


92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
require 'optparse'
require 'mechanize'
require 'nokogiri'

optparse = OptionParser.new do |opts|
	opts.on('-d', '--date DATE', "Date") { |d| Date_back = d }
end
optparse.parse!

class Smile
	attr_writer :date_back 
	attr_reader :page
	attr_reader :transactions
	attr_reader :balance

	def initialize
		@a = Mechanize.new
		@transactions = []
	end


	def transactions(date_back)
		@date_back = Date.parse(date_back)
		logon_start
		logon_passcode
		logon_other
		logon_bulletin
		recent_transactions
		previous_statements

		write_ledger
	end


	#All these private
	#Note sure how valid it is breaking these out into separate methods
	#Might make more sense in a rakefile as separate tasks with dependencies,
	#but these methods can't be used alone
	#Also, really not sure about using instance variables instead of passing args
	def logon_start
		@page = @a.get("https://banking.smile.co.uk/SmileWeb/start.do")
		#Since dealing with sensitive logon data don't want to get it from anywhere apart from keyboard input
		#Sortcode and Account number login
		puts "Enter sortcode"
		sortCode = gets.strip
		puts "Enter Account number"
		accountNumber = gets.strip
		@page.form.sortCode = sortCode
		@page.form.accountNumber = accountNumber
		@page = @page.form.submit
	end


	def logon_passcode


		#Passcode login
		doc = Nokogiri::HTML(@page.body)
		puts doc.xpath("//label")[0].text
		@page.form.firstPassCodeDigit = gets.strip
		puts doc.xpath("//label")[1].text
		@page.form.secondPassCodeDigit = gets.strip
		@page = @page.form.submit
	end


	def logon_other


		#Other logon details
		@page.form.fields.each do |field|
			unless field.type == "hidden"
				puts field.name
				field.value = gets.strip
			end
		end
		@page = @page.form.submit
	end


	def logon_bulletin


		if @page.form.action.include?("bulletinBoard")
			@page = @page.form.submit
		end
	end


	def recent_transactions


		@page = @a.click(@page.link_with(:text => "current account"))
		get_transactions


		doc = Nokogiri::HTML(@page.body)
		@balance = doc.xpath("//td[@class='recentTransactionsAccountData']/table/tr[2]/td[2]").text
	end


	def previous_statements


		#Previous statements
		@page = @a.click(@page.link_with(:text => "previous statements"))
		#Get first page of previous statements
		@page = @a.click(@page.links_with(:href => %r{getDomestic} )[0])
		date = Date.today
		until date < @date_back
			get_transactions
			#On previous statement pages most recent transaction is at bottom
			#This is opposite to recent item page
			date = @transactions[-1][:date]
			@page = @a.click(@page.link_with(:text => "previous statement page"))
		end
	end


	def get_transactions
		doc = Nokogiri::HTML(@page.body)
		#Look for summaryTable
		rows = doc.xpath("//table[@class='summaryTable']//tr")
		#Skip first row (table headers, ths)
		rows = rows[1..-1]
		transactions = []
		rows.each do |row|
			#Skip last row, maybe











<











<
<
<
<
<

>










|






|
|
|




>
>

|

|

|
|




>
>

|





|




>
>
|
|





>
>
|
|
>
>






>
>

|

|


|



|




|
|







1
2
3
4
5
6
7
8
9
10
11

12
13
14
15
16
17
18
19
20
21
22





23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
require 'optparse'
require 'mechanize'
require 'nokogiri'

optparse = OptionParser.new do |opts|
	opts.on('-d', '--date DATE', "Date") { |d| Date_back = d }
end
optparse.parse!

class Smile
	attr_writer :date_back 

	attr_reader :transactions
	attr_reader :balance

	def initialize
		@a = Mechanize.new
		@transactions = []
	end


	def transactions(date_back)
		@date_back = Date.parse(date_back)





		previous_statements
		#previous calls recent (I could change this though so it reads more sensibly here)
		write_ledger
	end


	#All these private
	#Note sure how valid it is breaking these out into separate methods
	#Might make more sense in a rakefile as separate tasks with dependencies,
	#but these methods can't be used alone
	#Also, really not sure about using instance variables instead of passing args
	def logon_start
		page = @a.get("https://banking.smile.co.uk/SmileWeb/start.do")
		#Since dealing with sensitive logon data don't want to get it from anywhere apart from keyboard input
		#Sortcode and Account number login
		puts "Enter sortcode"
		sortCode = gets.strip
		puts "Enter Account number"
		accountNumber = gets.strip
		page.form.sortCode = sortCode
		page.form.accountNumber = accountNumber
		page = page.form.submit
	end


	def logon_passcode
		#Requires
		page = logon_start
		#Passcode login
		doc = Nokogiri::HTML(page.body)
		puts doc.xpath("//label")[0].text
		page.form.firstPassCodeDigit = gets.strip
		puts doc.xpath("//label")[1].text
		page.form.secondPassCodeDigit = gets.strip
		page = page.form.submit
	end


	def logon_other
		#requires
		page = logon_passcode
		#Other logon details
		page.form.fields.each do |field|
			unless field.type == "hidden"
				puts field.name
				field.value = gets.strip
			end
		end
		page = page.form.submit
	end


	def logon_bulletin
		#requires
		page = logon_other
		if page.form.action.include?("bulletinBoard")
			page = page.form.submit
		end
	end


	def recent_transactions
		#requires
		page = logon_bulletin
		page = @a.click(page.link_with(:text => "current account"))
		get_transactions(page)
		#Need to return this
		page
		doc = Nokogiri::HTML(@page.body)
		@balance = doc.xpath("//td[@class='recentTransactionsAccountData']/table/tr[2]/td[2]").text
	end


	def previous_statements
		#requires
		page = recent_transactions
		#Previous statements
		page = @a.click(page.link_with(:text => "previous statements"))
		#Get first page of previous statements
		page = @a.click(page.links_with(:href => %r{getDomestic} )[0])
		date = Date.today
		until date < @date_back
			get_transactions(page)
			#On previous statement pages most recent transaction is at bottom
			#This is opposite to recent item page
			date = @transactions[-1][:date]
			page = @a.click(page.link_with(:text => "previous statement page"))
		end
	end


	def get_transactions(page)
		doc = Nokogiri::HTML(page.body)
		#Look for summaryTable
		rows = doc.xpath("//table[@class='summaryTable']//tr")
		#Skip first row (table headers, ths)
		rows = rows[1..-1]
		transactions = []
		rows.each do |row|
			#Skip last row, maybe