exact4r 1.2 → 1.4

Sign up to get free protection for your applications and to get access to all the features.
data/CHANGELOG CHANGED
@@ -1,3 +1,10 @@
1
+ == v1.4
2
+ Added support for specifying alternative SSL certificates
3
+
4
+ == v1.3
5
+ Added support for TaggedUpdate transactions
6
+ Added support for ReferencedVoid transactions
7
+
1
8
  == v1.2
2
9
  Updated with new SSL certificates for https://api.e-xact.com
3
10
 
data/VERSION CHANGED
@@ -1 +1 @@
1
- 1.2
1
+ 1.4
@@ -0,0 +1,63 @@
1
+ module EWS # :nodoc:
2
+ module CertificateHelper
3
+
4
+ EXACT_ISSUER_CERT_FILE = File.dirname(__FILE__)+"/../../certs/valicert_class2_root.crt" unless defined?(EXACT_ISSUER_CERT_FILE)
5
+ EXACT_SERVER_CERT_FILE = File.dirname(__FILE__)+"/../../certs/e-xact.com.crt" unless defined?(EXACT_SERVER_CERT_FILE)
6
+
7
+ attr_accessor :issuer_cert_file, :server_cert
8
+
9
+ def configure_certificates(options)
10
+ self.issuer_cert_file = (options[:issuer_cert] || EXACT_ISSUER_CERT_FILE)
11
+ server_cert_file = (options[:server_cert] || EXACT_SERVER_CERT_FILE)
12
+ self.server_cert = File.new(server_cert_file).read
13
+ end
14
+ private :configure_certificates
15
+
16
+ def validate_certificate(is_ok, ctx)
17
+ cert = ctx.current_cert
18
+ return false if cert.nil?
19
+
20
+ # preverify failed?
21
+ return false unless is_ok
22
+
23
+ self_signed = false
24
+ ca = false
25
+ pathlen = nil
26
+ server_auth = true
27
+ self_signed = (cert.subject.cmp(cert.issuer) == 0)
28
+
29
+ # Check extensions for the certificate purpose according to http://www.openssl.org/docs/apps/x509.html (Certificate Extensions) and
30
+ # http://www.ietf.org/rfc/rfc3280.txt.
31
+ cert.extensions.each do |ex|
32
+ case ex.oid
33
+ when 'basicConstraints'
34
+ /CA:(TRUE|FALSE)(?:, pathlen:)*(\d*)/ =~ ex.value
35
+ ca ||= ($1 == 'TRUE')
36
+ pathlen = $2.to_i
37
+ when 'keyUsage'
38
+ usage = ex.value.split(/\s*,\s*/)
39
+ # a CA must have
40
+ ca &&= !usage.grep(/Certificate Sign/i).empty?
41
+ # Server Cert Must have
42
+ server_auth &&= !usage.grep(/Key Encipherment/i).empty?
43
+ when 'extendedKeyUsage'
44
+ usage = ex.value.split(/\s*,\s*/)
45
+ # Server Cert Must have
46
+ server_auth &&= !usage.grep(/TLS Web Server Authentication/i).empty?
47
+ when 'nsCertType'
48
+ usage = ex.value.split(/\s*,\s*/)
49
+ ca ||= !usage.grep(/SSL CA/i).empty?
50
+ server_auth ||= !usage.grep(/SSL Server/i).empty?
51
+ end
52
+ end
53
+
54
+ # We're looking for the server cert, so accept all CAs (which have already passed pre-verification)
55
+ return true if self_signed || ca
56
+
57
+ # ensure the server cert is the one we're expecting
58
+ return server_auth && self.server_cert == cert.to_pem
59
+ end
60
+ private :validate_certificate
61
+
62
+ end
63
+ end
@@ -37,6 +37,8 @@ module EWS # :nodoc:
37
37
  # :tagged_void
38
38
  # :tagged_refund
39
39
  # :tagged_online_debit_refund
40
+ # :tagged_update
41
+ # :referenced_void
40
42
  # :recurring_seed_pre_auth
41
43
  # :recurring_seed_purchase
42
44
  # :idebit_purchase
@@ -113,6 +115,8 @@ METHOD_EOS
113
115
  :tagged_void => '33',
114
116
  :tagged_refund => '34',
115
117
  :tagged_online_debit_refund => '35',
118
+ :referenced_void => '36',
119
+ :tagged_update => '37',
116
120
  :recurring_seed_pre_auth => '40',
117
121
  :recurring_seed_purchase => '41',
118
122
  :idebit_purchase => '50',
@@ -40,6 +40,8 @@ module EWS # :nodoc:
40
40
 
41
41
  if self.transaction_type == "CR"
42
42
  append_error(:transaction_tag, "transaction_tag must be supplied") if self.transaction_tag.to_i < 1
43
+ elsif self.transaction_type == "36"
44
+ validate_referenced_void
43
45
  elsif %w(80 81).include?(self.transaction_type)
44
46
  # do nothing, no validation required
