internetkassa 0.9.4

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.
@@ -0,0 +1,4 @@
1
+ require 'abn-amro/internetkassa'
2
+ require 'abn-amro/internetkassa/helpers'
3
+
4
+ ActionView::Base.send(:include, AbnAmro::Internetkassa::Helpers)
@@ -0,0 +1,74 @@
1
+ RESPONSES = {
2
+ :succeeded => {
3
+ "CN" => "Buyer name",
4
+ "BRAND" => "iDEAL",
5
+ "orderID" => "1235052040",
6
+ "PAYID" => "3051611",
7
+ "ACCEPTANCE" => "0000000000",
8
+ "amount" => "10",
9
+ "CARDNO" => "11-XXXX-11",
10
+ "PM" => "iDEAL",
11
+ "STATUS" => "9",
12
+ "IP" => "83.68.2.74",
13
+ "TRXDATE" => "02/19/09",
14
+ "NCERROR" => "0",
15
+ "ED" => "",
16
+ "SHASIGN" => "7537DD222E35EE9F9842921BD90C2CBFCFA59466",
17
+ "currency" => "EUR"
18
+ },
19
+
20
+ :failed => {
21
+ "CN" => "",
22
+ "BRAND" => "iDEAL",
23
+ "orderID" => "1235052641",
24
+ "PAYID" => "3051687",
25
+ "ACCEPTANCE" => "",
26
+ "amount" => "10",
27
+ "CARDNO" => "",
28
+ "PM" => "iDEAL",
29
+ "STATUS" => "2",
30
+ "IP" => "83.68.2.74",
31
+ "TRXDATE" => "02/19/09",
32
+ "NCERROR" => "30001001",
33
+ "ED" => "",
34
+ "SHASIGN" => "BC9E821662DFD1EBC6E23BF044F6957796076B80",
35
+ "currency" => "EUR"
36
+ },
37
+
38
+ :cancelled => {
39
+ "CN" => "",
40
+ "BRAND" => "iDEAL",
41
+ "orderID" => "1235052559",
42
+ "PAYID" => "3051681",
43
+ "ACCEPTANCE" => "",
44
+ "amount" => "10",
45
+ "CARDNO" => "",
46
+ "PM" => "iDEAL",
47
+ "STATUS" => "2",
48
+ "IP" => "83.68.2.74",
49
+ "TRXDATE" => "02/19/09",
50
+ "NCERROR" => "30171001",
51
+ "ED" => "",
52
+ "SHASIGN" => "734AB5AD3033C46E1F69CBFB91EDD0AD34E7368D",
53
+ "currency" => "EUR"
54
+ },
55
+
56
+ :exception => {
57
+ "CN" => "",
58
+ "BRAND" => "iDEAL",
59
+ "orderID" => "1235052396",
60
+ "PAYID" => "3051657",
61
+ "action" => "index",
62
+ "ACCEPTANCE" => "",
63
+ "amount" => "10",
64
+ "CARDNO" => "",
65
+ "PM" => "iDEAL",
66
+ "STATUS" => "92",
67
+ "IP" => "83.68.2.74",
68
+ "TRXDATE" => "02/19/09",
69
+ "NCERROR" => "20002001",
70
+ "ED" => "",
71
+ "SHASIGN" => "614F540CC51607DA44CB8D2403B8DF1781B9712C",
72
+ "currency" => "EUR"
73
+ }
74
+ }
@@ -0,0 +1,7 @@
1
+ module FixturesHelper
2
+ def fixture(name)
3
+ RESPONSES[name]
4
+ end
5
+ end
6
+
7
+ Test::Unit::TestCase.send(:include, FixturesHelper)
@@ -0,0 +1,19 @@
1
+ require 'action_controller'
2
+ require 'action_view'
3
+ require 'action_view/test_case'
4
+
5
+ class TestController
6
+ attr_accessor :output_buffer
7
+
8
+ def initialize
9
+ @output_buffer = ''
10
+ end
11
+
12
+ def url_for(options)
13
+ "http://www.example.com"
14
+ end
15
+
16
+ def protect_against_forgery?
17
+ false
18
+ end
19
+ end
@@ -0,0 +1,45 @@
1
+ require File.expand_path('../test_helper', __FILE__)
2
+
3
+ describe "AbnAmro::Internetkassa::Helpers", ActionView::TestCase do
4
+ tests AbnAmro::Internetkassa::Helpers
5
+
6
+ before do
7
+ @controller = TestController.new
8
+
9
+ @instance = AbnAmro::Internetkassa.new(
10
+ :order_id => 123,
11
+ :amount => 1000,
12
+ :description => "HappyHardcore vol. 123 - the ballads",
13
+ :endpoint_url => "http://example.com/payments",
14
+ :TITLE => 'HappyHardcore vol. 123 - the ballads'
15
+ )
16
+
17
+ # make sure we don't get bitten by sorting
18
+ ordered_data = @instance.data.to_a
19
+ @instance.stubs(:data).returns(ordered_data)
20
+ end
21
+
22
+ it "should create a form tag with the AbnAmro::Internetkassa.service_url as its action" do
23
+ expected = %{<form action="#{AbnAmro::Internetkassa.service_url}" method="post">}
24
+ internetkassa_form_tag(@instance)[0..expected.length-1].should == expected
25
+ end
26
+
27
+ it "should create a form with data from a AbnAmro::Internetkassa instance and yield" do
28
+ internetkassa_form_tag(@instance) { concat submit_tag('Betaal') }
29
+
30
+ expected = [%{<form action="#{AbnAmro::Internetkassa.service_url}" method="post">}]
31
+ @instance.data.each do |name, value|
32
+ expected << %{<input name="#{name}" type="hidden" value="#{value}" />}
33
+ end
34
+ expected << %{<input name="commit" type="submit" value="Betaal" />}
35
+ expected << "</form>"
36
+
37
+ assert_dom_equal expected.join("\n"), output_buffer
38
+ end
39
+
40
+ private
41
+
42
+ def method_missing(method, *args, &block)
43
+ @controller.send(method, *args, &block)
44
+ end
45
+ end
@@ -0,0 +1,57 @@
1
+ require File.expand_path('../test_helper', __FILE__)
2
+
3
+ require 'rest'
4
+ require 'hpricot'
5
+
6
+ describe "AbnAmro::Internetkassa, when remote testing" do
7
+ before do
8
+ @instance = AbnAmro::Internetkassa.new(
9
+ :order_id => Time.now.to_i.to_s,
10
+ :amount => 1000,
11
+ :description => "HappyHardcore vol. 123 - the ballads",
12
+ :TITLE => 'HappyHardcore vol. 123 - the ballads'
13
+ )
14
+ end
15
+
16
+ it "should have the right data to make a successful POST request" do
17
+ response = post(AbnAmro::Internetkassa.service_url, @instance.data)
18
+ response.should.be.success
19
+
20
+ parse_response(response).should == {
21
+ :beneficiary => 'Fingertips BV',
22
+ :order_id => @instance.order_id,
23
+ :amount => '10.00 EUR',
24
+ :title => 'HappyHardcore vol. 123 - the ballads'
25
+ }
26
+ end
27
+
28
+ private
29
+
30
+ def post(uri, values)
31
+ body = values.map { |k,v| "#{k}=#{v.to_s.gsub(' ', '%20')}" }.join('&')
32
+ REST.post(uri, body)
33
+ end
34
+
35
+ def parse_response(response)
36
+ results = {}
37
+
38
+ doc = Hpricot(response.body)
39
+ (doc / '#ncol_ref' / 'tr').each do |row|
40
+ cols = (row / 'td')
41
+
42
+ key = case cols.first.inner_text
43
+ when /Ordernummer/
44
+ :order_id
45
+ when /Totaalbedrag/
46
+ :amount
47
+ when /Begunstigde/
48
+ :beneficiary
49
+ end
50
+
51
+ results[key] = cols.last.inner_text.strip
52
+ end
53
+
54
+ results[:title] = (doc / 'title').inner_text.strip
55
+ results
56
+ end
57
+ end
@@ -0,0 +1,151 @@
1
+ require File.expand_path('../test_helper', __FILE__)
2
+
3
+ describe "AbnAmro::Internetkassa, class methods" do
4
+ it "should return whether or not it's in test mode" do
5
+ assert AbnAmro::Internetkassa.test?
6
+ end
7
+
8
+ it "should return the PSPID with #pspid or its aliased handsome cousin #merchant_id" do
9
+ AbnAmro::Internetkassa.pspid.should == 'fingertips'
10
+ AbnAmro::Internetkassa.merchant_id.should == 'fingertips'
11
+ end
12
+
13
+ it "should return the passphrase used to sign the messages to the payment server" do
14
+ AbnAmro::Internetkassa.shasign.should == 'supersecret'
15
+ AbnAmro::Internetkassa.passphrase.should == 'supersecret'
16
+ end
17
+
18
+ it "should have the correct service_urls" do
19
+ AbnAmro::Internetkassa::TEST_URL.should ==
20
+ "https://internetkassa.abnamro.nl/ncol/test/orderstandard.asp"
21
+
22
+ AbnAmro::Internetkassa::PRODUCTION_URL.should ==
23
+ "https://internetkassa.abnamro.nl/ncol/prod/orderstandard.asp"
24
+ end
25
+
26
+ it "should return the service_url for the current environment" do
27
+ begin
28
+ AbnAmro::Internetkassa.test = true
29
+ AbnAmro::Internetkassa.service_url.should ==
30
+ AbnAmro::Internetkassa::TEST_URL
31
+
32
+ AbnAmro::Internetkassa.test = false
33
+ AbnAmro::Internetkassa.service_url.should ==
34
+ AbnAmro::Internetkassa::PRODUCTION_URL
35
+ ensure
36
+ AbnAmro::Internetkassa.test = true
37
+ end
38
+ end
39
+ end
40
+
41
+ describe "AbnAmro::Internetkassa, an instance" do
42
+ before do
43
+ @valid_attributes = {
44
+ :order_id => 123,
45
+ :amount => 1000,
46
+ :description => "HappyHardcore vol. 123 - the ballads",
47
+ :endpoint_url => "http://example.com/payments",
48
+ :url_variable => ":id",
49
+ :endpoint_params => [[:session_id, 'abcde12345'], [:message, '“Thanks for your purchase”']]
50
+ }
51
+ @instance = AbnAmro::Internetkassa.new(@valid_attributes)
52
+ end
53
+
54
+ it "should have assigned the constructor arguments" do
55
+ @instance.order_id.should == 123
56
+ @instance.amount.should == 1000
57
+ @instance.description.should == "HappyHardcore vol. 123 - the ballads"
58
+ end
59
+
60
+ it "should have used the endpoint_url shortcut to set all endpoint urls" do
61
+ @instance.accept_url.should == "http://example.com/payments"
62
+ @instance.decline_url.should == "http://example.com/payments"
63
+ @instance.exception_url.should == "http://example.com/payments"
64
+ @instance.cancel_url.should == "http://example.com/payments"
65
+ end
66
+
67
+ it "should have merged default values" do
68
+ @instance.currency.should == 'EUR'
69
+ @instance.language.should == 'nl_NL'
70
+ end
71
+
72
+ it "should return the url_variable" do
73
+ @instance.url_variable.should == ":id"
74
+ end
75
+
76
+ it "should return the extra params" do
77
+ @instance.endpoint_params.should == [[:session_id, 'abcde12345'], [:message, '“Thanks for your purchase”']]
78
+ end
79
+
80
+ it "should have access to the pspid/merchant_id" do
81
+ @instance.send(:merchant_id).should == AbnAmro::Internetkassa.merchant_id
82
+ end
83
+
84
+ it "should have access to the shasign/passphrase" do
85
+ @instance.send(:passphrase).should == AbnAmro::Internetkassa.passphrase
86
+ end
87
+
88
+ it "should verify that the mandatory values are specified or raise an ArgumentError" do
89
+ %w{ merchant_id order_id amount currency language }.each do |key|
90
+ instance = AbnAmro::Internetkassa.new(@valid_attributes)
91
+ instance.stubs(key).returns(nil)
92
+ lambda { instance.send(:verify_values!) }.should.raise ArgumentError
93
+ end
94
+ end
95
+
96
+ it "should create a SHA1 signature for the message" do
97
+ message = "#{@instance.order_id}#{@instance.amount}#{@instance.currency}#{AbnAmro::Internetkassa.merchant_id}#{AbnAmro::Internetkassa.passphrase}"
98
+ @instance.send(:signature).should == Digest::SHA1.hexdigest(message).upcase
99
+ end
100
+
101
+ it "should return the key-value pairs that should be POSTed, according to the Internetkassa specs" do
102
+ @instance.data.should == {
103
+ :PSPID => AbnAmro::Internetkassa.merchant_id,
104
+ :orderID => @instance.order_id,
105
+ :amount => @instance.amount,
106
+ :currency => @instance.currency,
107
+ :language => @instance.language,
108
+ :COM => @instance.description,
109
+ :SHASign => @instance.send(:signature),
110
+ :PARAMVAR => @instance.url_variable,
111
+ :PARAMPLUS => "session_id=abcde12345&message=%E2%80%9CThanks+for+your+purchase%E2%80%9D",
112
+ :accepturl => @valid_attributes[:endpoint_url],
113
+ :declineurl => @valid_attributes[:endpoint_url],
114
+ :exceptionurl => @valid_attributes[:endpoint_url],
115
+ :cancelurl => @valid_attributes[:endpoint_url]
116
+ }
117
+ end
118
+
119
+ it "should check if all mandatory values are specified before returning the `data'" do
120
+ @instance.expects(:verify_values!)
121
+ @instance.data
122
+ end
123
+
124
+ it "should merge any optional arguments with the data" do
125
+ @valid_attributes[:TITLE] = 'My Transaction'
126
+ AbnAmro::Internetkassa.new(@valid_attributes).data.should == {
127
+ :PSPID => AbnAmro::Internetkassa.merchant_id,
128
+ :orderID => @instance.order_id,
129
+ :amount => @instance.amount,
130
+ :currency => @instance.currency,
131
+ :language => @instance.language,
132
+ :COM => @instance.description,
133
+ :SHASign => @instance.send(:signature),
134
+ :PARAMVAR => @instance.url_variable,
135
+ :PARAMPLUS => "session_id=abcde12345&message=%E2%80%9CThanks+for+your+purchase%E2%80%9D",
136
+ :accepturl => @valid_attributes[:endpoint_url],
137
+ :declineurl => @valid_attributes[:endpoint_url],
138
+ :exceptionurl => @valid_attributes[:endpoint_url],
139
+ :cancelurl => @valid_attributes[:endpoint_url],
140
+ :TITLE => 'My Transaction'
141
+ }
142
+ end
143
+
144
+ it "should not return blank values in the `data'" do
145
+ @instance.url_variable = nil
146
+ @instance.data.should.not.has_key :PARAMVAR
147
+
148
+ @instance.url_variable = ''
149
+ @instance.data.should.not.has_key :PARAMVAR
150
+ end
151
+ end
@@ -0,0 +1,32 @@
1
+ require File.expand_path('../test_helper', __FILE__)
2
+
3
+ describe "AbnAmro::Internetkassa::Response, regression tests" do
4
+ before do
5
+ AbnAmro::Internetkassa::Response.any_instance.stubs(:valid?).returns(true)
6
+ @response = AbnAmro::Internetkassa::Response.new({})
7
+ end
8
+
9
+ it "should be retryable" do
10
+ retry_codes = AbnAmro::Internetkassa::Response::Codes::ERROR_CODES.select { |_,h| h[:retry] }
11
+ retry_codes.should.not.be.empty
12
+
13
+ retry_all = retry_codes.all? do |code, _|
14
+ @response.stubs(:error_code).returns(code)
15
+ @response.retry?
16
+ end
17
+
18
+ retry_all.should.be true
19
+ end
20
+
21
+ it "should not be retryable" do
22
+ dont_retry_codes = AbnAmro::Internetkassa::Response::Codes::ERROR_CODES.select { |_,h| !h[:retry] }
23
+ dont_retry_codes.should.not.be.empty
24
+
25
+ dont_retry_any = dont_retry_codes.all? do |code, _|
26
+ @response.stubs(:error_code).returns(code)
27
+ @response.retry? == false
28
+ end
29
+
30
+ dont_retry_any.should.be true
31
+ end
32
+ end
@@ -0,0 +1,185 @@
1
+ require File.expand_path('../test_helper', __FILE__)
2
+
3
+ describe "AbnAmro::Internetkassa::Response, in general" do
4
+ before do
5
+ @response = AbnAmro::Internetkassa::Response.new(fixture(:succeeded))
6
+ end
7
+
8
+ it "should return the raw params" do
9
+ @response.params.should == fixture(:succeeded)
10
+ end
11
+
12
+ it "should return whether or not the transaction was authorized" do
13
+ @response.stubs(:status_code).returns('5')
14
+ @response.should.be.authorized
15
+
16
+ @response.stubs(:status_code).returns('9')
17
+ @response.should.not.be.authorized
18
+ end
19
+
20
+ it "should return whether or not the transaction was captured" do
21
+ @response.stubs(:status_code).returns('9')
22
+ @response.should.be.captured
23
+
24
+ @response.stubs(:status_code).returns('5')
25
+ @response.should.not.be.captured
26
+ end
27
+
28
+ it "should return the essential attributes" do
29
+ @response.order_id.should == '1235052040'
30
+ @response.payment_id.should == '3051611'
31
+ @response.payment_method.should == 'iDEAL'
32
+ @response.acceptance.should == '0000000000'
33
+ @response.status_code.should == '9'
34
+ @response.signature.should == '7537DD222E35EE9F9842921BD90C2CBFCFA59466'
35
+ @response.currency.should == 'EUR'
36
+ end
37
+
38
+ it "should return the optional attributes" do
39
+ @response.customer_name.should == 'Buyer name'
40
+ @response.card_number.should == '11-XXXX-11'
41
+ @response.card_brand.should == 'iDEAL'
42
+ @response.card_expiration_date.should == ''
43
+ end
44
+
45
+ it "should return the amount in cents" do
46
+ @response.instance_variable_set(:@params, 'amount' => '10')
47
+ @response.amount.should == 1000
48
+ end
49
+
50
+ it "should return the amount with decimals in cents" do
51
+ @response.instance_variable_set(:@params, 'amount' => '10.31')
52
+ @response.amount.should == 1031
53
+ end
54
+
55
+ it "should return the transaction date as a Date instance" do
56
+ @response.transaction_date.should == Date.parse('02/19/2009')
57
+ end
58
+
59
+ it "should create a SHA1 signature for the message" do
60
+ message = @response.order_id
61
+ message += @response.currency
62
+ message += @response.params['amount']
63
+ message += @response.payment_method
64
+ message += @response.acceptance
65
+ message += @response.status_code
66
+ message += @response.card_number
67
+ message += @response.payment_id
68
+ message += @response.params['NCERROR']
69
+ message += @response.card_brand
70
+
71
+ message += AbnAmro::Internetkassa.passphrase
72
+
73
+ @response.send(:calculated_signature).should == Digest::SHA1.hexdigest(message).upcase
74
+ end
75
+
76
+ it "should return that the signature matches the calculated_signature" do
77
+ @response.should.be.valid
78
+ end
79
+
80
+ it "should return that the signature does NOT match the calculated_signature" do
81
+ @response.stubs(:signature).returns('NOT A VALID SHA1 SIGNATURE')
82
+ @response.should.not.be.valid
83
+ end
84
+
85
+ it "should raise a SignatureInvalidError if initializing a response and the signature does not match the calculated_signature" do
86
+ params = fixture(:succeeded).dup
87
+ params['SHASIGN'] = 'NOT A VALID SHA1 SIGNATURE'
88
+
89
+ lambda {
90
+ AbnAmro::Internetkassa::Response.new(params)
91
+ }.should.raise AbnAmro::Internetkassa::Response::SignatureInvalidError
92
+ end
93
+
94
+ it "should return the message for the status code" do
95
+ @response.status_message.should == 'Payment requested'
96
+ end
97
+ end
98
+
99
+ describe "AbnAmro::Internetkassa::Response, with a successful payment" do
100
+ before do
101
+ @response = AbnAmro::Internetkassa::Response.new(fixture(:succeeded))
102
+ end
103
+
104
+ it "should be successful" do
105
+ @response.should.be.success
106
+ end
107
+
108
+ it "should not be retryable" do
109
+ @response.should.not.retry
110
+ end
111
+
112
+ it "should return `nil' as the error code" do
113
+ @response.error_code.should.be nil
114
+ end
115
+
116
+ it "should return `nil' as the error message" do
117
+ @response.error_message.should.be nil
118
+ end
119
+ end
120
+
121
+ describe "AbnAmro::Internetkassa::Response, with a failed payment" do
122
+ before do
123
+ @response = AbnAmro::Internetkassa::Response.new(fixture(:failed))
124
+ end
125
+
126
+ it "should not be successful" do
127
+ @response.should.not.be.success
128
+ end
129
+
130
+ it "should not be retryable" do
131
+ @response.should.not.retry
132
+ end
133
+
134
+ it "should return the error code" do
135
+ @response.error_code.should == "30001001"
136
+ end
137
+
138
+ it "should return the error message" do
139
+ @response.error_message.should == "Payment refused by the acquirer"
140
+ end
141
+ end
142
+
143
+ describe "AbnAmro::Internetkassa::Response, with a cancelled payment" do
144
+ before do
145
+ @response = AbnAmro::Internetkassa::Response.new(fixture(:cancelled))
146
+ end
147
+
148
+ it "should not be successful" do
149
+ @response.should.not.be.success
150
+ end
151
+
152
+ it "should not be retryable" do
153
+ @response.should.not.retry
154
+ end
155
+
156
+ it "should return the error code" do
157
+ @response.error_code.should == "30171001"
158
+ end
159
+
160
+ it "should return the error message" do
161
+ @response.error_message.should == "Payment method cancelled by the buyer"
162
+ end
163
+ end
164
+
165
+ describe "AbnAmro::Internetkassa::Response, when an exception occurred" do
166
+ before do
167
+ @response = AbnAmro::Internetkassa::Response.new(fixture(:exception))
168
+ end
169
+
170
+ it "should not be successful" do
171
+ @response.should.not.be.success
172
+ end
173
+
174
+ it "should not be retryable" do
175
+ @response.should.not.retry
176
+ end
177
+
178
+ it "should return the error code" do
179
+ @response.error_code.should == "20002001"
180
+ end
181
+
182
+ it "should return the error message" do
183
+ @response.error_message.should == "Origin for the response of the bank can not be checked"
184
+ end
185
+ end