nordea-rb 0.2.1 → 0.3.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/README.markdown +1 -0
- data/Rakefile +1 -0
- data/VERSION +1 -1
- data/examples/atom_feed/.htaccess +9 -0
- data/examples/atom_feed/nordea.cgi +87 -0
- data/examples/transfer-to-salary +24 -0
- data/lib/nordea/resources/account.rb +28 -10
- data/lib/nordea/session.rb +18 -7
- data/lib/nordea/transaction.rb +5 -5
- data/lib/nordea/version.rb +2 -2
- data/lib/nordea.rb +22 -13
- data/nordea-rb.gemspec +8 -2
- data/test/test_account.rb +23 -2
- data/test/test_functional.rb +3 -10
- data/test/test_helper.rb +11 -0
- data/test/test_nordea.rb +34 -0
- data/test/test_session.rb +29 -0
- data/test/test_transaction.rb +12 -0
- metadata +16 -4
data/README.markdown
CHANGED
data/Rakefile
CHANGED
data/VERSION
CHANGED
@@ -1 +1 @@
|
|
1
|
-
0.
|
1
|
+
0.3.0
|
@@ -0,0 +1,9 @@
|
|
1
|
+
AddHandler cgi-script .cgi
|
2
|
+
|
3
|
+
RewriteEngine on
|
4
|
+
|
5
|
+
# foo.atom -> foo.cgi
|
6
|
+
RewriteRule ^(.+)\.atom$ $1.cgi
|
7
|
+
|
8
|
+
# Give Apache CGI access to HTTP auth, http://www.besthostratings.com/articles/http-auth-php-cgi.html
|
9
|
+
RewriteRule .* - [E=HTTP_AUTHORIZATION:%{HTTP:Authorization}]
|
@@ -0,0 +1,87 @@
|
|
1
|
+
#!/usr/bin/env ruby
|
2
|
+
|
3
|
+
# Based on/stolen from http://github.com/henrik/atomica -- Thanks!
|
4
|
+
|
5
|
+
require 'rubygems'
|
6
|
+
require 'nordea'
|
7
|
+
require('builder') rescue require('active_support') # gem install builder
|
8
|
+
|
9
|
+
class NordeAtom
|
10
|
+
NAME = "NordeAtom"
|
11
|
+
VERSION = "1.0"
|
12
|
+
SCHEMA_DATE = "2009-11-02"
|
13
|
+
|
14
|
+
def initialize(pnr, pin)
|
15
|
+
@pnr, @pin = pnr, pin
|
16
|
+
end
|
17
|
+
|
18
|
+
def render
|
19
|
+
atomize(fetch)
|
20
|
+
end
|
21
|
+
|
22
|
+
protected
|
23
|
+
|
24
|
+
def fetch
|
25
|
+
transactions = nil
|
26
|
+
Nordea.new(@pnr, @pin) do |n|
|
27
|
+
transactions = n.accounts.map(&:transactions).flatten.sort_by(&:date).reverse
|
28
|
+
end
|
29
|
+
transactions
|
30
|
+
end
|
31
|
+
|
32
|
+
def atomize(items)
|
33
|
+
updated_at = (Time.parse(items.first.date.to_s) || Time.now).iso8601
|
34
|
+
|
35
|
+
xml = Builder::XmlMarkup.new(:indent => 2, :target => $stdout)
|
36
|
+
xml.instruct! :xml, :version => "1.0"
|
37
|
+
|
38
|
+
xml.feed(:xmlns => "http://www.w3.org/2005/Atom") do |feed|
|
39
|
+
feed.title "Kontohistorik för #{@pnr}"
|
40
|
+
feed.id "tag:nordea,#{SCHEMA_DATE}:#{@pnr}"
|
41
|
+
feed.link :href => 'http://www.nordea.se'
|
42
|
+
feed.updated updated_at
|
43
|
+
feed.author { |a| a.name 'Nordea' }
|
44
|
+
feed.generator NAME, :version => VERSION
|
45
|
+
|
46
|
+
items.each do |item|
|
47
|
+
item_time = Time.parse(item.date.to_s)
|
48
|
+
item_date = [%w[Sön Mån Tis Ons Tors Fre Lör][item_time.wday], item_time.strftime('%Y-%m-%d')].join(' ')
|
49
|
+
style = item.withdrawal? ? 'color: red' : 'color: green'
|
50
|
+
|
51
|
+
feed.entry do |entry|
|
52
|
+
entry.id "tag:nordea,#{SCHEMA_DATE}:#{@pnr}/#{item.account.index};" +
|
53
|
+
"#{item_time.strftime('%Y-%m-%d')};#{item.text.gsub(/\W/, '')};" +
|
54
|
+
amount = %Q{%.2f SEK} % item.amount
|
55
|
+
entry.title "#{item.text} #{amount}"
|
56
|
+
"#{item.amount};#{}".gsub(/\s+/, '')
|
57
|
+
entry.content %{<table>
|
58
|
+
<tr><th>Konto:</th> <td>#{item.account.name}</td></tr>
|
59
|
+
<tr><th>Datum:</th> <td>#{item_date}</td></tr>
|
60
|
+
<tr><th>Belopp:</th> <td style="#{style}">#{item.amount}</td></tr>
|
61
|
+
</table>}, :type => 'html'
|
62
|
+
entry.updated item_time.iso8601
|
63
|
+
end
|
64
|
+
end
|
65
|
+
end
|
66
|
+
end
|
67
|
+
end
|
68
|
+
|
69
|
+
if __FILE__ == $0
|
70
|
+
|
71
|
+
# HTTP Basic auth based on code from http://blogs.23.nu/c0re/2005/04/antville-7409/
|
72
|
+
require 'base64'
|
73
|
+
|
74
|
+
auth = ENV.has_key?('HTTP_AUTHORIZATION') && ENV['HTTP_AUTHORIZATION'].to_s.split
|
75
|
+
if auth && auth[0] == 'Basic'
|
76
|
+
pnr, pwd = Base64.decode64(auth[1]).split(':')[0..1]
|
77
|
+
puts "Content-Type: application/atom+xml"
|
78
|
+
puts
|
79
|
+
NordeAtom.new(pnr, pwd).render
|
80
|
+
else
|
81
|
+
puts "Status: 401 Authorization Required"
|
82
|
+
puts %{WWW-Authenticate: Basic realm="#{NordeAtom::NAME} pnr/PIN"}
|
83
|
+
puts "Content-Type: text/plain"
|
84
|
+
puts
|
85
|
+
puts "Please provide personnummer and PIN as HTTP auth username/password."
|
86
|
+
end
|
87
|
+
end
|
@@ -0,0 +1,24 @@
|
|
1
|
+
#!/usr/bin/env ruby
|
2
|
+
|
3
|
+
# This script will take an amount as argument (or default to 3000 SEK)
|
4
|
+
# and transfer that amount from the salary to the payments account.
|
5
|
+
|
6
|
+
require 'rubygems'
|
7
|
+
require 'nordea'
|
8
|
+
|
9
|
+
amount = (ARGV.first || 3000).to_f
|
10
|
+
|
11
|
+
Nordea.new(:keychain) do |n|
|
12
|
+
main, payments = n.accounts[/Salary/], n.accounts[/payments/i]
|
13
|
+
puts "Current balance:", main, payments
|
14
|
+
puts
|
15
|
+
print "Transfer #{amount} SEK to payments account? (yes/no) "
|
16
|
+
|
17
|
+
if STDIN.gets.chop =~ /^y/i
|
18
|
+
print "\nTransferring..."
|
19
|
+
main.withdraw(amount, 'SEK', :deposit_to => payments)
|
20
|
+
puts "Done"
|
21
|
+
puts
|
22
|
+
puts "Current balance:", main, payments
|
23
|
+
end
|
24
|
+
end
|
@@ -3,7 +3,8 @@ module Nordea
|
|
3
3
|
def initialize(fields = {}, command_params = {}, session = nil)
|
4
4
|
@name, @balance, @currency, @index = fields[:name], fields[:balance], fields[:currency], fields[:index]
|
5
5
|
@command_params = command_params
|
6
|
-
@session = session
|
6
|
+
@session = session if session
|
7
|
+
yield self if block_given?
|
7
8
|
end
|
8
9
|
|
9
10
|
attr_accessor :name, :balance, :currency, :index, :session
|
@@ -14,13 +15,21 @@ module Nordea
|
|
14
15
|
@command_params
|
15
16
|
end
|
16
17
|
|
17
|
-
# TODO move shared transaction fetching to Nordea::Resource and call super
|
18
18
|
def transactions(reload = false)
|
19
19
|
@transactions = nil if reload
|
20
20
|
@transactions ||= begin
|
21
|
-
|
22
|
-
|
23
|
-
|
21
|
+
# for some reason it needs this otherwise it would use the old transaction list
|
22
|
+
session.request(Nordea::Commands::RESOURCE)
|
23
|
+
|
24
|
+
nodes = session.request(Commands::TRANSACTIONS, to_command_params).parse_xml.search('go[@href="#trans"]')
|
25
|
+
idx = nodes.length
|
26
|
+
|
27
|
+
nodes.inject([]) do |all, node|
|
28
|
+
trans = Transaction.new_from_xml(node, self)
|
29
|
+
# since transactions don't have a time (just date) but are listed in chronological order
|
30
|
+
# we add one second to each item in the collection so they can be sorted by date
|
31
|
+
trans.date = Time.parse(trans.date.to_s) + (idx -= 1)
|
32
|
+
all << trans
|
24
33
|
end
|
25
34
|
end
|
26
35
|
end
|
@@ -33,10 +42,15 @@ module Nordea
|
|
33
42
|
%Q{%.#{decimals}f} % balance
|
34
43
|
end
|
35
44
|
|
36
|
-
def
|
45
|
+
def reload
|
46
|
+
@transactions = nil
|
47
|
+
session.accounts(true)
|
48
|
+
end
|
49
|
+
|
50
|
+
def reload_from_xml(xml_node)
|
37
51
|
xml_node = Hpricot(xml_node) unless xml_node.class.to_s =~ /^Hpricot::/
|
38
52
|
xml_node = xml_node.at("anchor") unless xml_node.name == 'anchor'
|
39
|
-
|
53
|
+
initialize(self.class._setup_fields(xml_node), self.class._setup_command_params(xml_node))
|
40
54
|
end
|
41
55
|
|
42
56
|
def withdraw(amount, currency = 'SEK', options = {})
|
@@ -68,7 +82,7 @@ module Nordea
|
|
68
82
|
:to_currency_code => currency
|
69
83
|
})
|
70
84
|
|
71
|
-
|
85
|
+
reload
|
72
86
|
end
|
73
87
|
|
74
88
|
def deposit(amount, currency = 'SEK', options = {})
|
@@ -80,8 +94,12 @@ module Nordea
|
|
80
94
|
from.withdraw(amount, currency, options.merge(:deposit_to => self))
|
81
95
|
end
|
82
96
|
|
97
|
+
def self.new_from_xml(xml_node, session)
|
98
|
+
new({}, {}, session) { |acc| acc.reload_from_xml(xml_node) }
|
99
|
+
end
|
100
|
+
|
83
101
|
private
|
84
|
-
|
102
|
+
|
85
103
|
def self._setup_fields(xml_node)
|
86
104
|
name = xml_node.at("postfield[@name='account_name']")['value']
|
87
105
|
currency = xml_node.at("postfield[@name='account_currency_code']")['value']
|
@@ -99,4 +117,4 @@ module Nordea
|
|
99
117
|
end
|
100
118
|
end
|
101
119
|
end
|
102
|
-
end
|
120
|
+
end
|
data/lib/nordea/session.rb
CHANGED
@@ -45,19 +45,30 @@ module Nordea
|
|
45
45
|
end
|
46
46
|
|
47
47
|
def accounts(reload = false)
|
48
|
-
|
49
|
-
|
48
|
+
if reload && @accounts
|
49
|
+
reloaded_xml_nodes = reload_resources(Account)
|
50
|
+
@accounts.each_with_index { |account, idx| account.reload_from_xml(reloaded_xml_nodes[idx]) }
|
51
|
+
else
|
52
|
+
@accounts ||= setup_resources(Account)
|
53
|
+
end
|
50
54
|
end
|
51
55
|
|
52
56
|
private
|
53
57
|
|
54
|
-
def
|
58
|
+
def fetch_resources(klass)
|
55
59
|
type = klass.new.account_type_name
|
56
60
|
doc = request(Commands::RESOURCE, "account_type_name" => type).parse_xml
|
57
|
-
(doc/"go postfield[@name='OBJECT'][@value='#{Commands::TRANSACTIONS}']")
|
58
|
-
|
59
|
-
|
60
|
-
|
61
|
+
(doc/"go postfield[@name='OBJECT'][@value='#{Commands::TRANSACTIONS}']")
|
62
|
+
end
|
63
|
+
|
64
|
+
def reload_resources(klass)
|
65
|
+
fetch_resources(klass).map { |field| field.parent.parent }
|
66
|
+
end
|
67
|
+
|
68
|
+
def setup_resources(klass)
|
69
|
+
fetch_resources(klass).inject(ResourceCollection.new) do |all, field|
|
70
|
+
all << klass.new_from_xml(field.parent.parent, self)
|
71
|
+
end
|
61
72
|
end
|
62
73
|
end
|
63
74
|
end
|
data/lib/nordea/transaction.rb
CHANGED
@@ -2,11 +2,11 @@ require 'date'
|
|
2
2
|
|
3
3
|
module Nordea
|
4
4
|
class Transaction
|
5
|
-
def initialize(date, amount, text)
|
6
|
-
@date, @amount, @text = date, amount, text
|
5
|
+
def initialize(date, amount, text, account = nil)
|
6
|
+
@date, @amount, @text, @account = date, amount, text, account
|
7
7
|
end
|
8
8
|
|
9
|
-
attr_accessor :date, :amount, :text
|
9
|
+
attr_accessor :date, :amount, :text, :account
|
10
10
|
|
11
11
|
def withdrawal?
|
12
12
|
amount < 0
|
@@ -16,12 +16,12 @@ module Nordea
|
|
16
16
|
amount > 0
|
17
17
|
end
|
18
18
|
|
19
|
-
def self.new_from_xml(xml)
|
19
|
+
def self.new_from_xml(xml, account = nil)
|
20
20
|
node = xml.is_a?(String) ? Hpricot.XML(xml) : xml
|
21
21
|
date = Date.parse(node.at("setvar[@name='date']")['value'])
|
22
22
|
amount = Support.dirty_currency_string_to_f(node.at("setvar[@name='amount']")['value'])
|
23
23
|
text = node.at("setvar[@name='text']")['value']
|
24
|
-
new
|
24
|
+
new(date, amount, text, account)
|
25
25
|
end
|
26
26
|
end
|
27
27
|
end
|
data/lib/nordea/version.rb
CHANGED
data/lib/nordea.rb
CHANGED
@@ -40,30 +40,39 @@ module Nordea
|
|
40
40
|
|
41
41
|
private
|
42
42
|
|
43
|
-
# TODO clean up
|
44
43
|
def self.extract_login_details(pnr_or_hash, pin_or_options)
|
45
44
|
if pnr_or_hash.is_a?(Hash)
|
46
|
-
pnr_or_hash
|
47
|
-
pnr = pnr_or_hash[:pnr]
|
48
|
-
pin = pnr_or_hash[:pin]
|
45
|
+
pnr, pin = _login_details_from_hash(pnr_or_hash)
|
49
46
|
elsif pnr_or_hash.is_a?(Symbol)
|
50
|
-
|
51
|
-
options = { :label => 'Nordea' }.merge(pin_or_options.symbolize_keys)
|
52
|
-
pnr, pin = account_details_from_keychain(options)
|
53
|
-
end
|
47
|
+
pnr, pin = _login_details_from_symbol(pnr_or_hash, pin_or_options)
|
54
48
|
elsif pnr_or_hash.is_a?(String) && pin_or_options.is_a?(String)
|
55
|
-
pnr = pnr_or_hash
|
56
|
-
pin = pin_or_options
|
49
|
+
pnr, pin = pnr_or_hash, pin_or_options
|
57
50
|
else
|
58
51
|
raise ArgumentError
|
59
52
|
end
|
60
53
|
[pnr.to_s.gsub(/\D+/, ''), pin.to_s.gsub(/\D+/, '')]
|
61
54
|
end
|
62
|
-
|
63
|
-
def Nordea.
|
55
|
+
|
56
|
+
def Nordea._login_details_from_hash(pnr_or_hash)
|
57
|
+
pnr_or_hash.symbolize_keys!
|
58
|
+
[pnr_or_hash[:pnr], pnr_or_hash[:pin]]
|
59
|
+
end
|
60
|
+
|
61
|
+
def Nordea._login_details_from_symbol(symbol, options)
|
62
|
+
if symbol == :keychain
|
63
|
+
_account_details_from_keychain({ :label => 'Nordea' }.merge(options.symbolize_keys))
|
64
|
+
else
|
65
|
+
raise ArgumentError
|
66
|
+
end
|
67
|
+
end
|
68
|
+
|
69
|
+
def Nordea._account_details_from_keychain(options)
|
64
70
|
command = "security find-generic-password -l '#{options[:label]}' -g"
|
65
71
|
command << " #{options[:keychain_file].inspect}" if options[:keychain_file]
|
66
72
|
command << " 2>&1"
|
67
|
-
`#{command}
|
73
|
+
output = `#{command}`
|
74
|
+
pnr = output.match(/"acct"<blob>="(\d{10})"/)[1]
|
75
|
+
pin = output.match(/password: "(\d{4})"/)[1]
|
76
|
+
[pnr, pin]
|
68
77
|
end
|
69
78
|
end
|
data/nordea-rb.gemspec
CHANGED
@@ -5,11 +5,11 @@
|
|
5
5
|
|
6
6
|
Gem::Specification.new do |s|
|
7
7
|
s.name = %q{nordea-rb}
|
8
|
-
s.version = "0.
|
8
|
+
s.version = "0.3.0"
|
9
9
|
|
10
10
|
s.required_rubygems_version = Gem::Requirement.new(">= 0") if s.respond_to? :required_rubygems_version=
|
11
11
|
s.authors = ["Martin Str\303\266m"]
|
12
|
-
s.date = %q{2009-10
|
12
|
+
s.date = %q{2009-11-10}
|
13
13
|
s.default_executable = %q{nordea}
|
14
14
|
s.description = %q{Ruby library for accessing your Nordea Bank account and transferring money between your own accounts.}
|
15
15
|
s.email = %q{name@my-domain.se}
|
@@ -25,6 +25,9 @@ Gem::Specification.new do |s|
|
|
25
25
|
"Rakefile",
|
26
26
|
"VERSION",
|
27
27
|
"bin/nordea",
|
28
|
+
"examples/atom_feed/.htaccess",
|
29
|
+
"examples/atom_feed/nordea.cgi",
|
30
|
+
"examples/transfer-to-salary",
|
28
31
|
"lib/nordea.rb",
|
29
32
|
"lib/nordea/request.rb",
|
30
33
|
"lib/nordea/resources.rb",
|
@@ -80,9 +83,12 @@ Gem::Specification.new do |s|
|
|
80
83
|
s.specification_version = 3
|
81
84
|
|
82
85
|
if Gem::Version.new(Gem::RubyGemsVersion) >= Gem::Version.new('1.2.0') then
|
86
|
+
s.add_runtime_dependency(%q<hpricot>, [">= 0"])
|
83
87
|
else
|
88
|
+
s.add_dependency(%q<hpricot>, [">= 0"])
|
84
89
|
end
|
85
90
|
else
|
91
|
+
s.add_dependency(%q<hpricot>, [">= 0"])
|
86
92
|
end
|
87
93
|
end
|
88
94
|
|
data/test/test_account.rb
CHANGED
@@ -6,6 +6,7 @@ class TestAccount < Test::Unit::TestCase
|
|
6
6
|
@session = Nordea::Session.new('foo', 'bar')
|
7
7
|
@account = Nordea::Account.new(:name => "savings account", :balance => 1234.50, :currency => 'EUR', :index => '2')
|
8
8
|
@account.session = @session
|
9
|
+
@session.stubs(:request)
|
9
10
|
end
|
10
11
|
|
11
12
|
context "each Account instance" do
|
@@ -20,8 +21,14 @@ class TestAccount < Test::Unit::TestCase
|
|
20
21
|
should "request the transactions from the server" do
|
21
22
|
response = mock(:parse_xml => Hpricot.XML(fixture_content('account')))
|
22
23
|
@session.expects(:request).with('KF11TW', {}).returns(response)
|
24
|
+
@session.expects(:request).with('KF00TW') # it needs this command to reset the transaction list
|
23
25
|
@account.transactions
|
24
26
|
end
|
27
|
+
|
28
|
+
should "reload the account object from session" do
|
29
|
+
@session.expects(:accounts).with(true)
|
30
|
+
@account.reload
|
31
|
+
end
|
25
32
|
end
|
26
33
|
|
27
34
|
context "transfers" do
|
@@ -72,7 +79,7 @@ class TestAccount < Test::Unit::TestCase
|
|
72
79
|
end
|
73
80
|
|
74
81
|
should "reload the accounts" do
|
75
|
-
@
|
82
|
+
@account.expects(:reload)
|
76
83
|
@savings.withdraw(6.5, "EUR", :deposit_to => @checking)
|
77
84
|
end
|
78
85
|
end
|
@@ -105,7 +112,11 @@ class TestAccount < Test::Unit::TestCase
|
|
105
112
|
end
|
106
113
|
|
107
114
|
should "set transaction's date" do
|
108
|
-
assert_equal "2009-08-16", @transactions.first.date.
|
115
|
+
assert_equal "2009-08-16", @transactions.first.date.strftime("%Y-%m-%d")
|
116
|
+
end
|
117
|
+
|
118
|
+
should "set each transaction's time increased in the same order as listed" do
|
119
|
+
assert_equal (0...20).to_a.reverse, @transactions.map { |t| t.date.sec }
|
109
120
|
end
|
110
121
|
|
111
122
|
should "set transaction's amount" do
|
@@ -115,6 +126,10 @@ class TestAccount < Test::Unit::TestCase
|
|
115
126
|
should "set transaction's text" do
|
116
127
|
assert_equal "Res. köp", @transactions.first.text
|
117
128
|
end
|
129
|
+
|
130
|
+
should "set transaction's account" do
|
131
|
+
assert_equal @account, @transactions.first.account
|
132
|
+
end
|
118
133
|
end
|
119
134
|
|
120
135
|
context "creating a new Account object from XML" do
|
@@ -163,6 +178,12 @@ class TestAccount < Test::Unit::TestCase
|
|
163
178
|
should "have an index" do
|
164
179
|
assert_equal "1", @account.index
|
165
180
|
end
|
181
|
+
|
182
|
+
should "reload via xml" do
|
183
|
+
xml = @xml_node.sub('2.000,00', '1.234,00')
|
184
|
+
@account.reload_from_xml(xml)
|
185
|
+
assert_equal 1234.0, @account.balance
|
186
|
+
end
|
166
187
|
end
|
167
188
|
end
|
168
189
|
end
|
data/test/test_functional.rb
CHANGED
@@ -18,13 +18,6 @@ class FunctionalTest < Test::Unit::TestCase
|
|
18
18
|
end
|
19
19
|
|
20
20
|
should "login and display the number of accounts" do
|
21
|
-
def assert_requests_made(session, num_requests = 1, msg = nil, &blk)
|
22
|
-
before = session.num_requests
|
23
|
-
yield
|
24
|
-
after = session.num_requests
|
25
|
-
assert_equal before + num_requests, after, msg
|
26
|
-
end
|
27
|
-
|
28
21
|
Nordea.new('1234567890', '0987') do |n|
|
29
22
|
|
30
23
|
# logging in
|
@@ -39,7 +32,7 @@ class FunctionalTest < Test::Unit::TestCase
|
|
39
32
|
assert_requests_made(n, 1, "reloading the accounts cache") { n.accounts(true) }
|
40
33
|
|
41
34
|
# getting one of the account's transactions
|
42
|
-
assert_requests_made(n,
|
35
|
+
assert_requests_made(n, 2) do
|
43
36
|
assert_equal 5, n.accounts.first.transactions.size # we use the same ficture so all accounts have 20 transactions
|
44
37
|
end
|
45
38
|
|
@@ -48,12 +41,12 @@ class FunctionalTest < Test::Unit::TestCase
|
|
48
41
|
assert_equal 5, n.accounts['Sparkonto'].transactions.size
|
49
42
|
end
|
50
43
|
|
51
|
-
assert_requests_made(n,
|
44
|
+
assert_requests_made(n, 2, "reload the cached transactions list") {
|
52
45
|
n.accounts['Sparkonto'].transactions(true).size
|
53
46
|
}
|
54
47
|
|
55
48
|
# ask for the other accounts's transactions
|
56
|
-
assert_requests_made(n,
|
49
|
+
assert_requests_made(n, 4) do
|
57
50
|
assert_equal 10, n.accounts['Huvudkonto'].transactions.size
|
58
51
|
assert_equal 20, n.accounts['Betalkonto'].transactions.size
|
59
52
|
end
|
data/test/test_helper.rb
CHANGED
@@ -55,4 +55,15 @@ class Test::Unit::TestCase
|
|
55
55
|
end
|
56
56
|
end
|
57
57
|
end
|
58
|
+
|
59
|
+
def assert_requests_made(session, num_requests = 1, msg = nil, &blk)
|
60
|
+
before = session.num_requests
|
61
|
+
yield
|
62
|
+
after = session.num_requests
|
63
|
+
assert_equal before + num_requests, after, msg
|
64
|
+
end
|
65
|
+
|
66
|
+
def assert_no_requests_made(session, msg = nil, &blk)
|
67
|
+
assert_requests_made(session, 0, msg, &blk)
|
68
|
+
end
|
58
69
|
end
|
data/test/test_nordea.rb
CHANGED
@@ -45,5 +45,39 @@ class TestNordea < Test::Unit::TestCase
|
|
45
45
|
should "raise an error if there is no pin provided" do
|
46
46
|
assert_raise(ArgumentError) { Nordea.new("1234567890") }
|
47
47
|
end
|
48
|
+
|
49
|
+
should "raise an error when using a symbol other than :keychain" do
|
50
|
+
assert_raise(ArgumentError) { Nordea.new(:foo) }
|
51
|
+
end
|
52
|
+
|
53
|
+
should "raise call the secutiry commando on OS X to retreive the password" do
|
54
|
+
#Nordea.expects(:`).returns(<<-EOF)
|
55
|
+
return_value = <<-EOF
|
56
|
+
keychain: "/Users/me/Library/Keychains/login.keychain"
|
57
|
+
class: "genp"
|
58
|
+
attributes:
|
59
|
+
0x00000001 <blob>="Nordea"
|
60
|
+
0x00000002 <blob>=<NULL>
|
61
|
+
"acct"<blob>="1234567890"
|
62
|
+
"cdat"<timedate>=0x11111111111111111111111111111111 "111111111111111\000"
|
63
|
+
"crtr"<uint32>=<NULL>
|
64
|
+
"cusi"<sint32>=<NULL>
|
65
|
+
"desc"<blob>=<NULL>
|
66
|
+
"gena"<blob>=<NULL>
|
67
|
+
"icmt"<blob>=<NULL>
|
68
|
+
"invi"<sint32>=<NULL>
|
69
|
+
"mdat"<timedate>=0x22222222222222222222222222222222 "222222222222222\000"
|
70
|
+
"nega"<sint32>=<NULL>
|
71
|
+
"prot"<blob>=<NULL>
|
72
|
+
"scrp"<sint32>=<NULL>
|
73
|
+
"svce"<blob>="Nordea"
|
74
|
+
"type"<uint32>=<NULL>
|
75
|
+
password: "1337"
|
76
|
+
EOF
|
77
|
+
|
78
|
+
Nordea.expects(:`).with(anything).returns(return_value)
|
79
|
+
|
80
|
+
Nordea.new(:keychain)
|
81
|
+
end
|
48
82
|
end
|
49
83
|
end
|
data/test/test_session.rb
CHANGED
@@ -125,5 +125,34 @@ class TestSession < Test::Unit::TestCase
|
|
125
125
|
should "find the account's name by pattern when using #[] with a regexp" do
|
126
126
|
assert_equal @session.accounts[1], @session.accounts[/huvud/i]
|
127
127
|
end
|
128
|
+
|
129
|
+
should "cache the account objects" do
|
130
|
+
@session.accounts
|
131
|
+
assert_no_requests_made(@session) do
|
132
|
+
@session.accounts
|
133
|
+
@session.accounts
|
134
|
+
end
|
135
|
+
end
|
136
|
+
|
137
|
+
should "refetch the account objects when passing true as argument" do
|
138
|
+
@session.accounts
|
139
|
+
assert_requests_made(@session, 1) { @session.accounts(true) }
|
140
|
+
end
|
141
|
+
|
142
|
+
should "not create new account objects when reloading" do
|
143
|
+
assert_equal @session.accounts, @session.accounts(true)
|
144
|
+
end
|
145
|
+
|
146
|
+
should "setup the objects first time when passing reload flag" do
|
147
|
+
assert_requests_made(@session, 1) { @session.accounts(true) }
|
148
|
+
assert_equal 3, @session.accounts.length
|
149
|
+
end
|
150
|
+
|
151
|
+
should "set new balance when reloading" do
|
152
|
+
@session.accounts # create the account objects
|
153
|
+
xml = Hpricot.XML(fixture_content('accounts').sub('179,05', '1234,56'))
|
154
|
+
Nordea::Request.stubs(:new).returns(stub(:parse_xml => xml))
|
155
|
+
assert_equal 1234.56, @session.accounts(true)[/Betal/].balance
|
156
|
+
end
|
128
157
|
end
|
129
158
|
end
|
data/test/test_transaction.rb
CHANGED
@@ -11,6 +11,7 @@ class TestTransaction < Test::Unit::TestCase
|
|
11
11
|
</go>
|
12
12
|
</anchor>
|
13
13
|
END
|
14
|
+
@account = stub("Account", :name => 'fake account')
|
14
15
|
@transaction = Nordea::Transaction.new_from_xml(@xml_node)
|
15
16
|
end
|
16
17
|
|
@@ -55,4 +56,15 @@ class TestTransaction < Test::Unit::TestCase
|
|
55
56
|
assert t.deposit?
|
56
57
|
assert !t.withdrawal?
|
57
58
|
end
|
59
|
+
|
60
|
+
should "allow to pass an account to the contstructor" do
|
61
|
+
t = Nordea::Transaction.new('2009-01-01', 10.00, 'Salery', @account)
|
62
|
+
assert_equal @account, t.account
|
63
|
+
end
|
64
|
+
|
65
|
+
should "have a setter for the account property" do
|
66
|
+
t = Nordea::Transaction.new('2009-01-01', 10.00, 'Salery')
|
67
|
+
t.account = @account
|
68
|
+
assert_equal @account, t.account
|
69
|
+
end
|
58
70
|
end
|
metadata
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: nordea-rb
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.
|
4
|
+
version: 0.3.0
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- "Martin Str\xC3\xB6m"
|
@@ -9,10 +9,19 @@ autorequire:
|
|
9
9
|
bindir: bin
|
10
10
|
cert_chain: []
|
11
11
|
|
12
|
-
date: 2009-10
|
12
|
+
date: 2009-11-10 00:00:00 +01:00
|
13
13
|
default_executable: nordea
|
14
|
-
dependencies:
|
15
|
-
|
14
|
+
dependencies:
|
15
|
+
- !ruby/object:Gem::Dependency
|
16
|
+
name: hpricot
|
17
|
+
type: :runtime
|
18
|
+
version_requirement:
|
19
|
+
version_requirements: !ruby/object:Gem::Requirement
|
20
|
+
requirements:
|
21
|
+
- - ">="
|
22
|
+
- !ruby/object:Gem::Version
|
23
|
+
version: "0"
|
24
|
+
version:
|
16
25
|
description: Ruby library for accessing your Nordea Bank account and transferring money between your own accounts.
|
17
26
|
email: name@my-domain.se
|
18
27
|
executables:
|
@@ -29,6 +38,9 @@ files:
|
|
29
38
|
- Rakefile
|
30
39
|
- VERSION
|
31
40
|
- bin/nordea
|
41
|
+
- examples/atom_feed/.htaccess
|
42
|
+
- examples/atom_feed/nordea.cgi
|
43
|
+
- examples/transfer-to-salary
|
32
44
|
- lib/nordea.rb
|
33
45
|
- lib/nordea/request.rb
|
34
46
|
- lib/nordea/resources.rb
|