45
47
  elsif %w(50 54).include?(self.transaction_type)
@@ -166,12 +168,13 @@ module EWS # :nodoc:
166
168
  def validate_for_transaction_tag
167
169
  tt = self.transaction_type
168
170
 
169
- # mandatory: transaction_type must == (30, 31, 32, 33, 34, 35)
170
- append_error(:transaction_tag, "transaction_tag must only be set for tagged transactions") unless %w(30 31 32 33 34 35 CR).include?(tt)
171
+ # mandatory: transaction_type must == (30, 31, 32, 33, 34, 35, 37, CR)
172
+ append_error(:transaction_tag, "transaction_tag must only be set for tagged transactions") unless %w(30 31 32 33 34 35 37 CR).include?(tt)
171
173
 
172
174
  # transaction_tag, auth_num & amount mandatory
173
175
  mandatory = [:transaction_tag]
174
- mandatory << [:authorization_num, :amount] unless tt == 'CR'
176
+ mandatory << :authorization_num unless tt == 'CR'
177
+ mandatory << :amount unless %w(CR 37).include?(tt)
175
178
 
176
179
  # ensure no cc details sent
177
180
  append_error(:cc_number, "do not set cc_number for tagged transactions") unless self.cc_number.blank?
@@ -227,6 +230,15 @@ module EWS # :nodoc:
227
230
  check_mandatory(mandatory)
228
231
  end
229
232
 
233
+ def validate_referenced_void
234
+ [:cc_number, :pan, :track1, :track2, :transaction_tag].each do |attr_name|
235
+ append_error(attr_name, "#{attr_name} must not be set for referenced_void transactions") unless self.send(attr_name).nil?
236
+ end
237
+
238
+ check_mandatory([:reference_no, :customer_ref, :amount])
239
+ end
240
+
241
+
230
242
  def check_mandatory(mandatory)
231
243
  mandatory.each do |key|
232
244
  append_error(key, "#{key} must be supplied") if self.send(key).blank?
@@ -1,4 +1,5 @@
1
1
  require 'net/https'
2
+ require File.dirname(__FILE__) + '/certificate_helper'
2
3
 
3
4
  module EWS # :nodoc:
4
5
 
@@ -15,6 +16,7 @@ module EWS # :nodoc:
15
16
  # Once configured to connect to a particular service, it can be used repeatedly
16
17
  # to send as many transactions as required.
17
18
  class Transporter
19
+ include CertificateHelper
18
20
 
19
21
  # Initialize a Transporter.
20
22
  #
@@ -23,6 +25,8 @@ module EWS # :nodoc:
23
25
  #
24
26
  # You can also specify a hash of options as follows:
25
27
  # :transport_type the transport_type for this transporter (defaults to :rest)
28
+ # :server_cert the path to the server's certificate file (defaults to E-xact's Server Cert)
29
+ # :issuer_cert the path to the issuer's certificate file (defaults to E-xact's Issuer's Cert)
26
30
  #
27
31
  # The default certificates are those required to connect to https://api.e-xact.com and the
28
32
  # default <tt>transport_type</tt> is <tt>:rest</tt>. The default <tt>transport_type</tt> can be overridden on a per-transaction
@@ -31,8 +35,7 @@ module EWS # :nodoc:
31
35
  @url = URI.parse(url.gsub(/\/$/,''))
32
36
  @transport_type = options[:transport_type] || :rest
33
37
 
34
- @@issuer_cert ||= File.dirname(__FILE__)+"/../../certs/valicert_class2_root.crt"
35
- @@server_cert ||= File.new(File.dirname(__FILE__)+"/../../certs/e-xact.com.crt").read
38
+ configure_certificates(options)
36
39
  end
37
40
 
38
41
  # Submit a transaction request to the server
@@ -52,7 +55,7 @@ module EWS # :nodoc:
52
55
  request = build_http_request(transaction, transport_type, transport_details[:suffix])
53
56
  request.basic_auth(transaction.gateway_id, transaction.password)
54
57
  request.add_field "Accept", transport_details[:content_type]
55
- request.add_field "User-Agent", "exact4r v1.2"
58
+ request.add_field "User-Agent", "exact4r v1.4"
56
59
  request.add_field "Content-type", "#{transport_details[:content_type]}; charset=UTF-8"
57
60
 
58
61
  response = get_connection.request(request)
@@ -106,56 +109,11 @@ private
106
109
  @connection.use_ssl = true
107
110
  @connection.verify_mode = OpenSSL::SSL::VERIFY_PEER
108
111
  @connection.verify_callback = method(:validate_certificate)
109
- @connection.ca_file = @@issuer_cert
112
+ @connection.ca_file = self.issuer_cert_file
110
113
  end
111
114
  @connection
112
115
  end
113
116
 
114
- def validate_certificate(is_ok, ctx)
115
- cert = ctx.current_cert
116
- return false if cert.nil?
117
-
118
- # preverify failed?
119
- return false unless is_ok
120
-
121
- self_signed = false
122
- ca = false
123
- pathlen = nil
124
- server_auth = true
125
- self_signed = (cert.subject.cmp(cert.issuer) == 0)
126
-
127
- # Check extensions for the certificate purpose according to http://www.openssl.org/docs/apps/x509.html (Certificate Extensions) and
128
- # http://www.ietf.org/rfc/rfc3280.txt.
129
- cert.extensions.each do |ex|
130
- case ex.oid
131
- when 'basicConstraints'
132
- /CA:(TRUE|FALSE)(?:, pathlen:)*(\d*)/ =~ ex.value
133
- ca ||= ($1 == 'TRUE')
134
- pathlen = $2.to_i
135
- when 'keyUsage'
136
- usage = ex.value.split(/\s*,\s*/)
137
- # a CA must have
138
- ca &&= !usage.grep(/Certificate Sign/i).empty?
139
- # Server Cert Must have
140
- server_auth &&= !usage.grep(/Key Encipherment/i).empty?
141
- when 'extendedKeyUsage'
142
- usage = ex.value.split(/\s*,\s*/)
143
- # Server Cert Must have
144
- server_auth &&= !usage.grep(/TLS Web Server Authentication/i).empty?
145
- when 'nsCertType'
146
- usage = ex.value.split(/\s*,\s*/)
147
- ca ||= !usage.grep(/SSL CA/i).empty?
148
- server_auth ||= !usage.grep(/SSL Server/i).empty?
149
- end
150
- end
151
-
152
- # We're looking for the server cert, so accept all CAs (which have already passed pre-verification)
153
- return true if self_signed || ca
154
-
155
- # ensure the server cert is the one we're expecting
156
- return server_auth && @@server_cert == cert.to_pem
157
- end
158
-
159
117
  # what transport types we support, and their corresponding suffixes
160
118
  @@transport_types = {
161
119
  :rest => {:suffix => "xml", :content_type => "application/xml"},
Binary file
data/test/credentials.yml CHANGED
@@ -1,5 +1,5 @@
1
1
  DEV:
2
- location: http://ws.local/
2
+ location: http://localhost:3000/
3
3
  tsys:
4
4
  :gateway_id: AD0156-01
5
5
  :password: 4apitest
@@ -16,6 +16,24 @@ DEV:
16
16
  :gateway_id: AD0158-01
17
17
  :password: 4apitest
18
18
 
19
+ QA:
20
+ location: https://api.qa.e-xact.com/
21
+ tsys:
22
+ :gateway_id: A04766-01
23
+ :password: 4apitest
24
+ emergis:
25
+ :gateway_id: A04763-01
26
+ :password: 4apitest
27
+ moneris:
28
+ :gateway_id: A04760-01
29
+ :password: 4apitest
30
+ chase:
31
+ :gateway_id: A04757-02
32
+ :password: 4apitest
33
+ chase_batch:
34
+ :gateway_id: A04757-01
35
+ :password: 4apitest
36
+
19
37
  PROD:
20
38
  location: https://api.e-xact.com/
21
39
  tsys:
@@ -39,7 +39,9 @@ class ForcedPostTest < Test::Unit::TestCase
39
39
  assert request.valid?
40
40
  end
41
41
 
42
- def test_by_credit_card
42
+ def test_by_credit_card
43
+ return if @@credentials.chase? || @@credentials.moneris?
44
+
43
45
  request = EWS::Transaction::Request.new(cc_number_params.merge(:transaction_type => :forced_post))
44
46
  request.amount = 11.25
45
47
  request.authorization_num = "1234"
@@ -51,6 +53,8 @@ class ForcedPostTest < Test::Unit::TestCase
51
53
  end
52
54
 
53
55
  def test_by_track1
56
+ return if @@credentials.chase? || @@credentials.moneris?
57
+
54
58
  request = EWS::Transaction::Request.new(track1_params.merge(:transaction_type => :forced_post))
55
59
  request.amount = 11.25
56
60
  request.authorization_num = "1234"
@@ -62,6 +66,8 @@ class ForcedPostTest < Test::Unit::TestCase
62
66
  end
63
67
 
64
68
  def test_by_track2
69
+ return if @@credentials.chase? || @@credentials.moneris?
70
+
65
71
  request = EWS::Transaction::Request.new(track2_params.merge(:transaction_type => :forced_post))
66
72
  request.amount = 11.25
67
73
  request.authorization_num = "1234"
@@ -0,0 +1,131 @@
1
+ require File.dirname(__FILE__) + "/../test_helper"
2
+
3
+ #
4
+ # A ReferencedVoid behaves the same as a TaggedVoid, except, instead of using transaction_tag,
5
+ # authorization_num and amount to lookup the transaction to be voided, you use reference_no,
6
+ # customer_ref and amount.
7
+ #
8
+ class ReferencedVoidTest < Test::Unit::TestCase
9
+
10
+ def setup
11
+ @transporter = EWS::Transporter.new(@@credentials.config['location'])
12
+
13
+ # do initial purchase
14
+ request = EWS::Transaction::Request.new(cc_number_params.merge({
15
+ :transaction_type => :purchase,
16
+ :amount => 11.25,
17
+ :reference_no => "reference_no_#{rand(10)}",
18
+ :customer_ref => "customer_ref_#{rand(10)}"
19
+ }))
20
+ assert request.valid?, request.errors.inspect
21
+
22
+ @purchase = @transporter.submit(request, :json)
23
+ assert @purchase.approved?
24
+ end
25
+
26
+ def test_mandatory
27
+ request = EWS::Transaction::Request.new(:transaction_type => :referenced_void)
28
+ assert !request.valid?
29
+ assert_equal "gateway_id must be supplied", request.errors[:gateway_id]
30
+
31
+ request.gateway_id = @@credentials.current_gateway[:gateway_id]
32
+ assert !request.valid?
33
+ assert_equal "password must be supplied", request.errors[:password]
34
+
35
+ request.password = @@credentials.current_gateway[:password]
36
+ assert !request.valid?
37
+ assert_equal "reference_no must be supplied", request.errors[:reference_no]
38
+
39
+ request.reference_no = "something"
40
+ assert !request.valid?
41
+ assert_equal "customer_ref must be supplied", request.errors[:customer_ref]
42
+
43
+ request.customer_ref = "something"
44
+ assert !request.valid?
45
+ assert_equal "amount must be supplied", request.errors[:amount]
46
+
47
+ request.amount = 11.25
48
+ assert request.valid?
49
+
50
+ # don't set any CC information
51
+ [:cc_number, :pan, :track1, :track2, :transaction_tag].each do |attr_name|
52
+ request.send("#{attr_name}=", "something")
53
+ assert !request.valid?
54
+ assert_equal "#{attr_name} must not be set for referenced_void transactions", request.errors[attr_name]
55
+ request.send("#{attr_name}=", nil)
56
+ end
57
+ end
58
+
59
+ def test_json
60
+ request = EWS::Transaction::Request.new({
61
+ :transaction_type => :referenced_void,
62
+ :amount => 11.25,
63
+ :reference_no => @purchase.reference_no,
64
+ :customer_ref => @purchase.customer_ref
65
+ }.merge(@@credentials.current_gateway))
66
+ assert request.valid?, request.errors.inspect
67
+
68
+ assert_details_correct request, @transporter.submit(request, :json)
69
+ end
70
+
71
+ def test_rest
72
+ request = EWS::Transaction::Request.new({
73
+ :transaction_type => :referenced_void,
74
+ :amount => 11.25,
75
+ :reference_no => @purchase.reference_no,
76
+ :customer_ref => @purchase.customer_ref
77
+ }.merge(@@credentials.current_gateway))
78
+ assert request.valid?, request.errors.inspect
79
+
80
+ assert_details_correct request, @transporter.submit(request, :rest)
81
+ end
82
+
83
+ def test_soap
84
+ request = EWS::Transaction::Request.new({
85
+ :transaction_type => :referenced_void,
86
+ :amount => 11.25,
87
+ :reference_no => @purchase.reference_no,
88
+ :customer_ref => @purchase.customer_ref
89
+ }.merge(@@credentials.current_gateway))
90
+ assert request.valid?, request.errors.inspect
91
+
92
+ assert_details_correct request, @transporter.submit(request, :soap)
93
+ end
94
+
95
+ def test_requires_correct_amount
96
+ request = EWS::Transaction::Request.new({
97
+ :transaction_type => :referenced_void,
98
+ :amount => 3.50,
99
+ :reference_no => @purchase.reference_no,
100
+ :customer_ref => @purchase.customer_ref
101
+ }.merge(@@credentials.current_gateway))
102
+ assert request.valid?, request.errors.inspect
103
+
104
+ response = @transporter.submit(request, :json)
105
+ assert !response.approved?
106
+
107
+ request.amount = 13.50
108
+ response = @transporter.submit(request, :rest)
109
+ assert !response.approved?
110
+
111
+ request.amount = 11.25
112
+ assert_details_correct request, @transporter.submit(request, :soap)
113
+ end
114
+
115
+ def test_multiple_voids_against_one_transaction
116
+ request = EWS::Transaction::Request.new({
117
+ :transaction_type => :referenced_void,
118
+ :amount => 11.25,
119
+ :reference_no => @purchase.reference_no,
120
+ :customer_ref => @purchase.customer_ref
121
+ }.merge(@@credentials.current_gateway))
122
+ assert request.valid?, request.errors.inspect
123
+
124
+ assert_details_correct request, @transporter.submit(request, :json)
125
+
126
+ # can't void an already-voided transaction
127
+ response = @transporter.submit(request, :json)
128
+ assert !response.approved?
129
+ end
130
+
131
+ end
@@ -43,7 +43,7 @@ class RefundCorrectionTest < Test::Unit::TestCase
43
43
  assert request.valid?
44
44
  end
45
45
 
46
- def test_by_credit_card
46
+ def test_by_credit_card
47
47
  return unless @@credentials.moneris?
48
48
 
49
49
  request = EWS::Transaction::Request.new(cc_number_params.merge(:transaction_type => :refund_correction).merge(@@credentials.current_gateway))
@@ -0,0 +1,158 @@
1
+ require File.dirname(__FILE__) + "/../test_helper"
2
+
3
+ #
4
+ # A TaggedUpdate request allows a merchant to edit the reference_no and customer_ref values of a
5
+ # previous transaction. Please note that this is NOT a financial transaction, it merely allows
6
+ # you to change the values stored in our DB for a given transaction.
7
+ #
8
+ # In common with all other tagged transactions, you supply the transaction_tag and authorization_num
9
+ # for the transaction whose values you wish to change, along with the new values for reference_no
10
+ # and/or customer_ref.
11
+ #
12
+ # NOTE: nil, empty string ("") or whitespace string (" ") are not permitted, and, although the
13
+ # request will be approved, the relevant attribute WILL NOT CHANGE.
14
+ #
15
+ class TaggedUpdateTest < Test::Unit::TestCase
16
+
17
+ def setup
18
+ @transporter = EWS::Transporter.new(@@credentials.config['location'])
19
+
20
+ # do initial purchase request
21
+ request = EWS::Transaction::Request.new(cc_number_params.merge(:transaction_type => :purchase))
22
+ request.amount = 11.25
23
+ request.reference_no = "reference_no"
24
+ request.customer_ref = "customer_ref"
25
+ assert request.valid?, request.errors.inspect
26
+
27
+ @purchase = @transporter.submit(request, :json)
28
+ assert @purchase.approved?, @purchase.to_yaml
29
+ end
30
+
31
+ def test_mandatory
32
+ request = EWS::Transaction::Request.new(:transaction_type => :tagged_update)
33
+ assert !request.valid?
34
+ assert_equal "gateway_id must be supplied", request.errors[:gateway_id]
35
+
36
+ request.gateway_id = @@credentials.current_gateway[:gateway_id]
37
+ assert !request.valid?
38
+ assert_equal "password must be supplied", request.errors[:password]
39
+
40
+ request.password = @@credentials.current_gateway[:password]
41
+ assert !request.valid?
42
+ assert_equal "One of the following must be supplied: cc_number, track1, track2 or transaction_tag.", request.errors[:base]
43
+
44
+ request.transaction_tag = 1234
45
+ assert !request.valid?
46
+ assert_equal "authorization_num must be supplied", request.errors[:authorization_num]
47
+
48
+ request.authorization_num = "TH6754"
49
+ assert request.valid?, request.errors.inspect
50
+
51
+ request.cc_number = "4111111111111111"
52
+ assert !request.valid?
53
+ assert_equal "do not set cc_number for tagged transactions", request.errors[:cc_number]
54
+ end
55
+
56
+ def test_json
57
+ request = tagged_update_request(@purchase)
58
+ assert request.valid?, request.errors.inspect
59
+
60
+ response = @transporter.submit(request, :json)
61
+ assert response.approved?
62
+
63
+ # we're getting the details of the original transction returned
64
+ assert_equal @purchase.transaction_tag, response.transaction_tag
65
+ assert_equal "something_new", response.reference_no
66
+ assert_equal "something_old", response.customer_ref
67
+ end
68
+
69
+ def test_rest
70
+ request = tagged_update_request(@purchase)
71
+ assert request.valid?, request.errors.inspect
72
+
73
+ response = @transporter.submit(request, :rest)
74
+
75
+ # we're getting the details of the original transction returned
76
+ assert_equal @purchase.transaction_tag, response.transaction_tag
77
+ assert_equal "something_new", response.reference_no
78
+ assert_equal "something_old", response.customer_ref
79
+ end
80
+
81
+ def test_soap
82
+ request = tagged_update_request(@purchase)
83
+ assert request.valid?, request.errors.inspect
84
+
85
+ response = @transporter.submit(request, :soap)
86
+
87
+ # we're getting the details of the original transction returned
88
+ assert_equal @purchase.transaction_tag, response.transaction_tag
89
+ assert_equal "something_new", response.reference_no
90
+ assert_equal "something_old", response.customer_ref
91
+ end
92
+
93
+ def test_multiple_updates
94
+ request1 = tagged_update_request(@purchase)
95
+ assert request1.valid?, request1.errors.inspect
96
+
97
+ response1 = @transporter.submit(request1, :soap)
98
+ assert_equal "something_new", response1.reference_no
99
+ assert_equal "something_old", response1.customer_ref
100
+
101
+ request2 = tagged_update_request(@purchase, {
102
+ :reference_no => "bananas",
103
+ :customer_ref => "oranges"
104
+ })
105
+ assert request2.valid?, request2.errors.inspect
106
+
107
+ response2 = @transporter.submit(request2, :soap)
108
+ assert_equal "bananas", response2.reference_no
109
+ assert_equal "oranges", response2.customer_ref
110
+ end
111
+
112
+ def test_updating_single_attribute
113
+ # change only reference_no
114
+ request1 = tagged_update_request(@purchase, {:customer_ref => nil})
115
+ assert request1.valid?, request1.errors.inspect
116
+
117
+ response1 = @transporter.submit(request1, :soap)
118
+ assert_equal "something_new", response1.reference_no
119
+ assert_equal "customer_ref", response1.customer_ref
120
+
121
+ # change only customer_ref
122
+ request2 = tagged_update_request(@purchase, {:reference_no => nil})
123
+ assert request2.valid?, request2.errors.inspect
124
+
125
+ response2 = @transporter.submit(request2, :soap)
126
+ assert_equal "something_new", response2.reference_no
127
+ assert_equal "something_old", response2.customer_ref
128
+ end
129
+
130
+ def test_empty_strings_ignored
131
+ request1 = tagged_update_request(@purchase, {:customer_ref => ""})
132
+ assert request1.valid?, request1.errors.inspect
133
+
134
+ response1 = @transporter.submit(request1, :soap)
135
+ assert_equal "something_new", response1.reference_no
136
+ assert_equal "customer_ref", response1.customer_ref
137
+ end
138
+
139
+ def test_whitepaces_strings_ignored
140
+ request1 = tagged_update_request(@purchase, {:customer_ref => " "})
141
+ assert request1.valid?, request1.errors.inspect
142
+
143
+ response1 = @transporter.submit(request1, :soap)
144
+ assert_equal "something_new", response1.reference_no
145
+ assert_equal "customer_ref", response1.customer_ref
146
+ end
147
+
148
+ def tagged_update_request(original_txn, options = {})
149
+ EWS::Transaction::Request.new({
150
+ :transaction_type => :tagged_update,
151
+ :transaction_tag => original_txn.transaction_tag,
152
+ :authorization_num => original_txn.authorization_num,
153
+ :reference_no => "something_new",
154
+ :customer_ref => "something_old"
155
+ }.merge(options).merge(@@credentials.current_gateway))
156
+ end
157
+ private :tagged_update_request
158
+ end
@@ -70,18 +70,19 @@ class TransactionDetailsTest < Test::Unit::TestCase
70
70
  end
71
71
 
72
72
  def assert_details_match_original_response(original_response, details_response)
73
+ # exclude: client_ip, pan
73
74
  [:logon_message, :error_number, :error_description, :transaction_error, :transaction_approved, :exact_resp_code, :exact_message,
74
75
  :bank_resp_code, :bank_message, :bank_resp_code_2, :sequence_no, :avs, :cvv2, :retrieval_ref_no, :cavv_response, :merchant_name,
75
76
  :merchant_address, :merchant_city, :merchant_province, :merchant_country, :merchant_postal, :merchant_url, :gateway_id, :password,
76
- :transaction_type, :amount, :surcharge_amount, :cc_number, :transaction_tag, :track1, :track2, :pan, :authorization_num, :cc_expiry,
77
+ :transaction_type, :amount, :surcharge_amount, :cc_number, :transaction_tag, :track1, :track2, :authorization_num, :cc_expiry,
77
78
  :cardholder_name, :cc_verification_str1, :cc_verification_str2, :cvd_presence_ind, :tax1_amount, :tax1_number, :tax2_amount,
78
79
  :tax2_number, :secure_auth_required, :secure_auth_result, :ecommerce_flag, :xid, :cavv, :cavv_algorithm, :reference_no, :customer_ref,
79
- :reference_3, :language, :client_ip, :client_email, :user_name, :zip_code].each do |attr_name|
80
+ :reference_3, :language, :client_email, :user_name, :zip_code].each do |attr_name|
81
+ next if attr_name == :cc_expiry && %(35 50 54).include?(original_response.transaction_type)
82
+
80
83
  o_value = original_response.send(attr_name).to_s
81
84
  d_value = details_response.send(attr_name).to_s
82
- unless o_value == d_value
83
- puts "#{attr_name}: #{o_value} / #{d_value}"
84
- end
85
+ assert_equal o_value, d_value, "#{attr_name}: #{o_value} / #{d_value}"
85
86
  end
86
87
  end
87
88
  private :assert_details_match_original_response
@@ -40,42 +40,79 @@ class VoidTest < Test::Unit::TestCase
40
40
  end
41
41
 
42
42
  def test_by_credit_card
43
- return if @@credentials.chase? || @@credentials.moneris?
44
-
43
+ return if @@credentials.moneris?
44
+
45
+ response = send_purchase(cc_number_params)
46
+
45
47
  request = EWS::Transaction::Request.new(cc_number_params.merge(:transaction_type => :void))
46
48
  request.amount = 11.25
47
- request.authorization_num = "1234"
49
+ request.authorization_num = response.authorization_num
48
50
  assert request.valid?, request.errors.inspect
49
51
 
50
52
  assert_details_correct request, @transporter.submit(request, :json)
53
+
54
+ response = send_purchase(cc_number_params)
55
+ request.authorization_num = response.authorization_num
56
+
51
57
  assert_details_correct request, @transporter.submit(request, :rest)
58
+
59
+ response = send_purchase(cc_number_params)
60
+ request.authorization_num = response.authorization_num
61
+
52
62
  assert_details_correct request, @transporter.submit(request, :soap)
53
63
  end
54
64
 
55
65
  def test_by_track1
56
- return if @@credentials.chase? || @@credentials.moneris?
66
+ return if @@credentials.moneris?
57
67
 
68
+ response = send_purchase(track1_params)
69
+
58
70
  request = EWS::Transaction::Request.new(track1_params.merge(:transaction_type => :void))
59
71
  request.amount = 11.25
60
- request.authorization_num = "1234"
72
+ request.authorization_num = response.authorization_num
61
73
  assert request.valid?, request.errors.inspect
62
74
 
63
75
  assert_details_correct request, @transporter.submit(request, :json)
76
+
77
+ response = send_purchase(track1_params)
78
+ request.authorization_num = response.authorization_num
79
+
64
80
  assert_details_correct request, @transporter.submit(request, :rest)
81
+
82
+ response = send_purchase(track1_params)
83
+ request.authorization_num = response.authorization_num
84
+
65
85
  assert_details_correct request, @transporter.submit(request, :soap)
66
86
  end
67
87
 
68
88
  def test_by_track2
69
- return if @@credentials.chase? || @@credentials.moneris?
89
+ return if @@credentials.moneris?
70
90
 
91
+ response = send_purchase(track2_params)
92
+
71
93
  request = EWS::Transaction::Request.new(track2_params.merge(:transaction_type => :void))
72
94
  request.amount = 11.25
73
- request.authorization_num = "1234"
95
+ request.authorization_num = response.authorization_num
74
96
  assert request.valid?, request.errors.inspect
75
97
 
76
98
  assert_details_correct request, @transporter.submit(request, :json)
99
+
100
+ response = send_purchase(track2_params)
101
+ request.authorization_num = response.authorization_num
102
+
77
103
  assert_details_correct request, @transporter.submit(request, :rest)
104
+
105
+ response = send_purchase(track2_params)
106
+ request.authorization_num = response.authorization_num
107
+
78
108
  assert_details_correct request, @transporter.submit(request, :soap)
79
109
  end
80
110
 
111
+ def send_purchase(params)
112
+ request = EWS::Transaction::Request.new(params.merge(:transaction_type => :purchase, :amount => 11.25))
113
+ assert request.valid?, request.errors.inspect
114
+ response = @transporter.submit(request, :json)
115
+ assert response.approved?
116
+ response
117
+ end
81
118
  end
@@ -48,7 +48,27 @@ class TransporterTest < Test::Unit::TestCase
48
48
 
49
49
  assert_not_nil resp
50
50
  assert_equal 404, resp.error_number
51
- assert_equal "Not Found", resp.error_description
51
+ assert_equal "Not Found", resp.error_description.strip
52
+ end
53
+
54
+ def test_uses_supplied_certificates
55
+ req = ::EWS::Transaction::Request.new({
56
+ :transaction_type => :purchase,
57
+ :amount => "10.13",
58
+ :cardholder_name => "Simon Brown",
59
+ :cc_number => "4111111111111111",
60
+ :cc_expiry => "1012",
61
+ :reference_no => "987987",
62
+ }.merge(@@credentials.current_gateway))
63
+
64
+ tr = ::EWS::Transporter.new(@@credentials.config['location'], {
65
+ :issuer_cert => File.dirname(__FILE__)+"/../../certs/valicert_class2_root.crt",
66
+ :server_cert => File.dirname(__FILE__)+"/../../certs/e-xact.com.crt"
67
+ })
68
+ resp = tr.submit(req, :json)
69
+
70
+ assert_not_nil resp
71
+ assert resp.approved?
52
72
  end
53
73
 
54
74
  end
data/test/test_helper.rb CHANGED
@@ -38,7 +38,7 @@ end
38
38
 
39
39
  def assert_details_correct(request, response)
40
40
  assert_not_nil response, "response should not be nil"
41
- assert response.approved?, "#{response.error_number} / #{response.error_description} / #{response.exact_message} / #{response.bank_message}"
41
+ assert response.approved?, "#{response.error_number} / #{response.error_description} / #{response.exact_resp_code} / #{response.exact_message} / #{response.bank_message}"
42
42
 
43
43
  assert_not_nil response.transaction_tag
44
44
  assert_not_nil response.authorization_num
@@ -49,9 +49,11 @@ def assert_details_correct(request, response)
49
49
  end
50
50
 
51
51
  def assert_card_details(response)
52
- assert_match /............1111/, response.cc_number
53
- assert_equal TEST_CARD_HOLDER, response.cardholder_name
54
- assert_equal TEST_CARD_EXPIRY, response.cc_expiry unless %w(35 50 54).include?(response.transaction_type)
52
+ unless %w(35 50 54).include?(response.transaction_type)
53
+ assert_match /............1111/, response.cc_number
54
+ assert_equal TEST_CARD_HOLDER, response.cardholder_name
55
+ assert_equal TEST_CARD_EXPIRY, response.cc_expiry
56
+ end
55
57
  end
56
58
 
57
59
  def basic_params(options = {})
metadata CHANGED
@@ -1,7 +1,11 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: exact4r
3
3
  version: !ruby/object:Gem::Version
4
- version: "1.2"
4
+ prerelease: false
5
+ segments:
6
+ - 1
7
+ - 4
8
+ version: "1.4"
5
9
  platform: ruby
6
10
  authors:
7
11
  - E-xact Transactions Ltd.
@@ -9,29 +13,37 @@ autorequire:
9
13
  bindir: bin
10
14
  cert_chain: []
11
15
 
12
- date: 2010-03-11 00:00:00 +11:00
16
+ date: 2010-07-09 00:00:00 +10:00
13
17
  default_executable:
14
18
  dependencies:
15
19
  - !ruby/object:Gem::Dependency
16
20
  name: activesupport
17
- type: :runtime
18
- version_requirement:
19
- version_requirements: !ruby/object:Gem::Requirement
21
+ prerelease: false
22
+ requirement: &id001 !ruby/object:Gem::Requirement
20
23
  requirements:
21
24
  - - ">="
22
25
  - !ruby/object:Gem::Version
26
+ segments:
27
+ - 2
28
+ - 0
29
+ - 2
23
30
  version: 2.0.2
24
- version:
31
+ type: :runtime
32
+ version_requirements: *id001
25
33
  - !ruby/object:Gem::Dependency
26
34
  name: builder
27
- type: :runtime
28
- version_requirement:
29
- version_requirements: !ruby/object:Gem::Requirement
35
+ prerelease: false
36
+ requirement: &id002 !ruby/object:Gem::Requirement
30
37
  requirements:
31
38
  - - ">="
32
39
  - !ruby/object:Gem::Version
40
+ segments:
41
+ - 2
42
+ - 1
43
+ - 2
33
44
  version: 2.1.2
34
- version:
45
+ type: :runtime
46
+ version_requirements: *id002
35
47
  description:
36
48
  email: dredmond@e-xact.com
37
49
  executables: []
@@ -49,6 +61,7 @@ files:
49
61
  - ./certs/exact.cer
50
62
  - ./certs/valicert_class2_root.crt
51
63
  - ./CHANGELOG
64
+ - ./lib/ews/certificate_helper.rb
52
65
  - ./lib/ews/transaction/fake_response.rb
53
66
  - ./lib/ews/transaction/mapping.rb
54
67
  - ./lib/ews/transaction/request.rb
@@ -58,6 +71,7 @@ files:
58
71
  - ./lib/ews/transporter.rb
59
72
  - ./lib/exact4r.rb
60
73
  - ./LICENCE
74
+ - ./pkg/exact4r-1.2.gem
61
75
  - ./Rakefile
62
76
  - ./README
63
77
  - ./test/credentials.rb
@@ -73,6 +87,7 @@ files:
73
87
  - ./test/exhaustive/purchase_test.rb
74
88
  - ./test/exhaustive/recurring_seed_pre_auth_test.rb
75
89
  - ./test/exhaustive/recurring_seed_purchase_test.rb
90
+ - ./test/exhaustive/referenced_void_test.rb
76
91
  - ./test/exhaustive/refund_correction_test.rb
77
92
  - ./test/exhaustive/refund_test.rb
78
93
  - ./test/exhaustive/secure_storage_test.rb
@@ -81,6 +96,7 @@ files:
81
96
  - ./test/exhaustive/tagged_pre_auth_test.rb
82
97
  - ./test/exhaustive/tagged_purchase_test.rb
83
98
  - ./test/exhaustive/tagged_refund_test.rb
99
+ - ./test/exhaustive/tagged_update_test.rb
84
100
  - ./test/exhaustive/tagged_void_test.rb
85
101
  - ./test/exhaustive/transaction_details_test.rb
86
102
  - ./test/exhaustive/void_test.rb
@@ -122,18 +138,20 @@ required_ruby_version: !ruby/object:Gem::Requirement
122
138
  requirements:
123
139
  - - ">="
124
140
  - !ruby/object:Gem::Version
141
+ segments:
142
+ - 0
125
143
  version: "0"
126
- version:
127
144
  required_rubygems_version: !ruby/object:Gem::Requirement
128
145
  requirements:
129
146
  - - ">="
130
147
  - !ruby/object:Gem::Version
148
+ segments:
149
+ - 0
131
150
  version: "0"
132
- version:
133
151
  requirements: []
134
152
 
135
153
  rubyforge_project: exact4r
136
- rubygems_version: 1.3.5
154
+ rubygems_version: 1.3.6
137
155
  signing_key:
138
156
  specification_version: 3
139
157
  summary: E-xact Web Services Client Library.